OpenTTD Source 20260512-master-g20b387b91f
newgrf_badge_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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "stdafx.h"
11
12#include "core/flatset_type.hpp"
13#include "dropdown_type.h"
14#include "dropdown_func.h"
15#include "newgrf.h"
16#include "newgrf_badge.h"
17#include "newgrf_badge_config.h"
18#include "newgrf_badge_gui.h"
19#include "newgrf_badge_type.h"
20#include "settings_gui.h"
21#include "spritecache.h"
22#include "strings_func.h"
24#include "window_gui.h"
25#include "window_type.h"
26#include "zoom_func.h"
27
28#include "table/strings.h"
29
31
32#include "safeguards.h"
33
34static constexpr uint MAX_BADGE_HEIGHT = 12;
35static constexpr uint MAX_BADGE_WIDTH = MAX_BADGE_HEIGHT * 2;
36
43static Dimension GetBadgeMaximalDimension(BadgeClassID class_index, GrfSpecFeature feature)
44{
46
47 for (const auto &badge : GetBadges()) {
48 if (badge.class_index != class_index) continue;
49
50 PalSpriteID ps = GetBadgeSprite(badge, feature, std::nullopt, PAL_NONE);
51 if (ps.sprite == 0) continue;
52
53 /* Get unscaled sprite size ignoring offsets. Don't use GetSpriteSize as it applies offsets,
54 * and GetScaledSpriteSize uses interface scale. */
55 const Sprite *sprite = GetSprite(ps.sprite, SpriteType::Normal);
56 if (sprite == nullptr) continue;
57
58 uint width = UnScaleByZoom(sprite->width, ZoomLevel::Normal);
59 d.width = std::max(d.width, width);
60 if (d.width > MAX_BADGE_WIDTH) break;
61 }
62
63 d.width = std::min(d.width, MAX_BADGE_WIDTH);
64 return d;
65}
66
67static bool operator<(const GUIBadgeClasses::Element &a, const GUIBadgeClasses::Element &b)
68{
69 if (a.column_group != b.column_group) return a.column_group < b.column_group;
70 if (a.sort_order != b.sort_order) return a.sort_order < b.sort_order;
71 return a.label < b.label;
72}
73
78GUIBadgeClasses::GUIBadgeClasses(GrfSpecFeature feature) : UsedBadgeClasses(feature)
79{
80 /* Get list of classes used by feature. */
81 uint max_column = 0;
82 for (BadgeClassID class_index : this->Classes()) {
83 const Badge *class_badge = GetClassBadge(class_index);
84 if (class_badge->name == STR_NULL) continue;
85
86 Dimension size = GetBadgeMaximalDimension(class_index, feature);
87 if (size.width == 0) continue;
88
89 const auto [config, sort_order] = GetBadgeClassConfigItem(feature, class_badge->label);
90
91 this->gui_classes.emplace_back(class_index, config.column, config.show_icon, sort_order, size, class_badge->label);
92 if (size.width != 0 && config.show_icon) max_column = std::max(max_column, config.column);
93 }
94
95 std::sort(std::begin(this->gui_classes), std::end(this->gui_classes));
96
97 /* Determine total width of visible badge columns. */
98 this->column_widths.resize(max_column + 1);
99 for (const auto &el : this->gui_classes) {
100 if (!el.visible || el.size.width == 0) continue;
101 this->column_widths[el.column_group] += ScaleGUITrad(el.size.width) + WidgetDimensions::scaled.hsep_normal;
102 }
103
104 /* Replace trailing `hsep_normal` spacer with wider `hsep_wide` spacer. */
105 for (uint &badge_width : this->column_widths) {
106 if (badge_width == 0) continue;
107 badge_width = badge_width - WidgetDimensions::scaled.hsep_normal + WidgetDimensions::scaled.hsep_wide;
108 }
109}
110
116{
117 return std::accumulate(std::begin(this->column_widths), std::end(this->column_widths), 0U);
118}
119
127int DrawBadgeNameList(Rect r, std::span<const BadgeID> badges, GrfSpecFeature)
128{
129 if (badges.empty()) return r.top;
130
131 FlatSet<BadgeClassID> class_indexes;
132 for (const BadgeID &index : badges) class_indexes.insert(GetBadge(index)->class_index);
133
134 std::string_view list_separator = GetListSeparator();
135 for (const BadgeClassID &class_index : class_indexes) {
136 const Badge *class_badge = GetClassBadge(class_index);
137 if (class_badge == nullptr || class_badge->name == STR_NULL) continue;
138
139 std::string s;
140 for (const BadgeID &index : badges) {
141 const Badge *badge = GetBadge(index);
142 if (badge == nullptr || badge->name == STR_NULL) continue;
143 if (badge->class_index != class_index) continue;
144 if (badge->flags.Test(BadgeFlag::NameListSkip)) continue;
145
146 if (!s.empty()) {
147 if (badge->flags.Test(BadgeFlag::NameListFirstOnly)) continue;
148 s += list_separator;
149 }
150 AppendStringInPlace(s, badge->name);
151 if (badge->flags.Test(BadgeFlag::NameListStop)) break;
152 }
153
154 if (s.empty()) continue;
155
156 r.top = DrawStringMultiLine(r, GetString(STR_BADGE_NAME_LIST, class_badge->name, std::move(s)), TC_BLACK);
157 }
158
159 return r.top;
160}
161
172void DrawBadgeColumn(Rect r, int column_group, const GUIBadgeClasses &gui_classes, std::span<const BadgeID> badges, GrfSpecFeature feature, std::optional<TimerGameCalendar::Date> introduction_date, PaletteID remap)
173{
174 bool rtl = _current_text_dir == TD_RTL;
175 for (const auto &gc : gui_classes.GetClasses()) {
176 if (gc.column_group != column_group) continue;
177 if (!gc.visible) continue;
178
179 int width = ScaleGUITrad(gc.size.width);
180 for (const BadgeID &index : badges) {
181 const Badge &badge = *GetBadge(index);
182 if (badge.class_index != gc.class_index) continue;
183
184 PalSpriteID ps = GetBadgeSprite(badge, feature, introduction_date, remap);
185 if (ps.sprite == 0) continue;
186
187 DrawSpriteIgnorePadding(ps.sprite, ps.pal, r.WithWidth(width, rtl), SA_CENTER);
188 break;
189 }
190
191 r = r.Indent(width + WidgetDimensions::scaled.hsep_normal, rtl);
192 }
193}
194
196template <class TBase, bool TEnd = true, FontSize TFs = FontSize::Normal>
197class DropDownBadges : public TBase {
198public:
199 template <typename... Args>
200 explicit DropDownBadges(const std::shared_ptr<GUIBadgeClasses> &gui_classes, std::span<const BadgeID> badges, GrfSpecFeature feature, std::optional<TimerGameCalendar::Date> introduction_date, Args &&...args) :
201 TBase(std::forward<Args>(args)...), gui_classes(gui_classes), badges(badges), feature(feature), introduction_date(introduction_date)
202 {
203 for (const auto &gc : gui_classes->GetClasses()) {
204 if (gc.column_group != 0) continue;
205 dim.width += ScaleGUITrad(gc.size.width) + WidgetDimensions::scaled.hsep_normal;
206 dim.height = std::max<uint>(dim.height, ScaleGUITrad(gc.size.height));
207 }
208
209 /* Remove trailing `hsep_normal` spacer. */
210 if (dim.width > 0) dim.width -= WidgetDimensions::scaled.hsep_normal;
211 }
212
214 void FilterText(StringFilter &string_filter) const override
215 {
216 for (const BadgeID &badge_index : this->badges) {
217 const Badge *badge = GetBadge(badge_index);
218 if (badge->name == STR_NULL) continue;
219 string_filter.AddLine(GetString(badge->name));
220 }
221 this->TBase::FilterText(string_filter);
222 }
223
224 uint Height() const override
225 {
226 return std::max<uint>(this->dim.height, this->TBase::Height());
227 }
228
229 uint Width() const override
230 {
231 if (this->dim.width == 0) return this->TBase::Width();
232 return this->dim.width + WidgetDimensions::scaled.hsep_normal + this->TBase::Width();
233 }
234
235 int OnClick(const Rect &r, const Point &pt) const override
236 {
237 if (this->dim.width == 0) {
238 return this->TBase::OnClick(r, pt);
239 } else {
240 bool rtl = TEnd ^ (_current_text_dir == TD_RTL);
241 return this->TBase::OnClick(r.Indent(this->dim.width + WidgetDimensions::scaled.hsep_normal, rtl), pt);
242 }
243 }
244
245 void Draw(const Rect &full, const Rect &r, bool sel, int click_result, Colours bg_colour) const override
246 {
247 if (this->dim.width == 0) {
248 this->TBase::Draw(full, r, sel, click_result, bg_colour);
249 } else {
250 bool rtl = TEnd ^ (_current_text_dir == TD_RTL);
251 DrawBadgeColumn(r.WithWidth(this->dim.width, rtl), 0, *this->gui_classes, this->badges, this->feature, this->introduction_date, PAL_NONE);
252 this->TBase::Draw(full, r.Indent(this->dim.width + WidgetDimensions::scaled.hsep_normal, rtl), sel, click_result, bg_colour);
253 }
254 }
255
256private:
257 std::shared_ptr<GUIBadgeClasses> gui_classes;
258
259 const std::span<const BadgeID> badges;
260 const GrfSpecFeature feature;
261 const std::optional<TimerGameCalendar::Date> introduction_date;
262
263 Dimension dim{};
264};
265
268
269std::unique_ptr<DropDownListItem> MakeDropDownListBadgeItem(const std::shared_ptr<GUIBadgeClasses> &gui_classes, std::span<const BadgeID> badges, GrfSpecFeature feature, std::optional<TimerGameCalendar::Date> introduction_date, std::string &&str, int value, bool masked, bool shaded)
270{
271 return std::make_unique<DropDownListBadgeItem>(gui_classes, badges, feature, introduction_date, "", std::move(str), value, masked, shaded);
272}
273
274std::unique_ptr<DropDownListItem> MakeDropDownListBadgeItem(const std::shared_ptr<GUIBadgeClasses> &gui_classes, std::span<const BadgeID> badges, GrfSpecFeature feature, std::optional<TimerGameCalendar::Date> introduction_date, Money cost, std::string &&str, int value, bool masked, bool shaded)
275{
276 return std::make_unique<DropDownListBadgeItem>(gui_classes, badges, feature, introduction_date, GetString(STR_JUST_CURRENCY_SHORT, cost), std::move(str), value, masked, shaded);
277}
278
279std::unique_ptr<DropDownListItem> MakeDropDownListBadgeIconItem(const std::shared_ptr<GUIBadgeClasses> &gui_classes, std::span<const BadgeID> badges, GrfSpecFeature feature, std::optional<TimerGameCalendar::Date> introduction_date, Money cost, const Dimension &dim, SpriteID sprite, PaletteID palette, std::string &&str, int value, bool masked, bool shaded)
280{
281 return std::make_unique<DropDownListBadgeIconItem>(gui_classes, badges, feature, introduction_date, GetString(STR_JUST_CURRENCY_SHORT, cost), dim, sprite, palette, std::move(str), value, masked, shaded);
282}
283
287template <class TBase, bool TEnd = true, FontSize TFs = FontSize::Normal>
288class DropDownMover : public TBase {
289public:
290 template <typename... Args>
291 explicit DropDownMover(int click_up, int click_down, Colours button_colour, Args &&...args)
292 : TBase(std::forward<Args>(args)...), click_up(click_up), click_down(click_down), button_colour(button_colour)
293 {
294 }
295
296 uint Height() const override
297 {
298 return std::max<uint>(SETTING_BUTTON_HEIGHT, this->TBase::Height());
299 }
300
301 uint Width() const override
302 {
303 return SETTING_BUTTON_WIDTH + WidgetDimensions::scaled.hsep_wide + this->TBase::Width();
304 }
305
306 int OnClick(const Rect &r, const Point &pt) const override
307 {
308 bool rtl = (_current_text_dir == TD_RTL);
309 int w = SETTING_BUTTON_WIDTH;
310
311 Rect br = r.WithWidth(w, TEnd ^ rtl).CentreToHeight(SETTING_BUTTON_HEIGHT);
312 if (br.WithWidth(w / 2, rtl).Contains(pt)) return this->click_up;
313 if (br.WithWidth(w / 2, !rtl).Contains(pt)) return this->click_down;
314
315 return this->TBase::OnClick(r.Indent(w + WidgetDimensions::scaled.hsep_wide, TEnd ^ rtl), pt);
316 }
317
318 void Draw(const Rect &full, const Rect &r, bool sel, int click_result, Colours bg_colour) const override
319 {
320 bool rtl = (_current_text_dir == TD_RTL);
321 int w = SETTING_BUTTON_WIDTH;
322
323 int state = 0;
324 if (sel && click_result != 0) {
325 if (click_result == this->click_up) state = 1;
326 if (click_result == this->click_down) state = 2;
327 }
328
329 Rect br = r.WithWidth(w, TEnd ^ rtl).CentreToHeight(SETTING_BUTTON_HEIGHT);
330 DrawUpDownButtons(br.left, br.top, this->button_colour, state, this->click_up != 0, this->click_down != 0);
331
332 this->TBase::Draw(full, r.Indent(w + WidgetDimensions::scaled.hsep_wide, TEnd ^ rtl), sel, click_result, bg_colour);
333 }
334
335private:
339};
340
341using DropDownListToggleMoverItem = DropDownMover<DropDownToggle<DropDownString<DropDownListItem>>>;
342using DropDownListToggleItem = DropDownToggle<DropDownString<DropDownListItem>>;
343
344enum BadgeClick : int {
345 BADGE_CLICK_NONE,
346 BADGE_CLICK_MOVE_UP,
347 BADGE_CLICK_MOVE_DOWN,
348 BADGE_CLICK_TOGGLE_ICON,
349 BADGE_CLICK_TOGGLE_FILTER,
350};
351
352DropDownList BuildBadgeClassConfigurationList(const GUIBadgeClasses &gui_classes, uint columns, std::span<const StringID> column_separators, Colours bg_colour)
353{
354 DropDownList list;
355
356 list.push_back(MakeDropDownListStringItem(STR_BADGE_CONFIG_RESET, INT_MAX));
357 if (gui_classes.GetClasses().empty()) return list;
358 list.push_back(MakeDropDownListDividerItem());
359 list.push_back(std::make_unique<DropDownUnselectable<DropDownListStringItem>>(GetString(STR_BADGE_CONFIG_ICONS), -1));
360
361 const BadgeClassID front = gui_classes.GetClasses().front().class_index;
362 const BadgeClassID back = gui_classes.GetClasses().back().class_index;
363
364 for (uint i = 0; i < columns; ++i) {
365 for (const auto &gc : gui_classes.GetClasses()) {
366 if (gc.column_group != i) continue;
367 if (gc.size.width == 0) continue;
368
369 bool first = (i == 0 && gc.class_index == front);
370 bool last = (i == columns - 1 && gc.class_index == back);
371 list.push_back(std::make_unique<DropDownListToggleMoverItem>(first ? 0 : BADGE_CLICK_MOVE_UP, last ? 0 : BADGE_CLICK_MOVE_DOWN, Colours::Yellow, gc.visible, BADGE_CLICK_TOGGLE_ICON, Colours::Yellow, bg_colour, GetString(GetClassBadge(gc.class_index)->name), gc.class_index.base()));
372 }
373
374 if (i >= column_separators.size()) continue;
375
376 if (column_separators[i] == STR_NULL) {
377 list.push_back(MakeDropDownListDividerItem());
378 } else {
379 list.push_back(MakeDropDownListStringItem(column_separators[i], INT_MIN + i, false, true));
380 }
381 }
382
383 list.push_back(MakeDropDownListDividerItem());
384 list.push_back(std::make_unique<DropDownUnselectable<DropDownListStringItem>>(GetString(STR_BADGE_CONFIG_FILTERS), -1));
385
386 for (const BadgeClassID &badge_class_index : gui_classes.Classes()) {
387 const Badge *badge = GetClassBadge(badge_class_index);
388 if (!badge->flags.Test(BadgeFlag::HasText)) continue;
389
390 const auto [config, _] = GetBadgeClassConfigItem(gui_classes.GetFeature(), badge->label);
391 list.push_back(std::make_unique<DropDownListToggleItem>(config.show_filter, BADGE_CLICK_TOGGLE_FILTER, Colours::Yellow, bg_colour, GetString(badge->name), badge_class_index.base()));
392 }
393
394 return list;
395}
396
404static void BadgeClassToggleVisibility(GrfSpecFeature feature, Badge &class_badge, int click_result, BadgeFilterChoices &choices)
405{
406 auto config = GetBadgeClassConfiguration(feature);
407 auto it = std::ranges::find(config, class_badge.label, &BadgeClassConfigItem::label);
408 if (it == std::end(config)) return;
409
410 if (click_result == BADGE_CLICK_TOGGLE_ICON) it->show_icon = !it->show_icon;
411 if (click_result == BADGE_CLICK_TOGGLE_FILTER) {
412 it->show_filter = !it->show_filter;
413 if (!it->show_filter) ResetBadgeFilter(choices, class_badge.class_index);
414 }
415}
416
422static void BadgeClassMovePrevious(GrfSpecFeature feature, Badge &class_badge)
423{
424 GUIBadgeClasses gui_classes(feature);
425 if (gui_classes.GetClasses().empty()) return;
426
427 auto config = GetBadgeClassConfiguration(feature);
428 auto it = std::ranges::find(config, class_badge.label, &BadgeClassConfigItem::label);
429 if (it == std::end(config)) return;
430
431 auto pos_cur = std::ranges::find(gui_classes.GetClasses(), class_badge.class_index, &GUIBadgeClasses::Element::class_index);
432 if (pos_cur == std::begin(gui_classes.GetClasses())) {
433 if (it->column > 0) --it->column;
434 return;
435 }
436
437 auto pos_prev = std::ranges::find(config, std::prev(pos_cur)->label, &BadgeClassConfigItem::label);
438 if (it->column > pos_prev->column) {
439 --it->column;
440 } else {
441 /* Rotate elements right so that it is placed before pos_prev, maintaining order of non-visible elements. */
442 std::rotate(pos_prev, it, std::next(it));
443 }
444}
445
452static void BadgeClassMoveNext(GrfSpecFeature feature, Badge &class_badge, uint columns)
453{
454 GUIBadgeClasses gui_classes(feature);
455 if (gui_classes.GetClasses().empty()) return;
456
457 auto config = GetBadgeClassConfiguration(feature);
458 auto it = std::ranges::find(config, class_badge.label, &BadgeClassConfigItem::label);
459 if (it == std::end(config)) return;
460
461 auto pos_cur = std::ranges::find(gui_classes.GetClasses(), class_badge.class_index, &GUIBadgeClasses::Element::class_index);
462 if (std::next(pos_cur) == std::end(gui_classes.GetClasses())) {
463 if (it->column < columns - 1) ++it->column;
464 return;
465 }
466
467 auto pos_next = std::ranges::find(config, std::next(pos_cur)->label, &BadgeClassConfigItem::label);
468 if (it->column < pos_next->column) {
469 ++it->column;
470 } else {
471 /* Rotate elements left so that it is placed after pos_next, maintaining order of non-visible elements. */
472 std::rotate(it, std::next(it), std::next(pos_next));
473 }
474}
475
485bool HandleBadgeConfigurationDropDownClick(GrfSpecFeature feature, uint columns, int result, int click_result, BadgeFilterChoices &choices)
486{
487 if (result == INT_MAX) {
489 return true;
490 }
491
492 Badge *class_badge = GetClassBadge(static_cast<BadgeClassID>(result));
493 if (class_badge == nullptr) return false;
494
495 switch (click_result) {
496 case BADGE_CLICK_MOVE_DOWN: // Move down button.
497 BadgeClassMoveNext(feature, *class_badge, columns);
498 break;
499 case BADGE_CLICK_MOVE_UP: // Move up button.
500 BadgeClassMovePrevious(feature, *class_badge);
501 break;
502 case BADGE_CLICK_TOGGLE_ICON:
503 case BADGE_CLICK_TOGGLE_FILTER:
504 BadgeClassToggleVisibility(feature, *class_badge, click_result, choices);
505 break;
506 default:
507 break;
508 }
509
510 return true;
511}
512
513NWidgetBadgeFilter::NWidgetBadgeFilter(Colours colour, WidgetID index, GrfSpecFeature feature, BadgeClassID badge_class)
514 : NWidgetLeaf(WWT_DROPDOWN, colour, index, WidgetData{ .string = STR_JUST_STRING }, STR_NULL)
515 , feature(feature), badge_class(badge_class)
516{
517 this->SetFill(1, 0);
518 this->SetResize(1, 0);
519}
520
521std::string NWidgetBadgeFilter::GetStringParameter(const BadgeFilterChoices &choices) const
522{
523 auto it = choices.find(this->badge_class);
524 if (it == std::end(choices)) {
525 return ::GetString(STR_BADGE_FILTER_ANY_LABEL, GetClassBadge(this->badge_class)->name);
526 }
527
528 return ::GetString(GetBadge(it->second)->name);
529}
530
537{
538 DropDownList list;
539
540 /* Add item for disabling filtering. */
541 list.push_back(MakeDropDownListStringItem(::GetString(STR_BADGE_FILTER_ANY_LABEL, GetClassBadge(this->badge_class)->name), -1));
542 list.push_back(MakeDropDownListDividerItem());
543
544 /* Add badges */
545 Dimension d = GetBadgeMaximalDimension(this->badge_class, this->feature);
546 d.width = ScaleGUITrad(d.width);
547 d.height = ScaleGUITrad(d.height);
548
549 auto start = list.size();
550
551 const auto *bc = GetClassBadge(this->badge_class);
552
553 for (const Badge &badge : GetBadges()) {
554 if (badge.class_index != this->badge_class) continue;
555 if (badge.index == bc->index) continue;
556 if (badge.name == STR_NULL) continue;
557 if (!badge.features.Test(this->feature)) continue;
558
559 PalSpriteID ps = GetBadgeSprite(badge, this->feature, std::nullopt, palette);
560 if (ps.sprite == 0) {
561 list.push_back(MakeDropDownListStringItem(badge.name, badge.index.base()));
562 } else {
563 list.push_back(MakeDropDownListIconItem(d, ps.sprite, ps.pal, badge.name, badge.index.base()));
564 }
565 }
566
567 std::sort(std::begin(list) + start, std::end(list), DropDownListStringItem::NatSortFunc);
568
569 return list;
570}
571
581std::pair<WidgetID, WidgetID> AddBadgeDropdownFilters(Window *window, WidgetID container_id, WidgetID widget, Colours colour, GrfSpecFeature feature)
582{
583 auto container = window->GetWidget<NWidgetContainer>(container_id);
584 container->Clear(window);
585 WidgetID first = ++widget;
586
587 /* Get list of classes used by feature. */
588 UsedBadgeClasses used(feature);
589
590 for (BadgeClassID class_index : used.Classes()) {
591 const auto [config, _] = GetBadgeClassConfigItem(feature, GetClassBadge(class_index)->label);
592 if (!config.show_filter) continue;
593
594 container->Add(std::make_unique<NWidgetBadgeFilter>(colour, widget, feature, class_index));
595 ++widget;
596 }
597
598 return {first, widget};
599}
600
606void ResetBadgeFilter(BadgeFilterChoices &choices, BadgeClassID badge_class_index)
607{
608 choices.erase(badge_class_index);
609}
610
617void SetBadgeFilter(BadgeFilterChoices &choices, BadgeID badge_index)
618{
619 const Badge *badge = GetBadge(badge_index);
620 assert(badge != nullptr);
621
622 choices[badge->class_index] = badge_index;
623}
std::string label
Class label.
BadgeClassID class_index
Index of class this badge belongs to.
std::string label
Label of badge.
BadgeID index
Index assigned to badge.
BadgeFlags flags
Display flags.
GrfSpecFeatures features
Bitmask of which features use this badge.
StringID name
Short name.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
Drop down element that draws a list of badges.
void FilterText(StringFilter &string_filter) const override
Add text from this dropdown item to a string filter.
Drop down component that shows extra buttons to indicate that the item can be moved up or down.
int click_down
Click result for down button. Button is inactive if 0.
Colours button_colour
Colour of buttons.
int click_up
Click result for up button. Button is inactive if 0.
static bool NatSortFunc(std::unique_ptr< const DropDownListItem > const &first, std::unique_ptr< const DropDownListItem > const &second)
Drop down boolean toggle component.
Drop down component that makes the item unselectable.
Flat set implementation that uses a sorted vector for storage.
std::pair< const_iterator, bool > insert(const Tkey &key)
Insert a key into the set, if it does not already exist.
uint GetTotalColumnsWidth() const
Get total width of all columns.
BadgeClassID badge_class
Badge class of this dropdown.
DropDownList GetDropDownList(PaletteID palette=PAL_NONE) const
Get the drop down list of badges for this filter.
Baseclass for container widgets.
void Clear(Window *parent_window)
Clears the container, deleting all widgets that were contained.
StringID GetString() const
Get the string that has been set for this nested widget.
Definition widget.cpp:1282
Leaf widget.
Utility class to create a list of badge classes used by a feature.
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:30
int hsep_normal
Normal horizontal spacing.
Definition window_gui.h:61
std::unique_ptr< DropDownListItem > MakeDropDownListDividerItem()
Creates new DropDownListDividerItem.
Definition dropdown.cpp:36
std::unique_ptr< DropDownListItem > MakeDropDownListIconItem(SpriteID sprite, PaletteID palette, StringID str, int value, bool masked, bool shaded)
Creates new DropDownListIconItem.
Definition dropdown.cpp:70
std::unique_ptr< DropDownListItem > MakeDropDownListStringItem(StringID str, int value, bool masked, bool shaded)
Creates new DropDownListStringItem.
Definition dropdown.cpp:49
Common drop down list components.
Functions related to the drop down widget.
Types related to the drop down widget.
std::vector< std::unique_ptr< const DropDownListItem > > DropDownList
A drop down list is a collection of drop down list items.
Flat set container implementation.
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:788
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
@ Normal
The most basic (normal) sprite.
Definition gfx_type.h:358
@ Small
Index of the small font in the font tables.
Definition gfx_type.h:250
@ SA_CENTER
Center both horizontally and vertically.
Definition gfx_type.h:398
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:18
Colours
One of 16 base colours used for companies and windows/widgets.
Definition gfx_type.h:283
@ Yellow
Yellow.
Definition gfx_type.h:288
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
#define Rect
Macro that prevents name conflicts between included headers.
#define Point
Macro that prevents name conflicts between included headers.
Base for the NewGRF implementation.
GrfSpecFeature
Definition newgrf.h:72
Badge * GetBadge(BadgeID index)
Get a badge if it exists.
std::span< const Badge > GetBadges()
Get a read-only view of badges.
PalSpriteID GetBadgeSprite(const Badge &badge, GrfSpecFeature feature, std::optional< TimerGameCalendar::Date > introduction_date, PaletteID remap)
Get sprite for the given badge.
Badge * GetClassBadge(BadgeClassID class_index)
Get the badge for a badge class index.
Functions related to NewGRF badges.
void ResetBadgeClassConfiguration(GrfSpecFeature feature)
Reset badge class configuration for a feature.
std::pair< const BadgeClassConfigItem &, int > GetBadgeClassConfigItem(GrfSpecFeature feature, std::string_view label)
Get configuration for a badge class.
std::span< BadgeClassConfigItem > GetBadgeClassConfiguration(GrfSpecFeature feature)
Get the badge user configuration for a feature.
Functions related to NewGRF badge configuration.
int DrawBadgeNameList(Rect r, std::span< const BadgeID > badges, GrfSpecFeature)
Draw names for a list of badge labels.
static void BadgeClassMoveNext(GrfSpecFeature feature, Badge &class_badge, uint columns)
Move the badge class to the next position.
void DrawBadgeColumn(Rect r, int column_group, const GUIBadgeClasses &gui_classes, std::span< const BadgeID > badges, GrfSpecFeature feature, std::optional< TimerGameCalendar::Date > introduction_date, PaletteID remap)
Draw a badge column group.
static void BadgeClassToggleVisibility(GrfSpecFeature feature, Badge &class_badge, int click_result, BadgeFilterChoices &choices)
Toggle badge class visibility.
static constexpr uint MAX_BADGE_HEIGHT
Maximal height of a badge sprite.
static constexpr uint MAX_BADGE_WIDTH
Maximal width.
std::pair< WidgetID, WidgetID > AddBadgeDropdownFilters(Window *window, WidgetID container_id, WidgetID widget, Colours colour, GrfSpecFeature feature)
Add badge drop down filter widgets.
bool HandleBadgeConfigurationDropDownClick(GrfSpecFeature feature, uint columns, int result, int click_result, BadgeFilterChoices &choices)
Handle the badge configuration drop down selection.
static Dimension GetBadgeMaximalDimension(BadgeClassID class_index, GrfSpecFeature feature)
Get the largest badge size (within limits) for a badge class.
void SetBadgeFilter(BadgeFilterChoices &choices, BadgeID badge_index)
Set badge filter choice for a class.
static void BadgeClassMovePrevious(GrfSpecFeature feature, Badge &class_badge)
Move the badge class to the previous position.
void ResetBadgeFilter(BadgeFilterChoices &choices, BadgeClassID badge_class_index)
Reset badge filter choice for a class.
GUI functions related to NewGRF badges.
Types related to NewGRF badges.
@ NameListStop
Stop adding names to the name list after this badge.
@ NameListFirstOnly
Don't add this name to the name list if not first.
@ HasText
Internal flag set if the badge has text.
@ NameListSkip
Don't show name in name list at all.
A number of safeguards to prevent using unsafe methods.
void DrawUpDownButtons(int x, int y, Colours button_colour, uint8_t state, bool clickable_up, bool clickable_down)
Draw [^][v] buttons.
Functions for setting GUIs.
#define SETTING_BUTTON_WIDTH
Width of setting buttons.
#define SETTING_BUTTON_HEIGHT
Height of setting buttons.
Functions to cache sprites in memory.
Definition of base types and functions in a cross-platform compatible way.
std::string_view GetListSeparator()
Get the list separator string for the current language.
Definition strings.cpp:299
void AppendStringInPlace(std::string &result, StringID string)
Resolve the given StringID and append in place into an existing std::string with formatting but no pa...
Definition strings.cpp:434
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:424
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.
Dimensions (a width and height) of a rectangle in 2D.
uint sort_order
Order of element.
std::string_view label
Class label (string owned by the class badge).
BadgeClassID class_index
Badge class index.
uint8_t column_group
Column group in UI. 0 = left, 1 = centre, 2 = right.
Combination of a palette sprite and a 'real' sprite.
Definition gfx_type.h:22
SpriteID sprite
The 'real' sprite.
Definition gfx_type.h:23
PaletteID pal
The palette (use PAL_NONE) if not needed).
Definition gfx_type.h:24
Specification of a rectangle with absolute coordinates of all edges.
Rect WithWidth(int width, bool end) const
Copy Rect and set its width.
Rect Indent(int indent, bool end) const
Copy Rect and indent it from its position.
Rect CentreToHeight(int height) const
Centre a vertical dimension within this Rect.
bool Contains(const Point &pt) const
Test if a point falls inside this Rect.
Data structure describing a sprite.
uint16_t width
Width of the sprite.
String filter and state.
Container with the data associated to a single widget.
Data structure for an opened window.
Definition window_gui.h:274
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:990
int16_t Height
Fixed point type for heights.
Definition tgp.cpp:152
Definition of the game-calendar-timer.
static RectPadding ScaleGUITrad(const RectPadding &r)
Scale a RectPadding to GUI zoom level.
Definition widget.cpp:49
@ WWT_DROPDOWN
Drop down list.
Definition widget_type.h:61
Functions, definitions and such used only by the GUI.
Types related to windows.
int WidgetID
Widget ID.
Definition window_type.h:21
Functions related to zooming.
int UnScaleByZoom(int value, ZoomLevel zoom)
Scale by zoom level, usually shift right (when zoom > ZoomLevel::Min) When shifting right,...
Definition zoom_func.h:34
@ Normal
The normal zoom level.
Definition zoom_type.h:26