From 9d2efd4c96278d5779820935670586f6b2f4fa95 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 2 May 2024 22:27:17 +0100 Subject: [PATCH] Codechange: Use callback function to set labels of slider widget marks. Slider widgets can only use a predefined list of values and strings to draw labels. This makes it difficult to vary the display by context. Instead of providing a predefined list as a std::map, use a callback function instead. This function can decide what text to display, and can call SetDParam to dynamically set up strings. --- src/lang/english.txt | 12 ++-------- src/music_gui.cpp | 4 ++-- src/settings_gui.cpp | 56 ++++++++++++++++++-------------------------- src/slider.cpp | 30 +++++++++++++++--------- src/slider_func.h | 3 ++- 5 files changed, 48 insertions(+), 57 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index 36fea5c491..df48b08dec 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -956,11 +956,7 @@ STR_GAME_OPTIONS_VOLUME :Volume STR_GAME_OPTIONS_SFX_VOLUME :Sound effects STR_GAME_OPTIONS_MUSIC_VOLUME :Music -STR_GAME_OPTIONS_VOLUME_0 :0% -STR_GAME_OPTIONS_VOLUME_25 :25% -STR_GAME_OPTIONS_VOLUME_50 :50% -STR_GAME_OPTIONS_VOLUME_75 :75% -STR_GAME_OPTIONS_VOLUME_100 :100% +STR_GAME_OPTIONS_VOLUME_MARK :{NUM}% STR_GAME_OPTIONS_CURRENCY_UNITS_FRAME :{BLACK}Currency units STR_GAME_OPTIONS_CURRENCY_UNITS_DROPDOWN_TOOLTIP :{BLACK}Currency units selection @@ -1058,11 +1054,7 @@ STR_GAME_OPTIONS_GUI_FONT_SPRITE_TOOLTIP :{BLACK}Check th STR_GAME_OPTIONS_GUI_FONT_AA :{BLACK}Anti-alias fonts STR_GAME_OPTIONS_GUI_FONT_AA_TOOLTIP :{BLACK}Check this box to anti-alias resizable fonts -STR_GAME_OPTIONS_GUI_SCALE_1X :1x -STR_GAME_OPTIONS_GUI_SCALE_2X :2x -STR_GAME_OPTIONS_GUI_SCALE_3X :3x -STR_GAME_OPTIONS_GUI_SCALE_4X :4x -STR_GAME_OPTIONS_GUI_SCALE_5X :5x +STR_GAME_OPTIONS_GUI_SCALE_MARK :{DECIMAL}x STR_GAME_OPTIONS_PARTICIPATE_SURVEY_FRAME :{BLACK}Automated survey STR_GAME_OPTIONS_PARTICIPATE_SURVEY :{BLACK}Participate in automated survey diff --git a/src/music_gui.cpp b/src/music_gui.cpp index c31bfca711..639f360ce0 100644 --- a/src/music_gui.cpp +++ b/src/music_gui.cpp @@ -775,11 +775,11 @@ struct MusicWindow : public Window { } case WID_M_MUSIC_VOL: - DrawSliderWidget(r, 0, INT8_MAX, _settings_client.music.music_vol, {}); + DrawSliderWidget(r, 0, INT8_MAX, 0, _settings_client.music.music_vol, nullptr); break; case WID_M_EFFECT_VOL: - DrawSliderWidget(r, 0, INT8_MAX, _settings_client.music.effect_vol, {}); + DrawSliderWidget(r, 0, INT8_MAX, 0, _settings_client.music.effect_vol, nullptr); break; } } diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 0ef8fb330e..889f65d7ad 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -152,37 +152,27 @@ static void AddCustomRefreshRates() std::copy(monitorRates.begin(), monitorRates.end(), std::inserter(_refresh_rates, _refresh_rates.end())); } -static const std::map _scale_labels = { - { 100, STR_GAME_OPTIONS_GUI_SCALE_1X }, - { 125, STR_NULL }, - { 150, STR_NULL }, - { 175, STR_NULL }, - { 200, STR_GAME_OPTIONS_GUI_SCALE_2X }, - { 225, STR_NULL }, - { 250, STR_NULL }, - { 275, STR_NULL }, - { 300, STR_GAME_OPTIONS_GUI_SCALE_3X }, - { 325, STR_NULL }, - { 350, STR_NULL }, - { 375, STR_NULL }, - { 400, STR_GAME_OPTIONS_GUI_SCALE_4X }, - { 425, STR_NULL }, - { 450, STR_NULL }, - { 475, STR_NULL }, - { 500, STR_GAME_OPTIONS_GUI_SCALE_5X }, -}; +static const int SCALE_NMARKS = (MAX_INTERFACE_SCALE - MIN_INTERFACE_SCALE) / 25 + 1; // Show marks at 25% increments +static const int VOLUME_NMARKS = 9; // Show 5 values and 4 empty marks. -static const std::map _volume_labels = { - { 0, STR_GAME_OPTIONS_VOLUME_0 }, - { 15, STR_NULL }, - { 31, STR_GAME_OPTIONS_VOLUME_25 }, - { 47, STR_NULL }, - { 63, STR_GAME_OPTIONS_VOLUME_50 }, - { 79, STR_NULL }, - { 95, STR_GAME_OPTIONS_VOLUME_75 }, - { 111, STR_NULL }, - { 127, STR_GAME_OPTIONS_VOLUME_100 }, -}; +static StringID ScaleMarkFunc(int, int, int value) +{ + /* Label only every 100% mark. */ + if (value % 100 != 0) return STR_NULL; + + SetDParam(0, value / 100); + SetDParam(1, 0); + return STR_GAME_OPTIONS_GUI_SCALE_MARK; +} + +static StringID VolumeMarkFunc(int, int mark, int value) +{ + /* Label only every other mark. */ + if (mark % 2 != 0) return STR_NULL; + + SetDParam(0, value / 31 * 25); // 0-127 does not map nicely to 0-100. Dividing first gives us nice round numbers. + return STR_GAME_OPTIONS_VOLUME_MARK; +} static constexpr NWidgetPart _nested_social_plugins_widgets[] = { NWidget(NWID_HORIZONTAL), @@ -572,7 +562,7 @@ struct GameOptionsWindow : Window { break; case WID_GO_GUI_SCALE: - DrawSliderWidget(r, MIN_INTERFACE_SCALE, MAX_INTERFACE_SCALE, this->gui_scale, _scale_labels); + DrawSliderWidget(r, MIN_INTERFACE_SCALE, MAX_INTERFACE_SCALE, SCALE_NMARKS, this->gui_scale, ScaleMarkFunc); break; case WID_GO_VIDEO_DRIVER_INFO: @@ -581,11 +571,11 @@ struct GameOptionsWindow : Window { break; case WID_GO_BASE_SFX_VOLUME: - DrawSliderWidget(r, 0, INT8_MAX, _settings_client.music.effect_vol, _volume_labels); + DrawSliderWidget(r, 0, INT8_MAX, VOLUME_NMARKS, _settings_client.music.effect_vol, VolumeMarkFunc); break; case WID_GO_BASE_MUSIC_VOLUME: - DrawSliderWidget(r, 0, INT8_MAX, _settings_client.music.music_vol, _volume_labels); + DrawSliderWidget(r, 0, INT8_MAX, VOLUME_NMARKS, _settings_client.music.music_vol, VolumeMarkFunc); break; } } diff --git a/src/slider.cpp b/src/slider.cpp index 67894a88d2..c6f086c006 100644 --- a/src/slider.cpp +++ b/src/slider.cpp @@ -24,13 +24,14 @@ static const int SLIDER_WIDTH = 3; * @param r Rectangle to draw the widget in * @param min_value Minimum value of slider * @param max_value Maximum value of slider + * @param nmarks Number of marks to display (when mark_func is provided.) * @param value Value to put the slider at - * @param labels List of positions and labels to draw along the slider. + * @param mark_func Callback function to get the StringID to draw on a mark. */ -void DrawSliderWidget(Rect r, int min_value, int max_value, int value, const std::map &labels) +void DrawSliderWidget(Rect r, int min_value, int max_value, int nmarks, int value, SliderMarkFunc *mark_func) { /* Allow space for labels. We assume they are in the small font. */ - if (!labels.empty()) r.bottom -= GetCharacterHeight(FS_SMALL) + WidgetDimensions::scaled.hsep_normal; + if (mark_func != nullptr) r.bottom -= GetCharacterHeight(FS_SMALL) + WidgetDimensions::scaled.hsep_normal; max_value -= min_value; @@ -51,15 +52,22 @@ void DrawSliderWidget(Rect r, int min_value, int max_value, int value, const std GfxDrawLine(wedge[0].x, wedge[0].y, wedge[1].x, wedge[1].y, shadow, t); int x; - for (auto label : labels) { - x = label.first - min_value; - if (_current_text_dir == TD_RTL) x = max_value - x; - x = r.left + (x * (r.right - r.left - sw) / max_value) + sw / 2; - GfxDrawLine(x, r.bottom - ha + 1, x, r.bottom + (label.second == STR_NULL ? 0 : WidgetDimensions::scaled.hsep_normal), shadow, t); - if (label.second != STR_NULL) { - Dimension d = GetStringBoundingBox(label.second, FS_SMALL); + if (mark_func != nullptr) { + for (int mark = 0; mark < nmarks; ++mark) { + const int mark_value = (max_value * mark) / (nmarks - 1); + + const StringID str = mark_func(nmarks, mark, mark_value + min_value); + if (str == INVALID_STRING_ID) continue; + + x = mark_value; + if (_current_text_dir == TD_RTL) x = max_value - mark_value; + x = r.left + (x * (r.right - r.left - sw) / max_value) + sw / 2; + GfxDrawLine(x, r.bottom - ha + 1, x, r.bottom + (str == STR_NULL ? 0 : WidgetDimensions::scaled.hsep_normal), shadow, t); + if (str == STR_NULL) continue; + + Dimension d = GetStringBoundingBox(str, FS_SMALL); x = Clamp(x - d.width / 2, r.left, r.right - d.width); - DrawString(x, x + d.width, r.bottom + 1 + WidgetDimensions::scaled.hsep_normal, label.second, TC_BLACK, SA_CENTER, false, FS_SMALL); + DrawString(x, x + d.width, r.bottom + 1 + WidgetDimensions::scaled.hsep_normal, str, TC_BLACK, SA_CENTER, false, FS_SMALL); } } diff --git a/src/slider_func.h b/src/slider_func.h index 0aaa39bf15..f0ff9cc0ac 100644 --- a/src/slider_func.h +++ b/src/slider_func.h @@ -13,7 +13,8 @@ #include "core/geometry_type.hpp" #include "strings_type.h" -void DrawSliderWidget(Rect r, int min_value, int max_value, int value, const std::map &labels); +using SliderMarkFunc = StringID(int nmarks, int mark, int value); +void DrawSliderWidget(Rect r, int min_value, int max_value, int nmarks, int value, SliderMarkFunc *mark_func); bool ClickSliderWidget(Rect r, Point pt, int min_value, int max_value, int &value); inline bool ClickSliderWidget(Rect r, Point pt, int min_value, int max_value, uint8_t &value)