From 394adb654efa9da77202cd53d3cea280592fe6cc Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Fri, 18 Apr 2025 17:20:31 +0100 Subject: [PATCH] Codechange: Move GUI parts of badges to a separate file. (#14023) --- src/CMakeLists.txt | 2 + src/airport_gui.cpp | 2 +- src/build_vehicle_gui.cpp | 1 + src/engine_gui.h | 2 +- src/industry_gui.cpp | 1 + src/newgrf_badge.cpp | 257 +++----------------------------------- src/newgrf_badge.h | 52 +++----- src/newgrf_badge_gui.cpp | 241 +++++++++++++++++++++++++++++++++++ src/newgrf_badge_gui.h | 55 ++++++++ src/object_gui.cpp | 2 +- src/picker_gui.cpp | 1 + src/picker_gui.h | 1 + src/rail_gui.cpp | 1 + src/road_gui.cpp | 2 +- 14 files changed, 344 insertions(+), 276 deletions(-) create mode 100644 src/newgrf_badge_gui.cpp create mode 100644 src/newgrf_badge_gui.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3e7160c4e2..591bc6f4ba 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -279,6 +279,8 @@ add_files( newgrf_animation_type.h newgrf_badge.cpp newgrf_badge.h + newgrf_badge_gui.cpp + newgrf_badge_gui.h newgrf_badge_type.h newgrf_callbacks.h newgrf_canal.cpp diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index 5b2464e975..0d2b0b0b81 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -21,7 +21,7 @@ #include "company_base.h" #include "station_type.h" #include "newgrf_airport.h" -#include "newgrf_badge.h" +#include "newgrf_badge_gui.h" #include "newgrf_callbacks.h" #include "dropdown_type.h" #include "dropdown_func.h" diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index e2a5c7cdf0..f59ec75f33 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -18,6 +18,7 @@ #include "company_func.h" #include "vehicle_gui.h" #include "newgrf_badge.h" +#include "newgrf_badge_gui.h" #include "newgrf_engine.h" #include "newgrf_text.h" #include "group.h" diff --git a/src/engine_gui.h b/src/engine_gui.h index 5eb9816b09..12d0d04d7a 100644 --- a/src/engine_gui.h +++ b/src/engine_gui.h @@ -12,7 +12,7 @@ #include "engine_type.h" #include "group_type.h" -#include "newgrf_badge.h" +#include "newgrf_badge_gui.h" #include "sortlist_type.h" #include "gfx_type.h" #include "vehicle_type.h" diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index 6beb9bdaf9..f1693e265a 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -21,6 +21,7 @@ #include "town.h" #include "cheat_type.h" #include "newgrf_badge.h" +#include "newgrf_badge_gui.h" #include "newgrf_industries.h" #include "newgrf_text.h" #include "newgrf_debug.h" diff --git a/src/newgrf_badge.cpp b/src/newgrf_badge.cpp index 0ed9cced62..08d9bb641a 100644 --- a/src/newgrf_badge.cpp +++ b/src/newgrf_badge.cpp @@ -8,7 +8,6 @@ /** @file newgrf_badge.cpp Functionality for NewGRF badges. */ #include "stdafx.h" -#include "dropdown_type.h" #include "newgrf.h" #include "newgrf_badge.h" #include "newgrf_badge_type.h" @@ -16,13 +15,9 @@ #include "stringfilter_type.h" #include "strings_func.h" #include "timer/timer_game_calendar.h" -#include "window_gui.h" -#include "zoom_func.h" #include "table/strings.h" -#include "dropdown_common_type.h" - #include "safeguards.h" /** Separator to identify badge classes from a label. */ @@ -38,6 +33,15 @@ public: /** Static instance of badge state. */ static Badges _badges = {}; +/** + * Get a read-only view of badges. + * @return Span of badges. + */ +std::span GetBadges() +{ + return _badges.specs; +} + /** * Assign a BadgeClassID to the given badge. * @param index Badge ID of badge that should be assigned. @@ -254,16 +258,13 @@ void AppendCopyableBadgeList(std::vector &dst, std::span /** Apply features from all badges to their badge classes. */ void ApplyBadgeFeaturesToClassBadges() { - for (const Badge &badge : _badges.specs) { + for (const Badge &badge : GetBadges()) { Badge *class_badge = GetClassBadge(badge.class_index); assert(class_badge != nullptr); class_badge->features.Set(badge.features); } } -static constexpr uint MAX_BADGE_HEIGHT = 12; ///< Maximal height of a badge sprite. -static constexpr uint MAX_BADGE_WIDTH = MAX_BADGE_HEIGHT * 2; ///< Maximal width. - /** * Get sprite for the given badge. * @param badge Badge being queried. @@ -272,7 +273,7 @@ static constexpr uint MAX_BADGE_WIDTH = MAX_BADGE_HEIGHT * 2; ///< Maximal width * @param remap Palette remap to use if the flag is company-coloured. * @returns Custom sprite to draw, or \c 0 if not available. */ -static PalSpriteID GetBadgeSprite(const Badge &badge, GrfSpecFeature feature, std::optional introduction_date, PaletteID remap) +PalSpriteID GetBadgeSprite(const Badge &badge, GrfSpecFeature feature, std::optional introduction_date, PaletteID remap) { BadgeResolverObject object(badge, feature, introduction_date); const SpriteGroup *group = object.Resolve(); @@ -284,112 +285,19 @@ static PalSpriteID GetBadgeSprite(const Badge &badge, GrfSpecFeature feature, st } /** - * Get the largest badge size (within limits) for a badge class. - * @param class_index Badge class. - * @param feature Feature being used. - * @returns Largest base size of the badge class for the feature. + * Create a list of used badge classes for a feature. + * @param feature GRF feature being used. */ -static Dimension GetBadgeMaximalDimension(BadgeClassID class_index, GrfSpecFeature feature) +UsedBadgeClasses::UsedBadgeClasses(GrfSpecFeature feature) { - Dimension d = { 0, MAX_BADGE_HEIGHT }; + for (auto index : _badges.classes) { + Badge *class_badge = GetBadge(index); + if (!class_badge->features.Test(feature)) continue; - for (const auto &badge : _badges.specs) { - if (badge.class_index != class_index) continue; - - PalSpriteID ps = GetBadgeSprite(badge, feature, std::nullopt, PAL_NONE); - if (ps.sprite == 0) continue; - - d.width = std::max(d.width, GetSpriteSize(ps.sprite, nullptr, ZOOM_LVL_NORMAL).width); - if (d.width > MAX_BADGE_WIDTH) break; + this->classes.push_back(class_badge->class_index); } - d.width = std::min(d.width, MAX_BADGE_WIDTH); - return d; -} - -/** Utility class to create a list of badge classes used by a feature. */ -class UsedBadgeClasses { -public: - /** - * Create a list of used badge classes for a feature. - * @param feature GRF feature being used. - */ - explicit UsedBadgeClasses(GrfSpecFeature feature) - { - for (auto index : _badges.classes) { - Badge *class_badge = GetBadge(index); - if (!class_badge->features.Test(feature)) continue; - - this->classes.push_back(class_badge->class_index); - } - - std::ranges::sort(this->classes, [](const BadgeClassID &a, const BadgeClassID &b) - { - return GetClassBadge(a)->label < GetClassBadge(b)->label; - }); - } - - std::span Classes() const { return this->classes; } - -private: - std::vector classes; ///< List of badge classes. -}; - -static bool operator<(const GUIBadgeClasses::Element &a, const GUIBadgeClasses::Element &b) -{ - if (a.column_group != b.column_group) return a.column_group < b.column_group; - if (a.sort_order != b.sort_order) return a.sort_order < b.sort_order; - return a.label < b.label; -} - -/** - * Construct of list of badge classes and column groups to display. - * @param feature feature being used. - */ -GUIBadgeClasses::GUIBadgeClasses(GrfSpecFeature feature) -{ - /* Get list of classes used by feature. */ - UsedBadgeClasses used(feature); - - uint max_column = 0; - for (BadgeClassID class_index : used.Classes()) { - const Badge *class_badge = GetClassBadge(class_index); - if (class_badge->name == STR_NULL) continue; - - Dimension size = GetBadgeMaximalDimension(class_index, feature); - if (size.width == 0) continue; - - uint8_t column = 0; - bool visible = true; - uint sort_order = UINT_MAX; - - this->gui_classes.emplace_back(class_index, column, visible, sort_order, size, class_badge->label); - if (visible) max_column = std::max(max_column, column); - } - - std::sort(std::begin(this->gui_classes), std::end(this->gui_classes)); - - /* Determine total width of visible badge columns. */ - this->column_widths.resize(max_column + 1); - for (const auto &el : this->gui_classes) { - if (!el.visible) continue; - this->column_widths[el.column_group] += ScaleGUITrad(el.size.width) + WidgetDimensions::scaled.hsep_normal; - } - - /* Replace trailing `hsep_normal` spacer with wider `hsep_wide` spacer. */ - for (uint &badge_width : this->column_widths) { - if (badge_width == 0) continue; - badge_width = badge_width - WidgetDimensions::scaled.hsep_normal + WidgetDimensions::scaled.hsep_wide; - } -} - -/** - * Get total width of all columns. - * @returns sum of all column widths. - */ -uint GUIBadgeClasses::GetTotalColumnsWidth() const -{ - return std::accumulate(std::begin(this->column_widths), std::end(this->column_widths), 0U); + std::ranges::sort(this->classes, [](const BadgeClassID &a, const BadgeClassID &b) { return GetClassBadge(a)->label < GetClassBadge(b)->label; }); } /** @@ -403,7 +311,7 @@ BadgeTextFilter::BadgeTextFilter(StringFilter &filter, GrfSpecFeature feature) if (filter.IsEmpty()) return; /* Pre-build list of badges that match by string. */ - for (const auto &badge : _badges.specs) { + for (const auto &badge : GetBadges()) { if (badge.name == STR_NULL) continue; if (!badge.features.Test(feature)) continue; @@ -427,128 +335,3 @@ bool BadgeTextFilter::Filter(std::span badges) const { return std::ranges::any_of(badges, [this](const BadgeID &badge) { return std::ranges::binary_search(this->badges, badge); }); } - -/** - * Draw names for a list of badge labels. - * @param r Rect to draw in. - * @param badges List of badges. - * @param feature GRF feature being used. - * @returns Vertical position after drawing is complete. - */ -int DrawBadgeNameList(Rect r, std::span badges, GrfSpecFeature) -{ - if (badges.empty()) return r.top; - - std::set class_indexes; - for (const BadgeID &index : badges) class_indexes.insert(GetBadge(index)->class_index); - - std::string_view list_separator = GetListSeparator(); - for (const BadgeClassID &class_index : class_indexes) { - const Badge *class_badge = GetClassBadge(class_index); - if (class_badge == nullptr || class_badge->name == STR_NULL) continue; - - std::string s; - for (const BadgeID &index : badges) { - const Badge *badge = GetBadge(index); - if (badge == nullptr || badge->name == STR_NULL) continue; - if (badge->class_index != class_index) continue; - - if (!s.empty()) { - if (badge->flags.Test(BadgeFlag::NameListFirstOnly)) continue; - s += list_separator; - } - AppendStringInPlace(s, badge->name); - if (badge->flags.Test(BadgeFlag::NameListStop)) break; - } - - if (s.empty()) continue; - - r.top = DrawStringMultiLine(r, GetString(STR_BADGE_NAME_LIST, class_badge->name, std::move(s)), TC_BLACK); - } - - return r.top; -} - -/** - * Draw a badge column group. - * @param r rect to draw within. - * @param column_group column to draw. - * @param gui_classes gui badge classes. - * @param badges badges to draw. - * @param feature feature being used. - * @param introduction_date introduction date of item. - * @param remap palette remap to for company-coloured badges. - */ -void DrawBadgeColumn(Rect r, int column_group, const GUIBadgeClasses &gui_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, PaletteID remap) -{ - bool rtl = _current_text_dir == TD_RTL; - for (const auto &gc : gui_classes.GetClasses()) { - if (gc.column_group != column_group) continue; - if (!gc.visible) continue; - - int width = ScaleGUITrad(gc.size.width); - for (const BadgeID &index : badges) { - const Badge &badge = *GetBadge(index); - if (badge.class_index != gc.class_index) continue; - - PalSpriteID ps = GetBadgeSprite(badge, feature, introduction_date, remap); - if (ps.sprite == 0) continue; - - DrawSpriteIgnorePadding(ps.sprite, ps.pal, r.WithWidth(width, rtl), SA_CENTER); - break; - } - - r = r.Indent(width + WidgetDimensions::scaled.hsep_normal, rtl); - } -} - -/** Drop down element that draws a list of badges. */ -template -class DropDownBadges : public TBase { -public: - template - explicit DropDownBadges(const std::shared_ptr &gui_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, Args&&... args) - : TBase(std::forward(args)...), gui_classes(gui_classes), badges(badges), feature(feature), introduction_date(introduction_date) - { - for (const auto &gc : gui_classes->GetClasses()) { - if (gc.column_group != 0) continue; - dim.width += gc.size.width + WidgetDimensions::scaled.hsep_normal; - dim.height = std::max(dim.height, gc.size.height); - } - } - - uint Height() const override { return std::max(this->dim.height, this->TBase::Height()); } - uint Width() const override { return this->dim.width + WidgetDimensions::scaled.hsep_wide + this->TBase::Width(); } - - void Draw(const Rect &full, const Rect &r, bool sel, Colours bg_colour) const override - { - bool rtl = TEnd ^ (_current_text_dir == TD_RTL); - - DrawBadgeColumn(r.WithWidth(this->dim.width, rtl), 0, *this->gui_classes, this->badges, this->feature, this->introduction_date, PAL_NONE); - - this->TBase::Draw(full, r.Indent(this->dim.width + WidgetDimensions::scaled.hsep_wide, rtl), sel, bg_colour); - } - -private: - std::shared_ptr gui_classes; - - const std::span badges; - const GrfSpecFeature feature; - const std::optional introduction_date; - - Dimension dim{}; - -}; - -using DropDownListBadgeItem = DropDownBadges; -using DropDownListBadgeIconItem = DropDownBadges; - -std::unique_ptr MakeDropDownListBadgeItem(const std::shared_ptr &gui_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, std::string &&str, int value, bool masked, bool shaded) -{ - return std::make_unique(gui_classes, badges, feature, introduction_date, std::move(str), value, masked, shaded); -} - -std::unique_ptr MakeDropDownListBadgeIconItem(const std::shared_ptr &gui_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, const Dimension &dim, SpriteID sprite, PaletteID palette, std::string &&str, int value, bool masked, bool shaded) -{ - return std::make_unique(gui_classes, badges, feature, introduction_date, dim, sprite, palette, std::move(str), value, masked, shaded); -} diff --git a/src/newgrf_badge.h b/src/newgrf_badge.h index b296aa98bc..4b08d31618 100644 --- a/src/newgrf_badge.h +++ b/src/newgrf_badge.h @@ -10,7 +10,6 @@ #ifndef NEWGRF_BADGE_H #define NEWGRF_BADGE_H -#include "dropdown_type.h" #include "newgrf.h" #include "newgrf_badge_type.h" #include "newgrf_commons.h" @@ -30,6 +29,20 @@ public: Badge(std::string_view label, BadgeID index, BadgeClassID class_index) : label(label), index(index), class_index(class_index) {} }; +/** Utility class to create a list of badge classes used by a feature. */ +class UsedBadgeClasses { +public: + explicit UsedBadgeClasses(GrfSpecFeature feature); + + inline std::span Classes() const + { + return this->classes; + } + +private: + std::vector classes; ///< List of badge classes. +}; + void ResetBadges(); Badge &GetOrCreateBadge(std::string_view label); @@ -37,43 +50,15 @@ void MarkBadgeSeen(BadgeID index, GrfSpecFeature feature); void AppendCopyableBadgeList(std::vector &dst, std::span src, GrfSpecFeature feature); void ApplyBadgeFeaturesToClassBadges(); +std::span GetBadges(); Badge *GetBadge(BadgeID index); Badge *GetBadgeByLabel(std::string_view label); Badge *GetClassBadge(BadgeClassID class_index); -class GUIBadgeClasses { -public: - struct Element { - BadgeClassID class_index; ///< Badge class index. - uint8_t column_group; ///< Column group in UI. 0 = left, 1 = centre, 2 = right. - bool visible; ///< Whether this element is visible. - uint sort_order; ///< Order of element. - Dimension size; ///< Maximal size of this element. - std::string_view label; ///< Class label (string owned by the class badge) - - constexpr Element(BadgeClassID class_index, uint8_t column_group, bool visible, uint sort_order, Dimension size, std::string_view label) : - class_index(class_index), column_group(column_group), visible(visible), sort_order(sort_order), size(size), label(label) {} - }; - - GUIBadgeClasses() = default; - explicit GUIBadgeClasses(GrfSpecFeature feature); - - inline std::span GetClasses() const { return this->gui_classes; } - - inline std::span GetColumnWidths() const { return this->column_widths; } - - uint GetTotalColumnsWidth() const; - -private: - std::vector gui_classes{}; - std::vector column_widths{}; -}; - -int DrawBadgeNameList(Rect r, std::span badges, GrfSpecFeature feature); -void DrawBadgeColumn(Rect r, int column_group, const GUIBadgeClasses &gui_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, PaletteID remap); - uint32_t GetBadgeVariableResult(const struct GRFFile &grffile, std::span badges, uint32_t parameter); +PalSpriteID GetBadgeSprite(const Badge &badge, GrfSpecFeature feature, std::optional introduction_date, PaletteID remap); + class BadgeTextFilter { public: BadgeTextFilter(struct StringFilter &filter, GrfSpecFeature feature); @@ -83,7 +68,4 @@ private: std::vector badges{}; }; -std::unique_ptr MakeDropDownListBadgeItem(const std::shared_ptr &gui_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, std::string &&str, int value, bool masked = false, bool shaded = false); -std::unique_ptr MakeDropDownListBadgeIconItem(const std::shared_ptr &gui_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, const Dimension &dim, SpriteID sprite, PaletteID palette, std::string &&str, int value, bool masked = false, bool shaded = false); - #endif /* NEWGRF_BADGE_H */ diff --git a/src/newgrf_badge_gui.cpp b/src/newgrf_badge_gui.cpp new file mode 100644 index 0000000000..dfe288219c --- /dev/null +++ b/src/newgrf_badge_gui.cpp @@ -0,0 +1,241 @@ +/* + * This file is part of OpenTTD. + * 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. + * 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. + * 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 . + */ + +/** @file newgrf_badge.cpp Functionality for NewGRF badges. */ + +#include "stdafx.h" + +#include "dropdown_type.h" +#include "newgrf.h" +#include "newgrf_badge.h" +#include "newgrf_badge_gui.h" +#include "newgrf_badge_type.h" +#include "strings_func.h" +#include "timer/timer_game_calendar.h" +#include "window_gui.h" +#include "zoom_func.h" + +#include "table/strings.h" + +#include "dropdown_common_type.h" + +#include "safeguards.h" + +static constexpr uint MAX_BADGE_HEIGHT = 12; ///< Maximal height of a badge sprite. +static constexpr uint MAX_BADGE_WIDTH = MAX_BADGE_HEIGHT * 2; ///< Maximal width. + +/** + * Get the largest badge size (within limits) for a badge class. + * @param class_index Badge class. + * @param feature Feature being used. + * @returns Largest base size of the badge class for the feature. + */ +static Dimension GetBadgeMaximalDimension(BadgeClassID class_index, GrfSpecFeature feature) +{ + Dimension d = {0, MAX_BADGE_HEIGHT}; + + for (const auto &badge : GetBadges()) { + if (badge.class_index != class_index) continue; + + PalSpriteID ps = GetBadgeSprite(badge, feature, std::nullopt, PAL_NONE); + if (ps.sprite == 0) continue; + + d.width = std::max(d.width, GetSpriteSize(ps.sprite, nullptr, ZOOM_LVL_NORMAL).width); + if (d.width > MAX_BADGE_WIDTH) break; + } + + d.width = std::min(d.width, MAX_BADGE_WIDTH); + return d; +} + +static bool operator<(const GUIBadgeClasses::Element &a, const GUIBadgeClasses::Element &b) +{ + if (a.column_group != b.column_group) return a.column_group < b.column_group; + if (a.sort_order != b.sort_order) return a.sort_order < b.sort_order; + return a.label < b.label; +} + +/** + * Construct of list of badge classes and column groups to display. + * @param feature feature being used. + */ +GUIBadgeClasses::GUIBadgeClasses(GrfSpecFeature feature) +{ + /* Get list of classes used by feature. */ + UsedBadgeClasses used(feature); + + uint max_column = 0; + for (BadgeClassID class_index : used.Classes()) { + const Badge *class_badge = GetClassBadge(class_index); + if (class_badge->name == STR_NULL) continue; + + Dimension size = GetBadgeMaximalDimension(class_index, feature); + if (size.width == 0) continue; + + uint8_t column = 0; + bool visible = true; + uint sort_order = UINT_MAX; + + this->gui_classes.emplace_back(class_index, column, visible, sort_order, size, class_badge->label); + if (visible) max_column = std::max(max_column, column); + } + + std::sort(std::begin(this->gui_classes), std::end(this->gui_classes)); + + /* Determine total width of visible badge columns. */ + this->column_widths.resize(max_column + 1); + for (const auto &el : this->gui_classes) { + if (!el.visible) continue; + this->column_widths[el.column_group] += ScaleGUITrad(el.size.width) + WidgetDimensions::scaled.hsep_normal; + } + + /* Replace trailing `hsep_normal` spacer with wider `hsep_wide` spacer. */ + for (uint &badge_width : this->column_widths) { + if (badge_width == 0) continue; + badge_width = badge_width - WidgetDimensions::scaled.hsep_normal + WidgetDimensions::scaled.hsep_wide; + } +} + +/** + * Get total width of all columns. + * @returns sum of all column widths. + */ +uint GUIBadgeClasses::GetTotalColumnsWidth() const +{ + return std::accumulate(std::begin(this->column_widths), std::end(this->column_widths), 0U); +} + +/** + * Draw names for a list of badge labels. + * @param r Rect to draw in. + * @param badges List of badges. + * @param feature GRF feature being used. + * @returns Vertical position after drawing is complete. + */ +int DrawBadgeNameList(Rect r, std::span badges, GrfSpecFeature) +{ + if (badges.empty()) return r.top; + + std::set class_indexes; + for (const BadgeID &index : badges) class_indexes.insert(GetBadge(index)->class_index); + + std::string_view list_separator = GetListSeparator(); + for (const BadgeClassID &class_index : class_indexes) { + const Badge *class_badge = GetClassBadge(class_index); + if (class_badge == nullptr || class_badge->name == STR_NULL) continue; + + std::string s; + for (const BadgeID &index : badges) { + const Badge *badge = GetBadge(index); + if (badge == nullptr || badge->name == STR_NULL) continue; + if (badge->class_index != class_index) continue; + + if (!s.empty()) { + if (badge->flags.Test(BadgeFlag::NameListFirstOnly)) continue; + s += list_separator; + } + AppendStringInPlace(s, badge->name); + if (badge->flags.Test(BadgeFlag::NameListStop)) break; + } + + if (s.empty()) continue; + + r.top = DrawStringMultiLine(r, GetString(STR_BADGE_NAME_LIST, class_badge->name, std::move(s)), TC_BLACK); + } + + return r.top; +} + +/** + * Draw a badge column group. + * @param r rect to draw within. + * @param column_group column to draw. + * @param gui_classes gui badge classes. + * @param badges badges to draw. + * @param feature feature being used. + * @param introduction_date introduction date of item. + * @param remap palette remap to for company-coloured badges. + */ +void DrawBadgeColumn(Rect r, int column_group, const GUIBadgeClasses &gui_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, PaletteID remap) +{ + bool rtl = _current_text_dir == TD_RTL; + for (const auto &gc : gui_classes.GetClasses()) { + if (gc.column_group != column_group) continue; + if (!gc.visible) continue; + + int width = ScaleGUITrad(gc.size.width); + for (const BadgeID &index : badges) { + const Badge &badge = *GetBadge(index); + if (badge.class_index != gc.class_index) continue; + + PalSpriteID ps = GetBadgeSprite(badge, feature, introduction_date, remap); + if (ps.sprite == 0) continue; + + DrawSpriteIgnorePadding(ps.sprite, ps.pal, r.WithWidth(width, rtl), SA_CENTER); + break; + } + + r = r.Indent(width + WidgetDimensions::scaled.hsep_normal, rtl); + } +} + +/** Drop down element that draws a list of badges. */ +template +class DropDownBadges : public TBase { +public: + template + explicit DropDownBadges(const std::shared_ptr &gui_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, Args &&...args) : + TBase(std::forward(args)...), gui_classes(gui_classes), badges(badges), feature(feature), introduction_date(introduction_date) + { + for (const auto &gc : gui_classes->GetClasses()) { + if (gc.column_group != 0) continue; + dim.width += gc.size.width + WidgetDimensions::scaled.hsep_normal; + dim.height = std::max(dim.height, gc.size.height); + } + } + + uint Height() const override + { + return std::max(this->dim.height, this->TBase::Height()); + } + + uint Width() const override + { + return this->dim.width + WidgetDimensions::scaled.hsep_wide + this->TBase::Width(); + } + + void Draw(const Rect &full, const Rect &r, bool sel, Colours bg_colour) const override + { + bool rtl = TEnd ^ (_current_text_dir == TD_RTL); + + DrawBadgeColumn(r.WithWidth(this->dim.width, rtl), 0, *this->gui_classes, this->badges, this->feature, this->introduction_date, PAL_NONE); + + this->TBase::Draw(full, r.Indent(this->dim.width + WidgetDimensions::scaled.hsep_wide, rtl), sel, bg_colour); + } + +private: + std::shared_ptr gui_classes; + + const std::span badges; + const GrfSpecFeature feature; + const std::optional introduction_date; + + Dimension dim{}; +}; + +using DropDownListBadgeItem = DropDownBadges; +using DropDownListBadgeIconItem = DropDownBadges; + +std::unique_ptr MakeDropDownListBadgeItem(const std::shared_ptr &gui_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, std::string &&str, int value, bool masked, bool shaded) +{ + return std::make_unique(gui_classes, badges, feature, introduction_date, std::move(str), value, masked, shaded); +} + +std::unique_ptr MakeDropDownListBadgeIconItem(const std::shared_ptr &gui_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, const Dimension &dim, SpriteID sprite, PaletteID palette, std::string &&str, int value, bool masked, bool shaded) +{ + return std::make_unique(gui_classes, badges, feature, introduction_date, dim, sprite, palette, std::move(str), value, masked, shaded); +} diff --git a/src/newgrf_badge_gui.h b/src/newgrf_badge_gui.h new file mode 100644 index 0000000000..765fef751d --- /dev/null +++ b/src/newgrf_badge_gui.h @@ -0,0 +1,55 @@ +/* + * This file is part of OpenTTD. + * 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. + * 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. + * 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 . + */ + +/** @file newgrf_badge.h Functions related to NewGRF badges. */ + +#ifndef NEWGRF_BADGE_GUI_H +#define NEWGRF_BADGE_GUI_H + +#include "dropdown_type.h" +#include "newgrf.h" +#include "newgrf_badge_type.h" +#include "timer/timer_game_calendar.h" + +class GUIBadgeClasses { +public: + struct Element { + BadgeClassID class_index; ///< Badge class index. + uint8_t column_group; ///< Column group in UI. 0 = left, 1 = centre, 2 = right. + bool visible; ///< Whether this element is visible. + uint sort_order; ///< Order of element. + Dimension size; ///< Maximal size of this element. + std::string_view label; ///< Class label (string owned by the class badge) + }; + + GUIBadgeClasses() = default; + explicit GUIBadgeClasses(GrfSpecFeature feature); + + inline std::span GetClasses() const + { + return this->gui_classes; + } + + inline std::span GetColumnWidths() const + { + return this->column_widths; + } + + uint GetTotalColumnsWidth() const; + +private: + std::vector gui_classes{}; + std::vector column_widths{}; +}; + +int DrawBadgeNameList(Rect r, std::span badges, GrfSpecFeature feature); +void DrawBadgeColumn(Rect r, int column_group, const GUIBadgeClasses &gui_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, PaletteID remap); + +std::unique_ptr MakeDropDownListBadgeItem(const std::shared_ptr &gui_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, std::string &&str, int value, bool masked = false, bool shaded = false); +std::unique_ptr MakeDropDownListBadgeIconItem(const std::shared_ptr &gui_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, const Dimension &dim, SpriteID sprite, PaletteID palette, std::string &&str, int value, bool masked = false, bool shaded = false); + +#endif /* NEWGRF_BADGE_GUI_H */ diff --git a/src/object_gui.cpp b/src/object_gui.cpp index e02fa8faf0..b09ced2f23 100644 --- a/src/object_gui.cpp +++ b/src/object_gui.cpp @@ -12,7 +12,7 @@ #include "company_func.h" #include "hotkeys.h" #include "newgrf.h" -#include "newgrf_badge.h" +#include "newgrf_badge_gui.h" #include "newgrf_object.h" #include "newgrf_text.h" #include "object.h" diff --git a/src/picker_gui.cpp b/src/picker_gui.cpp index e2a116c6ff..3b6a4f224c 100644 --- a/src/picker_gui.cpp +++ b/src/picker_gui.cpp @@ -14,6 +14,7 @@ #include "hotkeys.h" #include "ini_type.h" #include "newgrf_badge.h" +#include "newgrf_badge_gui.h" #include "picker_gui.h" #include "querystring_gui.h" #include "settings_type.h" diff --git a/src/picker_gui.h b/src/picker_gui.h index dc27648185..48ba38883f 100644 --- a/src/picker_gui.h +++ b/src/picker_gui.h @@ -11,6 +11,7 @@ #define PICKER_GUI_H #include "newgrf_badge.h" +#include "newgrf_badge_gui.h" #include "querystring_gui.h" #include "sortlist_type.h" #include "stringfilter_type.h" diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 08d8b38d7f..118e70442b 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -18,6 +18,7 @@ #include "command_func.h" #include "waypoint_func.h" #include "newgrf_badge.h" +#include "newgrf_badge_gui.h" #include "newgrf_station.h" #include "company_base.h" #include "strings_func.h" diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 0eb0cec738..904a4e35b0 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -39,7 +39,7 @@ #include "waypoint_cmd.h" #include "road_cmd.h" #include "tunnelbridge_cmd.h" -#include "newgrf_badge.h" +#include "newgrf_badge_gui.h" #include "newgrf_roadstop.h" #include "picker_gui.h" #include "timer/timer.h"