OpenTTD Source 20250312-master-gcdcc6b491d
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"
21
23
24#include "table/strings.h"
25
26#include "safeguards.h"
27
29 Scrollbar *vscroll = nullptr;
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
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.ToIndustryID())->location.tile; break;
87 case SourceType::Town: xy = Town::Get(s->src.ToTownID())->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.ToIndustryID())->location.tile; break;
97 case SourceType::Town: xy = Town::Get(s->dst.ToTownID())->xy; break;
98 default: NOT_REACHED();
99 }
100
101 if (_ctrl_pressed) {
103 } else {
105 }
106 }
107 }
108
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()) {
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
146
147 void DrawCargoIcon(const Rect &r, int y_offset, CargoType cargo_type) const
148 {
149 bool rtl = _current_text_dir == TD_RTL;
150 SpriteID icon = CargoSpec::Get(cargo_type)->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 */
177 const CargoSpec *cs = CargoSpec::Get(s->cargo_type);
178 std::string text;
179
180 /* If using wallclock units, show minutes remaining. Otherwise show the date when the subsidy ends. */
183 cs->name, s->src.GetFormat(), s->src.id, s->dst.GetFormat(), s->dst.id,
185 s->remaining + 1); // We get the rest of the current economy month for free, since the expiration is checked on each new month.
186 } else {
188 cs->name, s->src.GetFormat(), s->src.id, s->dst.GetFormat(), s->dst.id,
190 TimerGameEconomy::date.base() - ymd.day + s->remaining * 32);
191 }
192
193 DrawCargoIcon(tr, pos * GetCharacterHeight(FS_NORMAL), s->cargo_type);
194 DrawString(sr.left, sr.right, sr.top + pos * GetCharacterHeight(FS_NORMAL), text);
195 }
196 pos++;
197 num++;
198 }
199 }
200
201 if (num == 0) {
202 if (IsInsideMM(pos, 0, cap)) DrawString(tr.left, tr.right, tr.top + pos * GetCharacterHeight(FS_NORMAL), STR_SUBSIDIES_NONE);
203 pos++;
204 }
205
206 /* Section for drawing the already granted subsidies */
207 pos++;
208 if (IsInsideMM(pos, 0, cap)) DrawString(tr.left, tr.right, tr.top + pos * GetCharacterHeight(FS_NORMAL), STR_SUBSIDIES_SUBSIDISED_TITLE);
209 pos++;
210 num = 0;
211
212 for (const Subsidy *s : Subsidy::Iterate()) {
213 if (s->IsAwarded()) {
214 if (IsInsideMM(pos, 0, cap)) {
215 const CargoSpec *cs = CargoSpec::Get(s->cargo_type);
216 std::string text;
217
218 /* If using wallclock units, show minutes remaining. Otherwise show the date when the subsidy ends. */
221 cs->name, s->src.GetFormat(), s->src.id, s->dst.GetFormat(), s->dst.id,
224 s->remaining + 1); // We get the rest of the current economy month for free, since the expiration is checked on each new month.
225 } else {
227 cs->name, s->src.GetFormat(), s->src.id, s->dst.GetFormat(), s->dst.id,
230 TimerGameEconomy::date.base() - ymd.day + s->remaining * 32);
231 }
232
233 /* Displays the two connected stations */
234 DrawCargoIcon(tr, pos * GetCharacterHeight(FS_NORMAL), s->cargo_type);
235 DrawString(sr.left, sr.right, sr.top + pos * GetCharacterHeight(FS_NORMAL), text);
236 }
237 pos++;
238 num++;
239 }
240 }
241
242 if (num == 0) {
243 if (IsInsideMM(pos, 0, cap)) DrawString(tr.left, tr.right, tr.top + pos * GetCharacterHeight(FS_NORMAL), STR_SUBSIDIES_NONE);
244 pos++;
245 }
246 }
247
248 void OnResize() override
249 {
250 this->vscroll->SetCapacityFromWidget(this, WID_SUL_PANEL, WidgetDimensions::scaled.framerect.Vertical());
251 }
252
258 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
259 {
260 if (!gui_scope) return;
261 this->vscroll->SetCount(this->CountLines());
262 }
263};
264
265static constexpr NWidgetPart _nested_subsidies_list_widgets[] = {
267 NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
268 NWidget(WWT_CAPTION, COLOUR_BROWN), SetStringTip(STR_SUBSIDIES_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
269 NWidget(WWT_SHADEBOX, COLOUR_BROWN),
270 NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
271 NWidget(WWT_STICKYBOX, COLOUR_BROWN),
272 EndContainer(),
274 NWidget(WWT_PANEL, COLOUR_BROWN, WID_SUL_PANEL), SetToolTip(STR_SUBSIDIES_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER), SetResize(1, 1), SetScrollbar(WID_SUL_SCROLLBAR), EndContainer(),
277 NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
278 EndContainer(),
279 EndContainer(),
280};
281
282static WindowDesc _subsidies_list_desc(
283 WDP_AUTO, "list_subsidies", 500, 127,
285 {},
286 _nested_subsidies_list_widgets
287);
288
289
290void ShowSubsidiesList()
291{
292 AllocateWindowDescFront<SubsidyListWindow>(_subsidies_list_desc, 0);
293}
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:23
Dimension GetLargestCargoIconSize()
Get dimensions of largest cargo icon.
Scrollbar data structure.
size_type GetCapacity() const
Gets the number of visible elements of the scrollbar.
void SetCount(size_t num)
Sets the number of elements in the list.
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:2447
void SetCapacityFromWidget(Window *w, WidgetID widget, int padding=0)
Set capacity of visible elements from the size and resize properties of a widget.
Definition widget.cpp:2521
size_type GetPosition() const
Gets the position of the first visible element in the list.
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:40
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:29
int hsep_normal
Normal horizontal spacing.
Definition window_gui.h:61
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:923
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:852
int DrawString(int left, int right, int top, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition gfx.cpp:658
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:38
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
Definition gfx.cpp:989
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:17
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:243
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
constexpr NWidgetPart SetStringTip(StringID string, StringID tip={})
Widget part function for setting the string and tooltip.
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 SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
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 size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
A number of safeguards to prevent using unsafe methods.
@ Industry
Source/destination is an industry.
@ Town
Source/destination is a town.
Definition of base types and functions in a cross-platform compatible way.
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:426
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition strings.cpp:56
Functions related to OTTD's strings.
@ TD_RTL
Text is written right-to-left by default.
Specification of a cargo type.
Definition cargotype.h:74
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:137
SpriteID GetCargoIcon() const
Get sprite for showing cargo of this type.
StringID name
Name of this type of cargo.
Definition cargotype.h:91
Dimensions (a width and height) of a rectangle in 2D.
Partial widget specification to allow NWidgets to be written nested.
Coordinates of a point in 2D.
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static Titem * Get(auto 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 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.
SourceID id
Index of industry/town/HQ, Source::Invalid if unknown/invalid.
Definition source_type.h:36
StringID GetFormat() const
Get the format string for a subsidy Source.
Definition subsidy.cpp:56
SourceType type
Type of source_id.
Definition source_type.h:37
uint CountLines()
Count the number of lines in this window.
void OnInit() override
Notification that the nested widget tree gets initialized.
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 UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
void OnResize() override
Called after the window got resized.
Struct about subsidies, offered and awarded.
bool IsAwarded() const
Tests whether this subsidy has been awarded to someone.
CargoType cargo_type
Cargo type involved in this subsidy, INVALID_CARGO for invalid subsidy.
CompanyID awarded
Subsidy is awarded to this company; CompanyID::Invalid() if it's not awarded to anyone.
Source dst
Destination of subsidised path.
Source src
Source of subsidised path.
uint16_t remaining
Remaining months when this subsidy is valid.
High level window description.
Definition window_gui.h:168
Number to differentiate different windows of the same class.
Data structure for an opened window.
Definition window_gui.h:274
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1736
ResizeInfo resize
Resize information.
Definition window_gui.h:315
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1726
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:973
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:311
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:303
Subsidy base class.
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.
Functions related to (drawing on) viewports.
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:65
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:40
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition widget_type.h:56
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition widget_type.h:54
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition widget_type.h:51
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:75
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:67
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition widget_type.h:59
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition widget_type.h:58
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition widget_type.h:55
Functions, definitions and such used only by the GUI.
@ WDP_AUTO
Find a place automatically.
Definition window_gui.h:145
int WidgetID
Widget ID.
Definition window_type.h:20
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:47
@ WC_SUBSIDIES_LIST
Subsidies list; Window numbers: