OpenTTD Source  20241108-master-g80f628063a
statusbar_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 "core/backup_type.hpp"
12 #include "gfx_func.h"
13 #include "news_func.h"
14 #include "company_func.h"
15 #include "string_func.h"
16 #include "strings_func.h"
17 #include "company_base.h"
18 #include "tilehighlight_func.h"
19 #include "news_gui.h"
20 #include "company_gui.h"
21 #include "window_gui.h"
22 #include "saveload/saveload.h"
23 #include "window_func.h"
24 #include "statusbar_gui.h"
25 #include "toolbar_gui.h"
26 #include "core/geometry_func.hpp"
27 #include "zoom_func.h"
28 #include "timer/timer.h"
30 #include "timer/timer_window.h"
31 
33 
34 #include "table/strings.h"
35 #include "table/sprites.h"
36 
37 #include "safeguards.h"
38 
39 static bool DrawScrollingStatusText(const NewsItem *ni, int scroll_pos, int left, int right, int top, int bottom)
40 {
41  CopyInDParam(ni->params);
42 
43  /* Replace newlines and the likes with spaces. */
45 
46  DrawPixelInfo tmp_dpi;
47  if (!FillDrawPixelInfo(&tmp_dpi, left, top, right - left, bottom)) return true;
48 
49  int width = GetStringBoundingBox(message).width;
50  int pos = (_current_text_dir == TD_RTL) ? (scroll_pos - width) : (right - scroll_pos - left);
51 
52  AutoRestoreBackup dpi_backup(_cur_dpi, &tmp_dpi);
53  DrawString(pos, INT16_MAX, 0, message, TC_LIGHT_BLUE, SA_LEFT | SA_FORCE);
54 
55  return (_current_text_dir == TD_RTL) ? (pos < right - left) : (pos + width > 0);
56 }
57 
59  bool saving;
60  int ticker_scroll;
61 
62  static const int TICKER_STOP = 1640;
63  static const int COUNTER_STEP = 2;
64  static constexpr auto REMINDER_START = std::chrono::milliseconds(1350);
65 
66  StatusBarWindow(WindowDesc &desc) : Window(desc)
67  {
68  this->ticker_scroll = TICKER_STOP;
69 
70  this->InitNested();
72  PositionStatusbar(this);
73  }
74 
75  Point OnInitialPosition([[maybe_unused]] int16_t sm_width, [[maybe_unused]] int16_t sm_height, [[maybe_unused]] int window_number) override
76  {
77  Point pt = { 0, _screen.height - sm_height };
78  return pt;
79  }
80 
81  void FindWindowPlacementAndResize([[maybe_unused]] int def_width, [[maybe_unused]] int def_height) override
82  {
84  }
85 
86  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
87  {
88  Dimension d;
89  switch (widget) {
90  case WID_S_LEFT:
92  d = GetStringBoundingBox(STR_JUST_DATE_LONG);
93  break;
94 
95  case WID_S_RIGHT: {
96  int64_t max_money = UINT32_MAX;
97  for (const Company *c : Company::Iterate()) max_money = std::max<int64_t>(c->money, max_money);
98  SetDParam(0, 100LL * max_money);
99  d = GetStringBoundingBox(STR_JUST_CURRENCY_LONG);
100  break;
101  }
102 
103  default:
104  return;
105  }
106 
107  d.width += padding.width;
108  d.height += padding.height;
109  size = maxdim(d, size);
110  }
111 
112  void DrawWidget(const Rect &r, WidgetID widget) const override
113  {
114  Rect tr = r.Shrink(WidgetDimensions::scaled.framerect, RectPadding::zero);
115  tr.top = CenterBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL));
116  switch (widget) {
117  case WID_S_LEFT:
118  /* Draw the date */
120  DrawString(tr, STR_JUST_DATE_LONG, TC_WHITE, SA_HOR_CENTER);
121  break;
122 
123  case WID_S_RIGHT: {
125  DrawString(tr, STR_STATUSBAR_SPECTATOR, TC_FROMSTRING, SA_HOR_CENTER);
127  DrawString(tr, STR_STATUSBAR_INFINITE_MONEY, TC_FROMSTRING, SA_HOR_CENTER);
128  } else {
129  /* Draw company money, if any */
131  if (c != nullptr) {
132  SetDParam(0, c->money);
133  DrawString(tr, STR_JUST_CURRENCY_LONG, TC_WHITE, SA_HOR_CENTER);
134  }
135  }
136  break;
137  }
138 
139  case WID_S_MIDDLE:
140  /* Draw status bar */
141  if (this->saving) { // true when saving is active
142  DrawString(tr, STR_STATUSBAR_SAVING_GAME, TC_FROMSTRING, SA_HOR_CENTER | SA_VERT_CENTER);
143  } else if (_do_autosave) {
144  DrawString(tr, STR_STATUSBAR_AUTOSAVE, TC_FROMSTRING, SA_HOR_CENTER);
145  } else if (_pause_mode != PM_UNPAUSED) {
146  StringID msg = (_pause_mode & PM_PAUSED_LINK_GRAPH) ? STR_STATUSBAR_PAUSED_LINK_GRAPH : STR_STATUSBAR_PAUSED;
147  DrawString(tr, msg, TC_FROMSTRING, SA_HOR_CENTER);
148  } else if (this->ticker_scroll < TICKER_STOP && GetStatusbarNews() != nullptr && GetStatusbarNews()->string_id != 0) {
149  /* Draw the scrolling news text */
150  if (!DrawScrollingStatusText(GetStatusbarNews(), ScaleGUITrad(this->ticker_scroll), tr.left, tr.right, tr.top, tr.bottom)) {
153  /* This is the default text */
155  DrawString(tr, STR_STATUSBAR_COMPANY_NAME, TC_FROMSTRING, SA_HOR_CENTER);
156  }
157  }
158  } else {
160  /* This is the default text */
162  DrawString(tr, STR_STATUSBAR_COMPANY_NAME, TC_FROMSTRING, SA_HOR_CENTER);
163  }
164  }
165 
166  if (!this->reminder_timeout.HasFired()) {
167  Dimension icon_size = GetSpriteSize(SPR_UNREAD_NEWS);
168  DrawSprite(SPR_UNREAD_NEWS, PAL_NONE, tr.right - icon_size.width, CenterBounds(r.top, r.bottom, icon_size.height));
169  }
170  break;
171  }
172  }
173 
179  void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
180  {
181  if (!gui_scope) return;
182  switch (data) {
183  default: NOT_REACHED();
184  case SBI_SAVELOAD_START: this->saving = true; break;
185  case SBI_SAVELOAD_FINISH: this->saving = false; break;
186  case SBI_SHOW_TICKER: this->ticker_scroll = 0; break;
187  case SBI_SHOW_REMINDER: this->reminder_timeout.Reset(); break;
188  case SBI_NEWS_DELETED:
189  this->ticker_scroll = TICKER_STOP; // reset ticker ...
190  this->reminder_timeout.Abort(); // ... and reminder
191  break;
192  }
193  }
194 
195  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
196  {
197  switch (widget) {
198  case WID_S_MIDDLE: ShowLastNewsMessage(); break;
200  default: ResetObjectToPlace();
201  }
202  }
203 
205  IntervalTimer<TimerWindow> ticker_scroll_interval = {std::chrono::milliseconds(15), [this](uint count) {
206  if (_pause_mode != PM_UNPAUSED) return;
207 
208  if (this->ticker_scroll < TICKER_STOP) {
209  this->ticker_scroll += count;
211  }
212  }};
213 
214  TimeoutTimer<TimerWindow> reminder_timeout = {REMINDER_START, [this]() {
216  }};
217 
218  IntervalTimer<TimerGameCalendar> daily_interval = {{TimerGameCalendar::DAY, TimerGameCalendar::Priority::NONE}, [this](auto) {
219  this->SetWidgetDirty(WID_S_LEFT);
220  }};
221 };
222 
223 static constexpr NWidgetPart _nested_main_status_widgets[] = {
225  NWidget(WWT_PANEL, COLOUR_GREY, WID_S_LEFT), SetMinimalSize(140, 12), EndContainer(),
226  NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_S_MIDDLE), SetMinimalSize(40, 12), SetDataTip(0x0, STR_STATUSBAR_TOOLTIP_SHOW_LAST_NEWS), SetResize(1, 0),
227  NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_S_RIGHT), SetMinimalSize(140, 12),
228  EndContainer(),
229 };
230 
231 static WindowDesc _main_status_desc(
232  WDP_MANUAL, nullptr, 0, 0,
235  _nested_main_status_widgets
236 );
237 
242 {
243  const StatusBarWindow *w = dynamic_cast<StatusBarWindow*>(FindWindowById(WC_STATUS_BAR, 0));
244  return w != nullptr && w->ticker_scroll < StatusBarWindow::TICKER_STOP;
245 }
246 
251 {
252  new StatusBarWindow(_main_status_desc);
253 }
Class for backupping variables and making sure they are restored later.
#define CLRBITS(x, y)
Clears several bits in a variable.
void Reset()
Reset the timer, so it will fire again after the timeout.
Definition: timer.h:140
bool HasFired() const
Check whether the timeout occurred.
Definition: timer.h:171
void Abort()
Abort the timer so it doesn't fire if it hasn't yet.
Definition: timer.h:161
static Date date
Current date in days (day counter).
static constexpr TimerGame< struct Calendar >::Year MAX_YEAR
MAX_YEAR, nicely rounded value of the number of years that can be encoded in a single 32 bits date,...
static constexpr Date DateAtStartOfYear(Year year)
Calculate the date of the first day of a given year.
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition: window_gui.h:68
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.
Definition: company_cmd.cpp:52
Functions related to companies.
void ShowCompanyFinances(CompanyID company)
Open the finances window of a company.
GUI Functions related to companies.
@ COMPANY_SPECTATOR
The client is spectating.
Definition: company_type.h:35
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.
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition: gfx.cpp:922
PauseMode _pause_mode
The current pause mode.
Definition: gfx.cpp:50
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition: gfx.cpp:851
int DrawString(int left, int right, int top, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition: gfx.cpp:657
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
Definition: gfx.cpp:988
bool FillDrawPixelInfo(DrawPixelInfo *n, int left, int top, int width, int height)
Set up a clipping area for only drawing into a certain area.
Definition: gfx.cpp:1548
Functions related to the gfx engine.
int CenterBounds(int min, int max, int size)
Determine where to draw a centred object inside a widget.
Definition: gfx_func.h:166
@ SA_LEFT
Left align the text.
Definition: gfx_type.h:343
@ SA_HOR_CENTER
Horizontally center the text.
Definition: gfx_type.h:344
@ SA_FORCE
Force the alignment, i.e. don't swap for RTL languages.
Definition: gfx_type.h:355
@ SA_VERT_CENTER
Vertically center the text.
Definition: gfx_type.h:349
@ FS_NORMAL
Index of the normal font in the font tables.
Definition: gfx_type.h:209
constexpr NWidgetPart SetDataTip(uint32_t data, StringID tip)
Widget part function for setting the data and tooltip.
Definition: widget_type.h:1202
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
Definition: widget_type.h:1137
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
Definition: widget_type.h:1309
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
Definition: widget_type.h:1191
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
Definition: widget_type.h:1126
Functions related to news.
const NewsItem * GetStatusbarNews()
Get pointer to the current status bar news item.
Definition: news_gui.cpp:70
void ShowLastNewsMessage()
Show previous news item.
Definition: news_gui.cpp:1039
GUI functions related to the news.
@ PM_UNPAUSED
A normal unpaused game.
Definition: openttd.h:69
@ PM_PAUSED_LINK_GRAPH
A game paused due to the link graph schedule lagging.
Definition: openttd.h:76
A number of safeguards to prevent using unsafe methods.
bool _do_autosave
are we doing an autosave at the moment?
Definition: saveload.cpp:66
Functions/types related to saving and loading games.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition: settings.cpp:57
This file contains all sprite-related enums and defines.
void ShowStatusBar()
Show our status bar.
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)
Definition: statusbar_gui.h:18
@ SBI_SAVELOAD_FINISH
finished saving
Definition: statusbar_gui.h:16
@ SBI_SHOW_TICKER
start scrolling news
Definition: statusbar_gui.h:17
@ SBI_SAVELOAD_START
started saving
Definition: statusbar_gui.h:15
@ SBI_NEWS_DELETED
abort current news display (active news were deleted)
Definition: statusbar_gui.h:19
Types related to the statusbar widgets.
@ WID_S_LEFT
Left part of the statusbar; date is shown there.
@ WID_S_MIDDLE
Middle part; current news or company name or *** SAVING *** or *** PAUSED ***.
@ WID_S_RIGHT
Right part; bank balance.
Definition of base types and functions in a cross-platform compatible way.
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 SetDParamMaxValue(size_t n, uint64_t max_value, uint min_count, FontSize size)
Set DParam n to some number that is suitable for string size computations.
Definition: strings.cpp:127
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings.cpp:104
std::string GetString(StringID string)
Resolve the given StringID into a std::string with all the associated DParam lookups and formatting.
Definition: strings.cpp:319
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
Functions related to OTTD's strings.
@ TD_RTL
Text is written right-to-left by default.
Definition: strings_type.h:24
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
Class to backup a specific variable and restore it upon destruction of this object to prevent stack v...
Money money
Money owned by the company.
Definition: company_base.h:82
bool infinite_money
whether spending money despite negative balance is allowed
Dimensions (a width and height) of a rectangle in 2D.
Data about how and where to blit pixels.
Definition: gfx_type.h:157
DifficultySettings difficulty
settings related to the difficulty
Partial widget specification to allow NWidgets to be written nested.
Definition: widget_type.h:1075
Information about a single item of news.
Definition: news_type.h:128
std::vector< StringParameterData > params
Parameters for string resolving.
Definition: news_type.h:142
StringID string_id
Message text.
Definition: news_type.h:129
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.
Definition: pool_type.hpp:328
static Titem * GetIfValid(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:350
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
Definition: pool_type.hpp:388
Specification of a rectangle with absolute coordinates of all edges.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
IntervalTimer< TimerWindow > ticker_scroll_interval
Move information on the ticker slowly from one side to the other.
static const int TICKER_STOP
scrolling is finished when counter reaches this value
void OnInvalidateData([[maybe_unused]] int data=0, [[maybe_unused]] bool gui_scope=true) override
Some data on this window has become invalid.
static const int COUNTER_STEP
this is subtracted from active counters every tick
static constexpr auto REMINDER_START
time in ms for reminder notification (red dot on the right) to stay
High level window description.
Definition: window_gui.h:159
Data structure for an opened window.
Definition: window_gui.h:273
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition: window.cpp:551
ResizeInfo resize
Resize information.
Definition: window_gui.h:314
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition: window.cpp:1746
WindowFlags flags
Window flags.
Definition: window_gui.h:300
virtual void FindWindowPlacementAndResize(int def_width, int def_height)
Resize window towards the default size.
Definition: window.cpp:1420
WindowNumber window_number
Window number within the window class.
Definition: window_gui.h:302
Functions related to tile highlights.
void ResetObjectToPlace()
Reset the cursor and mouse mode handling back to default (normal cursor, only clicking in windows).
Definition: viewport.cpp:3498
Definition of Interval and OneShot timers.
Definition of the game-calendar-timer.
Definition of the Window system.
uint _toolbar_width
Width of the toolbar, shared by statusbar.
Definition: toolbar_gui.cpp:74
Stuff related to the (main) toolbar.
@ WWT_PUSHBTN
Normal push-button (no toggle button) with custom drawing.
Definition: widget_type.h:111
@ NWID_HORIZONTAL
Horizontal container.
Definition: widget_type.h:75
@ WWT_PANEL
Simple depressed panel.
Definition: widget_type.h:50
int PositionStatusbar(Window *w)
(Re)position statusbar window at the screen.
Definition: window.cpp:3393
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition: window.cpp:1098
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope)
Mark window data of the window of a given class and specific window number as invalid (in need of re-...
Definition: window.cpp:3211
Window functions not directly related to making/drawing windows.
Functions, definitions and such used only by the GUI.
@ WF_WHITE_BORDER
Window white border counter bit mask.
Definition: window_gui.h:236
@ WDF_NO_CLOSE
This window can't be interactively closed.
Definition: window_gui.h:206
@ WDF_NO_FOCUS
This window won't get focus/make any other window lose focus when click.
Definition: window_gui.h:205
@ WDP_MANUAL
Manually align the window (so no automatic location finding)
Definition: window_gui.h:146
int WidgetID
Widget ID.
Definition: window_type.h:18
@ WC_STATUS_BAR
Statusbar (at the bottom of your screen); Window numbers:
Definition: window_type.h:64
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition: window_type.h:45
Functions related to zooming.
int ScaleGUITrad(int value)
Scale traditional pixel dimensions to GUI zoom level.
Definition: zoom_func.h:117