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/>.
8 /** @file subsidy_gui.cpp GUI for subsidies. */
13 #include "window_gui.h"
14 #include "strings_func.h"
15 #include "timer/timer_game_calendar.h"
16 #include "viewport_func.h"
18 #include "subsidy_func.h"
19 #include "subsidy_base.h"
20 #include "core/geometry_func.hpp"
22 #include "widgets/subsidy_widget.h"
24 #include "table/strings.h"
26 #include "safeguards.h"
28 struct SubsidyListWindow
: Window
{
30 Dimension cargo_icon_size
;
32 SubsidyListWindow(WindowDesc
*desc
, WindowNumber window_number
) : Window(desc
)
34 this->CreateNestedTree();
35 this->vscroll
= this->GetScrollbar(WID_SUL_SCROLLBAR
);
36 this->FinishInitNested(window_number
);
37 this->OnInvalidateData(0);
40 void OnInit() override
42 this->cargo_icon_size
= GetLargestCargoIconSize();
45 void OnClick([[maybe_unused
]] Point pt
, WidgetID widget
, [[maybe_unused
]] int click_count
) override
47 if (widget
!= WID_SUL_PANEL
) return;
49 int y
= this->vscroll
->GetScrolledRowFromWidget(pt
.y
, this, WID_SUL_PANEL
, WidgetDimensions::scaled
.framerect
.top
);
51 for (const Subsidy
*s
: Subsidy::Iterate()) {
52 if (!s
->IsAwarded()) {
67 y
-= 2; // "Services already subsidised:"
70 for (const Subsidy
*s
: Subsidy::Iterate()) {
81 void HandleClick(const Subsidy
*s
)
83 /* determine src coordinate for subsidy and try to scroll to it */
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();
91 if (_ctrl_pressed
|| !ScrollMainWindowToTile(xy
)) {
92 if (_ctrl_pressed
) ShowExtraViewportWindow(xy
);
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();
102 ShowExtraViewportWindow(xy
);
104 ScrollMainWindowToTile(xy
);
110 * Count the number of lines in this window.
111 * @return the number of lines
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()) {
126 /* Count the 'none' lines */
127 if (num_awarded
== 0) num_awarded
= 1;
128 if (num_not_awarded
== 0) num_not_awarded
= 1;
130 /* Offered, accepted and an empty line before the accepted ones. */
131 return 3 + num_awarded
+ num_not_awarded
;
134 void UpdateWidgetSize(WidgetID widget
, Dimension
*size
, [[maybe_unused
]] const Dimension
&padding
, [[maybe_unused
]] Dimension
*fill
, [[maybe_unused
]] Dimension
*resize
) override
136 if (widget
!= WID_SUL_PANEL
) return;
137 Dimension d
= maxdim(GetStringBoundingBox(STR_SUBSIDIES_OFFERED_TITLE
), GetStringBoundingBox(STR_SUBSIDIES_SUBSIDISED_TITLE
));
139 resize
->height
= GetCharacterHeight(FS_NORMAL
);
142 d
.width
+= WidgetDimensions::scaled
.framerect
.Horizontal();
143 d
.height
+= WidgetDimensions::scaled
.framerect
.Vertical();
144 *size
= maxdim(*size
, d
);
147 void DrawCargoIcon(const Rect
&r
, int y_offset
, CargoID cid
) const
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
);
156 void DrawWidget(const Rect
&r
, WidgetID widget
) const override
158 if (widget
!= WID_SUL_PANEL
) return;
160 TimerGameEconomy::YearMonthDay ymd
= TimerGameEconomy::ConvertDateToYMD(TimerGameEconomy::date
);
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
);
165 int pos
= -this->vscroll
->GetPosition();
166 const int cap
= this->vscroll
->GetCapacity();
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
);
173 for (const Subsidy
*s
: Subsidy::Iterate()) {
174 if (!s
->IsAwarded()) {
175 if (IsInsideMM(pos
, 0, cap
)) {
176 /* Displays the two offered towns */
177 SetupSubsidyDecodeParam(s
, SubsidyDecodeParamType::Gui
);
178 /* If using wallclock units, show minutes remaining. Otherwise show the date when the subsidy ends. */
179 if (TimerGameEconomy::UsingWallclockUnits()) {
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.
183 SetDParam(7, STR_SUBSIDIES_OFFERED_EXPIRY_DATE
);
184 SetDParam(8, TimerGameEconomy::date
- ymd
.day
+ s
->remaining
* 32);
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
);
196 if (IsInsideMM(pos
, 0, cap
)) DrawString(tr
.left
, tr
.right
, tr
.top
+ pos
* GetCharacterHeight(FS_NORMAL
), STR_SUBSIDIES_NONE
);
200 /* Section for drawing the already granted subsidies */
202 if (IsInsideMM(pos
, 0, cap
)) DrawString(tr
.left
, tr
.right
, tr
.top
+ pos
* GetCharacterHeight(FS_NORMAL
), STR_SUBSIDIES_SUBSIDISED_TITLE
);
206 for (const Subsidy
*s
: Subsidy::Iterate()) {
207 if (s
->IsAwarded()) {
208 if (IsInsideMM(pos
, 0, cap
)) {
209 SetupSubsidyDecodeParam(s
, SubsidyDecodeParamType::Gui
);
210 SetDParam(7, s
->awarded
);
211 /* If using wallclock units, show minutes remaining. Otherwise show the date when the subsidy ends. */
212 if (TimerGameEconomy::UsingWallclockUnits()) {
213 SetDParam(8, STR_SUBSIDIES_SUBSIDISED_EXPIRY_TIME
);
214 SetDParam(9, s
->remaining
);
217 SetDParam(8, STR_SUBSIDIES_SUBSIDISED_EXPIRY_DATE
);
218 SetDParam(9, TimerGameEconomy::date
- ymd
.day
+ s
->remaining
* 32);
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
);
231 if (IsInsideMM(pos
, 0, cap
)) DrawString(tr
.left
, tr
.right
, tr
.top
+ pos
* GetCharacterHeight(FS_NORMAL
), STR_SUBSIDIES_NONE
);
236 void OnResize() override
238 this->vscroll
->SetCapacityFromWidget(this, WID_SUL_PANEL
);
242 * Some data on this window has become invalid.
243 * @param data Information about the changed data.
244 * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
246 void OnInvalidateData([[maybe_unused
]] int data
= 0, [[maybe_unused
]] bool gui_scope
= true) override
248 if (!gui_scope
) return;
249 this->vscroll
->SetCount(this->CountLines());
253 static constexpr NWidgetPart _nested_subsidies_list_widgets
[] = {
254 NWidget(NWID_HORIZONTAL
),
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
),
261 NWidget(NWID_HORIZONTAL
),
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(),
263 NWidget(NWID_VERTICAL
),
264 NWidget(NWID_VSCROLLBAR
, COLOUR_BROWN
, WID_SUL_SCROLLBAR
),
265 NWidget(WWT_RESIZEBOX
, COLOUR_BROWN
),
270 static WindowDesc
_subsidies_list_desc(__FILE__
, __LINE__
,
271 WDP_AUTO
, "list_subsidies", 500, 127,
272 WC_SUBSIDIES_LIST
, WC_NONE
,
274 std::begin(_nested_subsidies_list_widgets
), std::end(_nested_subsidies_list_widgets
)
278 void ShowSubsidiesList()
280 AllocateWindowDescFront
<SubsidyListWindow
>(&_subsidies_list_desc
, 0);