OpenTTD Source  20241121-master-g67a0fccfad
subsidy_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 "industry.h"
12 #include "town.h"
13 #include "window_gui.h"
14 #include "strings_func.h"
16 #include "viewport_func.h"
17 #include "gui.h"
18 #include "subsidy_func.h"
19 #include "subsidy_base.h"
20 #include "core/geometry_func.hpp"
21 
22 #include "widgets/subsidy_widget.h"
23 
24 #include "table/strings.h"
25 
26 #include "safeguards.h"
27 
29  Scrollbar *vscroll;
30  Dimension cargo_icon_size;
31 
33  {
34  this->CreateNestedTree();
35  this->vscroll = this->GetScrollbar(WID_SUL_SCROLLBAR);
36  this->FinishInitNested(window_number);
37  this->OnInvalidateData(0);
38  }
39 
40  void OnInit() override
41  {
42  this->cargo_icon_size = GetLargestCargoIconSize();
43  }
44 
45  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
46  {
47  if (widget != WID_SUL_PANEL) return;
48 
49  int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SUL_PANEL, WidgetDimensions::scaled.framerect.top);
50  int num = 0;
51  for (const Subsidy *s : Subsidy::Iterate()) {
52  if (!s->IsAwarded()) {
53  y--;
54  if (y == 0) {
55  this->HandleClick(s);
56  return;
57  }
58  num++;
59  }
60  }
61 
62  if (num == 0) {
63  y--; // "None"
64  if (y < 0) return;
65  }
66 
67  y -= 2; // "Services already subsidised:"
68  if (y < 0) return;
69 
70  for (const Subsidy *s : Subsidy::Iterate()) {
71  if (s->IsAwarded()) {
72  y--;
73  if (y == 0) {
74  this->HandleClick(s);
75  return;
76  }
77  }
78  }
79  }
80 
81  void HandleClick(const Subsidy *s)
82  {
83  /* determine src coordinate for subsidy and try to scroll to it */
84  TileIndex xy;
85  switch (s->src_type) {
86  case SourceType::Industry: xy = Industry::Get(s->src)->location.tile; break;
87  case SourceType::Town: xy = Town::Get(s->src)->xy; break;
88  default: NOT_REACHED();
89  }
90 
93 
94  /* otherwise determine dst coordinate for subsidy and scroll to it */
95  switch (s->dst_type) {
96  case SourceType::Industry: xy = Industry::Get(s->dst)->location.tile; break;
97  case SourceType::Town: xy = Town::Get(s->dst)->xy; break;
98  default: NOT_REACHED();
99  }
100 
101  if (_ctrl_pressed) {
103  } else {
105  }
106  }
107  }
108 
113  uint CountLines()
114  {
115  /* Count number of (non) awarded subsidies */
116  uint num_awarded = 0;
117  uint num_not_awarded = 0;
118  for (const Subsidy *s : Subsidy::Iterate()) {
119  if (!s->IsAwarded()) {
120  num_not_awarded++;
121  } else {
122  num_awarded++;
123  }
124  }
125 
126  /* Count the 'none' lines */
127  if (num_awarded == 0) num_awarded = 1;
128  if (num_not_awarded == 0) num_not_awarded = 1;
129 
130  /* Offered, accepted and an empty line before the accepted ones. */
131  return 3 + num_awarded + num_not_awarded;
132  }
133 
134  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
135  {
136  if (widget != WID_SUL_PANEL) return;
137  Dimension d = maxdim(GetStringBoundingBox(STR_SUBSIDIES_OFFERED_TITLE), GetStringBoundingBox(STR_SUBSIDIES_SUBSIDISED_TITLE));
138 
140 
141  d.height *= 5;
144  size = maxdim(size, d);
145  }
146 
147  void DrawCargoIcon(const Rect &r, int y_offset, CargoID cid) const
148  {
149  bool rtl = _current_text_dir == TD_RTL;
150  SpriteID icon = CargoSpec::Get(cid)->GetCargoIcon();
151  Dimension d = GetSpriteSize(icon);
152  Rect ir = r.WithWidth(this->cargo_icon_size.width, rtl).WithHeight(GetCharacterHeight(FS_NORMAL));
153  DrawSprite(icon, PAL_NONE, CenterBounds(ir.left, ir.right, d.width), CenterBounds(ir.top, ir.bottom, this->cargo_icon_size.height) + y_offset);
154  }
155 
156  void DrawWidget(const Rect &r, WidgetID widget) const override
157  {
158  if (widget != WID_SUL_PANEL) return;
159 
160  TimerGameEconomy::YearMonthDay ymd = TimerGameEconomy::ConvertDateToYMD(TimerGameEconomy::date);
161 
162  Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
163  Rect sr = tr.Indent(this->cargo_icon_size.width + WidgetDimensions::scaled.hsep_normal, _current_text_dir == TD_RTL);
164 
165  int pos = -this->vscroll->GetPosition();
166  const int cap = this->vscroll->GetCapacity();
167 
168  /* Section for drawing the offered subsidies */
169  if (IsInsideMM(pos, 0, cap)) DrawString(tr.left, tr.right, tr.top + pos * GetCharacterHeight(FS_NORMAL), STR_SUBSIDIES_OFFERED_TITLE);
170  pos++;
171 
172  uint num = 0;
173  for (const Subsidy *s : Subsidy::Iterate()) {
174  if (!s->IsAwarded()) {
175  if (IsInsideMM(pos, 0, cap)) {
176  /* Displays the two offered towns */
178  /* If using wallclock units, show minutes remaining. Otherwise show the date when the subsidy ends. */
180  SetDParam(7, STR_SUBSIDIES_OFFERED_EXPIRY_TIME);
181  SetDParam(8, s->remaining + 1); // We get the rest of the current economy month for free, since the expiration is checked on each new month.
182  } else {
183  SetDParam(7, STR_SUBSIDIES_OFFERED_EXPIRY_DATE);
184  SetDParam(8, TimerGameEconomy::date - ymd.day + s->remaining * 32);
185  }
186 
187  DrawCargoIcon(tr, pos * GetCharacterHeight(FS_NORMAL), s->cargo_type);
188  DrawString(sr.left, sr.right, sr.top + pos * GetCharacterHeight(FS_NORMAL), STR_SUBSIDIES_OFFERED_FROM_TO);
189  }
190  pos++;
191  num++;
192  }
193  }
194 
195  if (num == 0) {
196  if (IsInsideMM(pos, 0, cap)) DrawString(tr.left, tr.right, tr.top + pos * GetCharacterHeight(FS_NORMAL), STR_SUBSIDIES_NONE);
197  pos++;
198  }
199 
200  /* Section for drawing the already granted subsidies */
201  pos++;
202  if (IsInsideMM(pos, 0, cap)) DrawString(tr.left, tr.right, tr.top + pos * GetCharacterHeight(FS_NORMAL), STR_SUBSIDIES_SUBSIDISED_TITLE);
203  pos++;
204  num = 0;
205 
206  for (const Subsidy *s : Subsidy::Iterate()) {
207  if (s->IsAwarded()) {
208  if (IsInsideMM(pos, 0, cap)) {
210  SetDParam(7, s->awarded);
211  /* If using wallclock units, show minutes remaining. Otherwise show the date when the subsidy ends. */
213  SetDParam(8, STR_SUBSIDIES_SUBSIDISED_EXPIRY_TIME);
214  SetDParam(9, s->remaining);
215  }
216  else {
217  SetDParam(8, STR_SUBSIDIES_SUBSIDISED_EXPIRY_DATE);
218  SetDParam(9, TimerGameEconomy::date - ymd.day + s->remaining * 32);
219  }
220 
221  /* Displays the two connected stations */
222  DrawCargoIcon(tr, pos * GetCharacterHeight(FS_NORMAL), s->cargo_type);
223  DrawString(sr.left, sr.right, sr.top + pos * GetCharacterHeight(FS_NORMAL), STR_SUBSIDIES_SUBSIDISED_FROM_TO);
224  }
225  pos++;
226  num++;
227  }
228  }
229 
230  if (num == 0) {
231  if (IsInsideMM(pos, 0, cap)) DrawString(tr.left, tr.right, tr.top + pos * GetCharacterHeight(FS_NORMAL), STR_SUBSIDIES_NONE);
232  pos++;
233  }
234  }
235 
236  void OnResize() override
237  {
238  this->vscroll->SetCapacityFromWidget(this, WID_SUL_PANEL, WidgetDimensions::scaled.framerect.Vertical());
239  }
240 
246  void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
247  {
248  if (!gui_scope) return;
249  this->vscroll->SetCount(this->CountLines());
250  }
251 };
252 
253 static constexpr NWidgetPart _nested_subsidies_list_widgets[] = {
255  NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
256  NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_SUBSIDIES_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
257  NWidget(WWT_SHADEBOX, COLOUR_BROWN),
258  NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
259  NWidget(WWT_STICKYBOX, COLOUR_BROWN),
260  EndContainer(),
262  NWidget(WWT_PANEL, COLOUR_BROWN, WID_SUL_PANEL), SetDataTip(0x0, STR_SUBSIDIES_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER), SetResize(1, 1), SetScrollbar(WID_SUL_SCROLLBAR), EndContainer(),
264  NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_SUL_SCROLLBAR),
265  NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
266  EndContainer(),
267  EndContainer(),
268 };
269 
270 static WindowDesc _subsidies_list_desc(
271  WDP_AUTO, "list_subsidies", 500, 127,
273  0,
274  _nested_subsidies_list_widgets
275 );
276 
277 
278 void ShowSubsidiesList()
279 {
280  AllocateWindowDescFront<SubsidyListWindow>(_subsidies_list_desc, 0);
281 }
uint8_t CargoID
Cargo slots to indicate a cargo type within a game.
Definition: cargo_type.h:22
@ Industry
Source/destination is an industry.
@ Town
Source/destination is a town.
Dimension GetLargestCargoIconSize()
Get dimensions of largest cargo icon.
Definition: cargotype.cpp:156
Scrollbar data structure.
Definition: widget_type.h:694
size_type GetCapacity() const
Gets the number of visible elements of the scrollbar.
Definition: widget_type.h:731
void SetCount(size_t num)
Sets the number of elements in the list.
Definition: widget_type.h:780
size_type GetScrolledRowFromWidget(int clickpos, const Window *const w, WidgetID widget, int padding=0, int line_height=-1) const
Compute the row of a scrolled widget that a user clicked in.
Definition: widget.cpp:2320
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:2394
size_type GetPosition() const
Gets the position of the first visible element in the list.
Definition: widget_type.h:740
static Date date
Current date in days (day counter).
static bool UsingWallclockUnits(bool newgame=false)
Check if we are using wallclock units.
static YearMonthDay ConvertDateToYMD(Date date)
Converts a Date to a Year, Month & Day.
RectPadding framerect
Standard padding inside many panels.
Definition: window_gui.h:42
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition: window_gui.h:68
int hsep_normal
Normal horizontal spacing.
Definition: window_gui.h:63
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
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 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
int CenterBounds(int min, int max, int size)
Determine where to draw a centred object inside a widget.
Definition: gfx_func.h:166
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition: gfx_type.h:18
@ FS_NORMAL
Index of the normal font in the font tables.
Definition: gfx_type.h:209
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
Definition: widget_type.h:1284
constexpr NWidgetPart SetDataTip(uint32_t data, StringID tip)
Widget part function for setting the data and tooltip.
Definition: widget_type.h:1202
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
GUI functions that shouldn't be here.
void ShowExtraViewportWindow(TileIndex tile=INVALID_TILE)
Show a new Extra Viewport window.
Base of all industries.
constexpr bool IsInsideMM(const T x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
Definition: math_func.hpp:268
A number of safeguards to prevent using unsafe methods.
Definition of base types and functions in a cross-platform compatible way.
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
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
SpriteID GetCargoIcon() const
Get sprite for showing cargo of this type.
Definition: cargotype.cpp:169
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo ID.
Definition: cargotype.h:134
Dimensions (a width and height) of a rectangle in 2D.
Partial widget specification to allow NWidgets to be written nested.
Definition: widget_type.h:1075
Coordinates of a point in 2D.
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:339
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
Definition: pool_type.hpp:388
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 WithHeight(int height, bool end=false) const
Copy Rect and set its height.
Rect Indent(int indent, bool end) const
Copy Rect and indent it from its position.
uint CountLines()
Count the number of lines in this window.
void OnInvalidateData([[maybe_unused]] int data=0, [[maybe_unused]] bool gui_scope=true) override
Some data on this window has become invalid.
void OnInit() override
Notification that the nested widget tree gets initialized.
Definition: subsidy_gui.cpp:40
void OnResize() override
Called after the window got resized.
Struct about subsidies, offered and awarded.
Definition: subsidy_base.h:22
bool IsAwarded() const
Tests whether this subsidy has been awarded to someone.
Definition: subsidy_base.h:45
SourceType dst_type
Destination of subsidised path (SourceType::Industry or SourceType::Town)
Definition: subsidy_base.h:27
SourceType src_type
Source of subsidised path (SourceType::Industry or SourceType::Town)
Definition: subsidy_base.h:26
CompanyID awarded
Subsidy is awarded to this company; INVALID_COMPANY if it's not awarded to anyone.
Definition: subsidy_base.h:25
CargoID cargo_type
Cargo type involved in this subsidy, INVALID_CARGO for invalid subsidy.
Definition: subsidy_base.h:23
uint16_t remaining
Remaining months when this subsidy is valid.
Definition: subsidy_base.h:24
SourceID src
Index of source. Either TownID or IndustryID.
Definition: subsidy_base.h:28
SourceID dst
Index of destination. Either TownID or IndustryID.
Definition: subsidy_base.h:29
High level window description.
Definition: window_gui.h:159
Data structure for an opened window.
Definition: window_gui.h:273
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition: window.cpp:1733
ResizeInfo resize
Resize information.
Definition: window_gui.h:314
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition: window.cpp:1723
Window(WindowDesc &desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition: window.cpp:1756
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition: window.cpp:314
WindowNumber window_number
Window number within the window class.
Definition: window_gui.h:302
std::pair< NewsReferenceType, NewsReferenceType > SetupSubsidyDecodeParam(const Subsidy *s, SubsidyDecodeParamType mode, uint parameter_offset)
Setup the string parameters for printing the subsidy at the screen, and compute the news reference fo...
Definition: subsidy.cpp:75
Subsidy base class.
@ Gui
Subsidies listed in the Subsidy GUI.
Functions related to subsidies.
Types related to the subsidy widgets.
@ WID_SUL_PANEL
Main panel of window.
@ WID_SUL_SCROLLBAR
Scrollbar of panel.
Definition of the game-calendar-timer.
Base of the town class.
bool ScrollMainWindowToTile(TileIndex tile, bool instant)
Scrolls the viewport of the main window to a given location.
Definition: viewport.cpp:2515
Functions related to (drawing on) viewports.
@ NWID_HORIZONTAL
Horizontal container.
Definition: widget_type.h:75
@ WWT_PANEL
Simple depressed panel.
Definition: widget_type.h:50
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition: widget_type.h:66
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition: widget_type.h:64
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition: widget_type.h:61
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition: widget_type.h:84
@ NWID_VERTICAL
Vertical container.
Definition: widget_type.h:77
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition: widget_type.h:69
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition: widget_type.h:68
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition: widget_type.h:65
Functions, definitions and such used only by the GUI.
@ WDP_AUTO
Find a place automatically.
Definition: window_gui.h:147
int WidgetID
Widget ID.
Definition: window_type.h:18
int32_t WindowNumber
Number to differentiate different windows of the same class.
Definition: window_type.h:737
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition: window_type.h:45
@ WC_SUBSIDIES_LIST
Subsidies list; Window numbers:
Definition: window_type.h:260