diff --git a/src/fontcache/freetypefontcache.cpp b/src/fontcache/freetypefontcache.cpp index 06a96e8374..29650f3d22 100644 --- a/src/fontcache/freetypefontcache.cpp +++ b/src/fontcache/freetypefontcache.cpp @@ -65,18 +65,19 @@ void FreeTypeFontCache::SetFontSize(FontSize fs, FT_Face face, int pixels) { if (pixels == 0) { /* Try to determine a good height based on the minimal height recommended by the font. */ - int scaled_height = ScaleFontTrad(this->GetDefaultFontHeight(this->fs)); + int scaled_height = ScaleGUITrad(this->GetDefaultFontHeight(this->fs)); pixels = scaled_height; TT_Header *head = (TT_Header *)FT_Get_Sfnt_Table(this->face, ft_sfnt_head); if (head != nullptr) { /* Font height is minimum height plus the difference between the default * height for this font size and the small size. */ - int diff = scaled_height - ScaleFontTrad(this->GetDefaultFontHeight(FS_SMALL)); - pixels = Clamp(std::min(head->Lowest_Rec_PPEM, MAX_FONT_MIN_REC_SIZE) + diff, scaled_height, MAX_FONT_SIZE); + int diff = scaled_height - ScaleGUITrad(this->GetDefaultFontHeight(FS_SMALL)); + /* Clamp() is not used as scaled_height could be greater than MAX_FONT_SIZE, which is not permitted in Clamp(). */ + pixels = std::min(std::max(std::min(head->Lowest_Rec_PPEM, MAX_FONT_MIN_REC_SIZE) + diff, scaled_height), MAX_FONT_SIZE); } } else { - pixels = ScaleFontTrad(pixels); + pixels = ScaleGUITrad(pixels); } this->used_size = pixels; diff --git a/src/fontcache/spritefontcache.cpp b/src/fontcache/spritefontcache.cpp index 45a36fe8ef..373187952e 100644 --- a/src/fontcache/spritefontcache.cpp +++ b/src/fontcache/spritefontcache.cpp @@ -28,7 +28,8 @@ static const int ASCII_LETTERSTART = 32; ///< First printable ASCII letter. SpriteFontCache::SpriteFontCache(FontSize fs) : FontCache(fs), glyph_to_spriteid_map(nullptr) { this->InitializeUnicodeGlyphMap(); - this->height = ScaleFontTrad(this->GetDefaultFontHeight(this->fs)); + this->height = ScaleGUITrad(this->GetDefaultFontHeight(this->fs)); + this->ascender = (this->height - ScaleSpriteTrad(this->GetDefaultFontHeight(this->fs))) / 2; } /** @@ -104,7 +105,8 @@ void SpriteFontCache::ClearGlyphToSpriteMap() void SpriteFontCache::ClearFontCache() { Layouter::ResetFontCache(this->fs); - this->height = ScaleFontTrad(this->GetDefaultFontHeight(this->fs)); + this->height = ScaleGUITrad(this->GetDefaultFontHeight(this->fs)); + this->ascender = (this->height - ScaleSpriteTrad(this->GetDefaultFontHeight(this->fs))) / 2; } const Sprite *SpriteFontCache::GetGlyph(GlyphID key) diff --git a/src/gfx.cpp b/src/gfx.cpp index 728750c025..147a717a85 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -61,12 +61,9 @@ static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode, static ReusableBuffer _cursor_backup; -ZoomLevel _gui_zoom; ///< GUI Zoom level -ZoomLevel _font_zoom; ///< Font Zoom level - -int8 _gui_zoom_cfg; ///< GUI zoom level in config. -int8 _font_zoom_cfg; ///< Font zoom level in config. - +ZoomLevel _gui_zoom = ZOOM_LVL_OUT_4X; ///< GUI Zoom level +int _gui_scale = MIN_INTERFACE_SCALE; ///< GUI scale, 100 is 100%. +int _gui_scale_cfg; ///< GUI scale in config. /** * The rect for repaint. @@ -2028,48 +2025,52 @@ void SortResolutions() void UpdateGUIZoom() { /* Determine real GUI zoom to use. */ - if (_gui_zoom_cfg == ZOOM_LVL_CFG_AUTO) { - _gui_zoom = static_cast(Clamp(VideoDriver::GetInstance()->GetSuggestedUIZoom(), _settings_client.gui.zoom_min, _settings_client.gui.zoom_max)); + if (_gui_scale_cfg == -1) { + _gui_scale = VideoDriver::GetInstance()->GetSuggestedUIScale(); } else { - /* Ensure the gui_zoom is clamped between min/max. Change the - * _gui_zoom_cfg if it isn't, as this is used to visually show the - * selection in the Game Options. */ - _gui_zoom_cfg = Clamp(_gui_zoom_cfg, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max); - _gui_zoom = static_cast(_gui_zoom_cfg); + _gui_scale = Clamp(_gui_scale_cfg, MIN_INTERFACE_SCALE, MAX_INTERFACE_SCALE); } - /* Determine real font zoom to use. */ - if (_font_zoom_cfg == ZOOM_LVL_CFG_AUTO) { - _font_zoom = static_cast(VideoDriver::GetInstance()->GetSuggestedUIZoom()); - } else { - _font_zoom = static_cast(_font_zoom_cfg); - } + int8 new_zoom = ScaleGUITrad(1) <= 1 ? ZOOM_LVL_OUT_4X : ScaleGUITrad(1) >= 4 ? ZOOM_LVL_MIN : ZOOM_LVL_OUT_2X; + /* Ensure the gui_zoom is clamped between min/max. */ + new_zoom = Clamp(new_zoom, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max); + _gui_zoom = static_cast(new_zoom); } /** * Resolve GUI zoom level and adjust GUI to new zoom, if auto-suggestion is requested. + * @param automatic Set if the change is occuring due to OS DPI scaling being changed. * @returns true when the zoom level has changed, caller must call ReInitAllWindows(true) * after resizing the application's window/buffer. */ -bool AdjustGUIZoom() +bool AdjustGUIZoom(bool automatic) { - auto old_zoom = _gui_zoom; + ZoomLevel old_zoom = _gui_zoom; + int old_scale = _gui_scale; UpdateGUIZoom(); - if (old_zoom == _gui_zoom) return false; - GfxClearSpriteCache(); - VideoDriver::GetInstance()->ClearSystemSprites(); + if (old_scale == _gui_scale) return false; + + /* Reload sprites if sprite zoom level has changed. */ + if (old_zoom != _gui_zoom) { + GfxClearSpriteCache(); + VideoDriver::GetInstance()->ClearSystemSprites(); + UpdateCursorSize(); + } + ClearFontCache(); - GfxClearSpriteCache(); + LoadStringWidthTable(); UpdateAllVirtCoords(); /* Adjust all window sizes to match the new zoom level, so that they don't appear to move around when the application is moved to a screen with different DPI. */ auto zoom_shift = old_zoom - _gui_zoom; for (Window *w : Window::Iterate()) { - w->left = AdjustByZoom(w->left, zoom_shift); - w->top = AdjustByZoom(w->top, zoom_shift); - w->width = AdjustByZoom(w->width, zoom_shift); - w->height = AdjustByZoom(w->height, zoom_shift); + if (automatic) { + w->left = (w->left * _gui_scale) / old_scale; + w->top = (w->top * _gui_scale) / old_scale; + w->width = (w->width * _gui_scale) / old_scale; + w->height = (w->height * _gui_scale) / old_scale; + } if (w->viewport != nullptr) { w->viewport->zoom = Clamp(ZoomLevel(w->viewport->zoom - zoom_shift), _settings_client.gui.zoom_min, _settings_client.gui.zoom_max); } diff --git a/src/gfx_func.h b/src/gfx_func.h index 4ed6a81461..5f5b89003e 100644 --- a/src/gfx_func.h +++ b/src/gfx_func.h @@ -79,8 +79,7 @@ void ChangeGameSpeed(bool enable_fast_forward); void DrawMouseCursor(); void ScreenSizeChanged(); void GameSizeChanged(); -void UpdateGUIZoom(); -bool AdjustGUIZoom(); +bool AdjustGUIZoom(bool automatic); void UndrawMouseCursor(); /** Size of the buffer used for drawing strings. */ diff --git a/src/gfx_layout.cpp b/src/gfx_layout.cpp index 38f6d62e59..8246e10aca 100644 --- a/src/gfx_layout.cpp +++ b/src/gfx_layout.cpp @@ -339,12 +339,12 @@ FallbackParagraphLayout::FallbackVisualRun::FallbackVisualRun(Font *font, const /* Positions contains the location of the begin of each of the glyphs, and the end of the last one. */ this->positions = MallocT(this->glyph_count * 2 + 2); this->positions[0] = x; - this->positions[1] = 0; + this->positions[1] = font->fc->GetAscender(); for (int i = 0; i < this->glyph_count; i++) { this->glyphs[i] = font->fc->MapCharToGlyph(chars[i]); this->positions[2 * i + 2] = this->positions[2 * i] + font->fc->GetGlyphWidth(this->glyphs[i]); - this->positions[2 * i + 3] = 0; + this->positions[2 * i + 3] = font->fc->GetAscender(); this->glyph_to_char[i] = i; } } diff --git a/src/graph_gui.cpp b/src/graph_gui.cpp index 4bf6f069c8..4e2babf61f 100644 --- a/src/graph_gui.cpp +++ b/src/graph_gui.cpp @@ -900,7 +900,7 @@ struct PaymentRatesGraphWindow : BaseGraphWindow { void OnInit() override { /* Width of the legend blob. */ - this->legend_width = (FONT_HEIGHT_SMALL - ScaleFontTrad(1)) * 8 / 5; + this->legend_width = (FONT_HEIGHT_SMALL - ScaleGUITrad(1)) * 8 / 5; } void UpdateExcludedData() diff --git a/src/lang/english.txt b/src/lang/english.txt index 8883a15850..bb85c04ca0 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1008,24 +1008,19 @@ STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Check th STR_GAME_OPTIONS_VIDEO_DRIVER_INFO :{BLACK}Current driver: {RAW_STRING} -STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Interface size -STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Select the interface element size to use +STR_GAME_OPTIONS_GUI_SCALE_FRAME :{BLACK}Interface size +STR_GAME_OPTIONS_GUI_SCALE_TOOLTIP :{BLACK}Drag slider to set interface size. Hold Ctrl for continuous adjustment +STR_GAME_OPTIONS_GUI_SCALE_AUTO :{BLACK}Auto-detect size +STR_GAME_OPTIONS_GUI_SCALE_AUTO_TOOLTIP :{BLACK}Check this box to detect interface size automatically STR_GAME_OPTIONS_GUI_SCALE_BEVELS :{BLACK}Scale bevels STR_GAME_OPTIONS_GUI_SCALE_BEVELS_TOOLTIP :{BLACK}Check this box to scale bevels by interface size -STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_AUTO :(auto-detect) -STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_NORMAL :Normal -STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_2X_ZOOM :Double size -STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_4X_ZOOM :Quad size - -STR_GAME_OPTIONS_FONT_ZOOM :{BLACK}Font size -STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Select the interface font size to use - -STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_AUTO :(auto-detect) -STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_NORMAL :Normal -STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_2X_ZOOM :Double size -STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_4X_ZOOM :Quad size +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_GRAPHICS :{BLACK}Graphics diff --git a/src/news_gui.cpp b/src/news_gui.cpp index 7439d67c3e..4f18a5d455 100644 --- a/src/news_gui.cpp +++ b/src/news_gui.cpp @@ -1159,7 +1159,7 @@ struct MessageHistoryWindow : Window { /* Months are off-by-one, so it's actually 8. Not using * month 12 because the 1 is usually less wide. */ SetDParam(0, ConvertYMDToDate(ORIGINAL_MAX_YEAR, 7, 30)); - this->date_width = GetStringBoundingBox(STR_SHORT_DATE).width + ScaleFontTrad(5); + this->date_width = GetStringBoundingBox(STR_SHORT_DATE).width + ScaleGUITrad(5); size->height = 4 * resize->height + WidgetDimensions::scaled.framerect.Vertical(); // At least 4 lines are visible. size->width = std::max(200u, size->width); // At least 200 pixels wide. diff --git a/src/openttd.cpp b/src/openttd.cpp index 1e7cd9ae0e..20401892be 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -756,7 +756,9 @@ int openttd_main(int argc, char *argv[]) /* Initialize the zoom level of the screen to normal */ _screen.zoom = ZOOM_LVL_NORMAL; - UpdateGUIZoom(); + + /* The video driver is now selected, now initialise GUI zoom */ + AdjustGUIZoom(false); NetworkStartUp(); // initialize network-core diff --git a/src/os/macosx/font_osx.cpp b/src/os/macosx/font_osx.cpp index cb0ffda94b..b3b4f306db 100644 --- a/src/os/macosx/font_osx.cpp +++ b/src/os/macosx/font_osx.cpp @@ -173,7 +173,7 @@ void CoreTextFontCache::SetFontSize(int pixels) { if (pixels == 0) { /* Try to determine a good height based on the height recommended by the font. */ - int scaled_height = ScaleFontTrad(this->GetDefaultFontHeight(this->fs)); + int scaled_height = ScaleGUITrad(this->GetDefaultFontHeight(this->fs)); pixels = scaled_height; CFAutoRelease font(CTFontCreateWithFontDescriptor(this->font_desc.get(), 0.0f, nullptr)); @@ -197,11 +197,12 @@ void CoreTextFontCache::SetFontSize(int pixels) /* Font height is minimum height plus the difference between the default * height for this font size and the small size. */ - int diff = scaled_height - ScaleFontTrad(this->GetDefaultFontHeight(FS_SMALL)); - pixels = Clamp(std::min(min_size, MAX_FONT_MIN_REC_SIZE) + diff, scaled_height, MAX_FONT_SIZE); + int diff = scaled_height - ScaleGUITrad(this->GetDefaultFontHeight(FS_SMALL)); + /* Clamp() is not used as scaled_height could be greater than MAX_FONT_SIZE, which is not permitted in Clamp(). */ + pixels = std::min(std::max(std::min(min_size, MAX_FONT_MIN_REC_SIZE) + diff, scaled_height), MAX_FONT_SIZE); } } else { - pixels = ScaleFontTrad(pixels); + pixels = ScaleGUITrad(pixels); } this->used_size = pixels; diff --git a/src/os/windows/font_win32.cpp b/src/os/windows/font_win32.cpp index fb62aadb59..962595a016 100644 --- a/src/os/windows/font_win32.cpp +++ b/src/os/windows/font_win32.cpp @@ -392,7 +392,7 @@ void Win32FontCache::SetFontSize(FontSize fs, int pixels) { if (pixels == 0) { /* Try to determine a good height based on the minimal height recommended by the font. */ - int scaled_height = ScaleFontTrad(this->GetDefaultFontHeight(this->fs)); + int scaled_height = ScaleGUITrad(this->GetDefaultFontHeight(this->fs)); pixels = scaled_height; HFONT temp = CreateFontIndirect(&this->logfont); @@ -405,14 +405,15 @@ void Win32FontCache::SetFontSize(FontSize fs, int pixels) /* Font height is minimum height plus the difference between the default * height for this font size and the small size. */ - int diff = scaled_height - ScaleFontTrad(this->GetDefaultFontHeight(FS_SMALL)); - pixels = Clamp(std::min(otm->otmusMinimumPPEM, MAX_FONT_MIN_REC_SIZE) + diff, scaled_height, MAX_FONT_SIZE); + int diff = scaled_height - ScaleGUITrad(this->GetDefaultFontHeight(FS_SMALL)); + /* Clamp() is not used as scaled_height could be greater than MAX_FONT_SIZE, which is not permitted in Clamp(). */ + pixels = std::min(std::max(std::min(otm->otmusMinimumPPEM, MAX_FONT_MIN_REC_SIZE) + diff, scaled_height), MAX_FONT_SIZE); SelectObject(dc, old); DeleteObject(temp); } } else { - pixels = ScaleFontTrad(pixels); + pixels = ScaleGUITrad(pixels); } this->used_size = pixels; diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index c11393de52..3b03ef17b8 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -57,22 +57,6 @@ static const StringID _autosave_dropdown[] = { INVALID_STRING_ID, }; -static const StringID _gui_zoom_dropdown[] = { - STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_AUTO, - STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_NORMAL, - STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_2X_ZOOM, - STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_4X_ZOOM, - INVALID_STRING_ID, -}; - -static const StringID _font_zoom_dropdown[] = { - STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_AUTO, - STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_NORMAL, - STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_2X_ZOOM, - STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_4X_ZOOM, - INVALID_STRING_ID, -}; - static Dimension _circle_size; ///< Dimension of the circle +/- icon. This is here as not all users are within the class of the settings window. static const void *ResolveObject(const GameSettings *settings_ptr, const IntSettingDesc *sd); @@ -158,14 +142,36 @@ 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 }, +}; + struct GameOptionsWindow : Window { GameSettings *opt; bool reload; + int gui_scale; GameOptionsWindow(WindowDesc *desc) : Window(desc) { this->opt = &GetGameSettings(); this->reload = false; + this->gui_scale = _gui_scale; AddCustomRefreshRates(); @@ -264,24 +270,6 @@ struct GameOptionsWindow : Window { } break; - case WID_GO_GUI_ZOOM_DROPDOWN: { - *selected_index = _gui_zoom_cfg != ZOOM_LVL_CFG_AUTO ? ZOOM_LVL_OUT_4X - _gui_zoom + 1 : 0; - const StringID *items = _gui_zoom_dropdown; - for (int i = 0; *items != INVALID_STRING_ID; items++, i++) { - list.emplace_back(new DropDownListStringItem(*items, i, i != 0 && _settings_client.gui.zoom_min > ZOOM_LVL_OUT_4X - i + 1)); - } - break; - } - - case WID_GO_FONT_ZOOM_DROPDOWN: { - *selected_index = _font_zoom_cfg != ZOOM_LVL_CFG_AUTO ? ZOOM_LVL_OUT_4X - _font_zoom + 1 : 0; - const StringID *items = _font_zoom_dropdown; - for (int i = 0; *items != INVALID_STRING_ID; items++, i++) { - list.emplace_back(new DropDownListStringItem(*items, i, false)); - } - break; - } - case WID_GO_BASE_GRF_DROPDOWN: list = BuildSetDropDownList(selected_index, (_game_mode == GM_MENU)); break; @@ -304,8 +292,6 @@ struct GameOptionsWindow : Window { case WID_GO_CURRENCY_DROPDOWN: SetDParam(0, _currency_specs[this->opt->locale.currency].name); break; case WID_GO_AUTOSAVE_DROPDOWN: SetDParam(0, _autosave_dropdown[_settings_client.gui.autosave]); break; case WID_GO_LANG_DROPDOWN: SetDParamStr(0, _current_language->own_name); break; - case WID_GO_GUI_ZOOM_DROPDOWN: SetDParam(0, _gui_zoom_dropdown[_gui_zoom_cfg != ZOOM_LVL_CFG_AUTO ? ZOOM_LVL_OUT_4X - _gui_zoom_cfg + 1 : 0]); break; - case WID_GO_FONT_ZOOM_DROPDOWN: SetDParam(0, _font_zoom_dropdown[_font_zoom_cfg != ZOOM_LVL_CFG_AUTO ? ZOOM_LVL_OUT_4X - _font_zoom_cfg + 1 : 0]); break; case WID_GO_BASE_GRF_DROPDOWN: SetDParamStr(0, BaseGraphics::GetUsedSet()->name); break; case WID_GO_BASE_GRF_STATUS: SetDParam(0, BaseGraphics::GetUsedSet()->GetNumInvalid()); break; case WID_GO_BASE_SFX_DROPDOWN: SetDParamStr(0, BaseSounds::GetUsedSet()->name); break; @@ -346,6 +332,10 @@ struct GameOptionsWindow : Window { DrawStringMultiLine(r.left, r.right, r.top, UINT16_MAX, STR_BLACK_RAW_STRING); break; + case WID_GO_GUI_SCALE: + DrawSliderWidget(r, MIN_INTERFACE_SCALE, MAX_INTERFACE_SCALE, this->gui_scale, _scale_labels); + break; + case WID_GO_BASE_SFX_VOLUME: DrawSliderWidget(r, 0, INT8_MAX, _settings_client.music.effect_vol, {}); break; @@ -486,6 +476,30 @@ struct GameOptionsWindow : Window { break; } + case WID_GO_GUI_SCALE: + if (ClickSliderWidget(this->GetWidget(widget)->GetCurrentRect(), pt, MIN_INTERFACE_SCALE, MAX_INTERFACE_SCALE, this->gui_scale)) { + if (!_ctrl_pressed) this->gui_scale = ((this->gui_scale + 12) / 25) * 25; + this->SetWidgetDirty(widget); + } + + if (click_count > 0) this->mouse_capture_widget = widget; + break; + + case WID_GO_GUI_SCALE_AUTO: + { + if (_gui_scale_cfg == -1) { + _gui_scale_cfg = _gui_scale; + this->SetWidgetLoweredState(WID_GO_GUI_SCALE_AUTO, false); + } else { + _gui_scale_cfg = -1; + this->SetWidgetLoweredState(WID_GO_GUI_SCALE_AUTO, true); + if (AdjustGUIZoom(false)) ReInitAllWindows(true); + this->gui_scale = _gui_scale; + } + this->SetWidgetDirty(widget); + break; + } + case WID_GO_BASE_SFX_VOLUME: case WID_GO_BASE_MUSIC_VOLUME: { byte &vol = (widget == WID_GO_BASE_MUSIC_VOLUME) ? _settings_client.music.music_vol : _settings_client.music.effect_vol; @@ -517,6 +531,19 @@ struct GameOptionsWindow : Window { } } + void OnMouseLoop() override + { + if (_left_button_down || this->gui_scale == _gui_scale) return; + + _gui_scale_cfg = this->gui_scale; + + if (AdjustGUIZoom(false)) { + ReInitAllWindows(true); + this->SetWidgetLoweredState(WID_GO_GUI_SCALE_AUTO, false); + this->SetDirty(); + } + } + /** * Set the base media set. * @param index the index of the media set @@ -576,36 +603,6 @@ struct GameOptionsWindow : Window { break; } - case WID_GO_GUI_ZOOM_DROPDOWN: { - int8 new_zoom = index > 0 ? ZOOM_LVL_OUT_4X - index + 1 : ZOOM_LVL_CFG_AUTO; - if (new_zoom != _gui_zoom_cfg) { - GfxClearSpriteCache(); - _gui_zoom_cfg = new_zoom; - UpdateGUIZoom(); - UpdateCursorSize(); - SetupWidgetDimensions(); - UpdateAllVirtCoords(); - FixTitleGameZoom(); - ReInitAllWindows(true); - } - break; - } - - case WID_GO_FONT_ZOOM_DROPDOWN: { - int8 new_zoom = index > 0 ? ZOOM_LVL_OUT_4X - index + 1 : ZOOM_LVL_CFG_AUTO; - if (new_zoom != _font_zoom_cfg) { - GfxClearSpriteCache(); - _font_zoom_cfg = new_zoom; - UpdateGUIZoom(); - ClearFontCache(); - LoadStringWidthTable(); - SetupWidgetDimensions(); - UpdateAllVirtCoords(); - ReInitAllWindows(true); - } - break; - } - case WID_GO_BASE_GRF_DROPDOWN: this->SetMediaSet(index); break; @@ -637,6 +634,7 @@ struct GameOptionsWindow : Window { this->SetWidgetDisabledState(WID_GO_VIDEO_VSYNC_BUTTON, !_video_hw_accel); #endif + this->SetWidgetLoweredState(WID_GO_GUI_SCALE_AUTO, _gui_scale_cfg == -1); this->SetWidgetLoweredState(WID_GO_GUI_SCALE_BEVEL_BUTTON, _settings_client.gui.scale_bevels); bool missing_files = BaseGraphics::GetUsedSet()->GetNumMissing() == 0; @@ -664,16 +662,6 @@ static const NWidgetPart _nested_game_options_widgets[] = { NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_AUTOSAVE_FRAME, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_AUTOSAVE_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP), SetFill(1, 0), EndContainer(), - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_GUI_ZOOM_FRAME, STR_NULL), - NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_GUI_ZOOM_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP), SetFill(1, 0), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetDataTip(STR_GAME_OPTIONS_GUI_SCALE_BEVELS, STR_NULL), - NWidget(NWID_SPACER), SetMinimalSize(1, 0), SetFill(1, 0), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_GUI_SCALE_BEVEL_BUTTON), SetMinimalSize(21, 9), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_GUI_SCALE_BEVELS_TOOLTIP), - EndContainer(), - EndContainer(), - EndContainer(), NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_CURRENCY_UNITS_FRAME, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_CURRENCY_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_CURRENCY_UNITS_DROPDOWN_TOOLTIP), SetFill(1, 0), EndContainer(), @@ -683,8 +671,20 @@ static const NWidgetPart _nested_game_options_widgets[] = { NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_LANGUAGE, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_LANG_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_LANGUAGE_TOOLTIP), SetFill(1, 0), EndContainer(), - NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_FONT_ZOOM, STR_NULL), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_FONT_ZOOM_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_TOOLTIP), SetFill(1, 0), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_GUI_SCALE_FRAME, STR_NULL), + NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_GO_GUI_SCALE), SetMinimalSize(67, 0), SetMinimalTextLines(1, 12 + WidgetDimensions::unscaled.vsep_normal, FS_SMALL), SetFill(0, 0), SetDataTip(0x0, STR_GAME_OPTIONS_GUI_SCALE_TOOLTIP), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetDataTip(STR_GAME_OPTIONS_GUI_SCALE_AUTO, STR_NULL), + NWidget(NWID_SPACER), SetMinimalSize(1, 0), SetFill(1, 0), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_GUI_SCALE_AUTO), SetMinimalSize(21, 9), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_GUI_SCALE_AUTO_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetDataTip(STR_GAME_OPTIONS_GUI_SCALE_BEVELS, STR_NULL), + NWidget(NWID_SPACER), SetMinimalSize(1, 0), SetFill(1, 0), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_GUI_SCALE_BEVEL_BUTTON), SetMinimalSize(21, 9), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_GUI_SCALE_BEVELS_TOOLTIP), + EndContainer(), + EndContainer(), EndContainer(), EndContainer(), EndContainer(), diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp index 4d3305cf84..f4fdf0013f 100644 --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -1188,7 +1188,7 @@ void SmallMapWindow::RebuildColourIndexIfNecessary() } /* Width of the legend blob. */ - this->legend_width = (FONT_HEIGHT_SMALL - ScaleFontTrad(1)) * 8 / 5; + this->legend_width = (FONT_HEIGHT_SMALL - ScaleGUITrad(1)) * 8 / 5; /* The width of a column is the minimum width of all texts + the size of the blob + some spacing */ this->column_width = min_width + this->legend_width + WidgetDimensions::scaled.framerect.Horizontal(); diff --git a/src/spritecache.cpp b/src/spritecache.cpp index e3dd33dfc9..a62d2e29ad 100644 --- a/src/spritecache.cpp +++ b/src/spritecache.cpp @@ -517,14 +517,14 @@ static void *ReadSprite(const SpriteCache *sc, SpriteID id, SpriteType sprite_ty return (void*)GetRawSprite(SPR_IMG_QUERY, ST_NORMAL, allocator, encoder); } - if (sprite->type == ST_FONT && ZOOM_LVL_FONT != ZOOM_LVL_NORMAL) { - /* Make ZOOM_LVL_NORMAL be ZOOM_LVL_FONT */ - sprite[ZOOM_LVL_NORMAL].width = sprite[ZOOM_LVL_FONT].width; - sprite[ZOOM_LVL_NORMAL].height = sprite[ZOOM_LVL_FONT].height; - sprite[ZOOM_LVL_NORMAL].x_offs = sprite[ZOOM_LVL_FONT].x_offs; - sprite[ZOOM_LVL_NORMAL].y_offs = sprite[ZOOM_LVL_FONT].y_offs; - sprite[ZOOM_LVL_NORMAL].data = sprite[ZOOM_LVL_FONT].data; - sprite[ZOOM_LVL_NORMAL].colours = sprite[ZOOM_LVL_FONT].colours; + if (sprite->type == ST_FONT && ZOOM_LVL_GUI != ZOOM_LVL_NORMAL) { + /* Make ZOOM_LVL_NORMAL be ZOOM_LVL_GUI */ + sprite[ZOOM_LVL_NORMAL].width = sprite[ZOOM_LVL_GUI].width; + sprite[ZOOM_LVL_NORMAL].height = sprite[ZOOM_LVL_GUI].height; + sprite[ZOOM_LVL_NORMAL].x_offs = sprite[ZOOM_LVL_GUI].x_offs; + sprite[ZOOM_LVL_NORMAL].y_offs = sprite[ZOOM_LVL_GUI].y_offs; + sprite[ZOOM_LVL_NORMAL].data = sprite[ZOOM_LVL_GUI].data; + sprite[ZOOM_LVL_NORMAL].colours = sprite[ZOOM_LVL_GUI].colours; } return encoder->Encode(sprite, allocator); diff --git a/src/station_gui.cpp b/src/station_gui.cpp index c551db17ca..512f025a48 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -163,7 +163,7 @@ static void StationsWndShowStationRating(int left, int right, int y, CargoID typ const CargoSpec *cs = CargoSpec::Get(type); if (!cs->IsValid()) return; - int padding = ScaleFontTrad(1); + int padding = ScaleGUITrad(1); int width = right - left; int colour = cs->rating_colour; TextColour tc = GetContrastColour(colour); @@ -177,7 +177,7 @@ static void StationsWndShowStationRating(int left, int right, int y, CargoID typ } else { /* Draw a (scaled) one pixel-wide bar of additional cargo meter, useful * for stations with only a small amount (<=30) */ - uint rest = ScaleFontTrad(amount) / 5; + uint rest = ScaleGUITrad(amount) / 5; if (rest != 0) { GfxFillRect(left, y + height - rest, left + padding - 1, y + height, colour); } @@ -391,7 +391,7 @@ public: } case WID_STL_LIST: - resize->height = std::max(FONT_HEIGHT_NORMAL, FONT_HEIGHT_SMALL + ScaleFontTrad(3)); + resize->height = std::max(FONT_HEIGHT_NORMAL, FONT_HEIGHT_SMALL + ScaleGUITrad(3)); size->height = padding.height + 5 * resize->height; /* Determine appropriate width for mini station rating graph */ diff --git a/src/table/settings/misc_settings.ini b/src/table/settings/misc_settings.ini index 15e9413ed2..dd3a58e24e 100644 --- a/src/table/settings/misc_settings.ini +++ b/src/table/settings/misc_settings.ini @@ -334,21 +334,12 @@ max = UINT32_MAX cat = SC_EXPERT [SDTG_VAR] -name = ""gui_zoom"" -type = SLE_INT8 -var = _gui_zoom_cfg -def = ZOOM_LVL_CFG_AUTO -min = ZOOM_LVL_CFG_AUTO -max = ZOOM_LVL_OUT_4X -cat = SC_BASIC - -[SDTG_VAR] -name = ""font_zoom"" -type = SLE_INT8 -var = _font_zoom_cfg -def = ZOOM_LVL_CFG_AUTO -min = ZOOM_LVL_CFG_AUTO -max = ZOOM_LVL_OUT_4X +name = ""gui_scale"" +type = SLE_INT32 +var = _gui_scale_cfg +def = -1 +min = -1 +max = MAX_INTERFACE_SCALE cat = SC_BASIC [SDTG_BOOL] diff --git a/src/video/cocoa/cocoa_wnd.mm b/src/video/cocoa/cocoa_wnd.mm index 36d010177d..d4fc5b292e 100644 --- a/src/video/cocoa/cocoa_wnd.mm +++ b/src/video/cocoa/cocoa_wnd.mm @@ -1269,7 +1269,7 @@ void CocoaDialog(const char *title, const char *message, const char *buttonLabel /** Screen the window is on changed. */ - (void)windowDidChangeBackingProperties:(NSNotification *)notification { - bool did_adjust = AdjustGUIZoom(); + bool did_adjust = AdjustGUIZoom(true); /* Reallocate screen buffer if necessary. */ driver->AllocateBackingStore(); diff --git a/src/video/video_driver.hpp b/src/video/video_driver.hpp index 6ef06c45f6..b81ec6e2fb 100644 --- a/src/video/video_driver.hpp +++ b/src/video/video_driver.hpp @@ -167,15 +167,13 @@ public: } /** - * Get a suggested default GUI zoom taking screen DPI into account. + * Get a suggested default GUI scale taking screen DPI into account. */ - virtual ZoomLevel GetSuggestedUIZoom() + virtual int GetSuggestedUIScale() { float dpi_scale = this->GetDPIScale(); - if (dpi_scale >= 3.0f) return ZOOM_LVL_NORMAL; - if (dpi_scale >= 1.5f) return ZOOM_LVL_OUT_2X; - return ZOOM_LVL_OUT_4X; + return Clamp(dpi_scale * 100, MIN_INTERFACE_SCALE, MAX_INTERFACE_SCALE); } virtual const char *GetInfoString() const diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp index 49c967bfa4..8d8a78a0ca 100644 --- a/src/video/win32_v.cpp +++ b/src/video/win32_v.cpp @@ -675,7 +675,7 @@ LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) } case WM_DPICHANGED: { - auto did_adjust = AdjustGUIZoom(); + auto did_adjust = AdjustGUIZoom(true); /* Resize the window to match the new DPI setting. */ RECT *prcNewWindow = (RECT *)lParam; diff --git a/src/widgets/settings_widget.h b/src/widgets/settings_widget.h index e727c4d277..8f655d945a 100644 --- a/src/widgets/settings_widget.h +++ b/src/widgets/settings_widget.h @@ -19,7 +19,8 @@ enum GameOptionsWidgets { WID_GO_LANG_DROPDOWN, ///< Language dropdown. WID_GO_RESOLUTION_DROPDOWN, ///< Dropdown for the resolution. WID_GO_FULLSCREEN_BUTTON, ///< Toggle fullscreen. - WID_GO_GUI_ZOOM_DROPDOWN, ///< Dropdown for the GUI zoom level. + WID_GO_GUI_SCALE, ///< GUI Scale slider. + WID_GO_GUI_SCALE_AUTO, ///< Autodetect GUI scale button. WID_GO_GUI_SCALE_BEVEL_BUTTON, ///< Toggle for chunky bevels. WID_GO_BASE_GRF_DROPDOWN, ///< Use to select a base GRF. WID_GO_BASE_GRF_STATUS, ///< Info about missing files etc. @@ -35,7 +36,6 @@ enum GameOptionsWidgets { WID_GO_BASE_MUSIC_STATUS, ///< Info about corrupted files etc. WID_GO_BASE_MUSIC_TEXTFILE, ///< Open base music readme, changelog (+1) or license (+2). WID_GO_BASE_MUSIC_DESCRIPTION = WID_GO_BASE_MUSIC_TEXTFILE + TFT_END, ///< Description of selected base music set. - WID_GO_FONT_ZOOM_DROPDOWN, ///< Dropdown for the font zoom level. WID_GO_VIDEO_ACCEL_BUTTON, ///< Toggle for video acceleration. WID_GO_VIDEO_VSYNC_BUTTON, ///< Toggle for video vsync. WID_GO_REFRESH_RATE_DROPDOWN, ///< Dropdown for all available refresh rates. diff --git a/src/zoom_func.h b/src/zoom_func.h index b9f23d2130..abcc050d25 100644 --- a/src/zoom_func.h +++ b/src/zoom_func.h @@ -116,27 +116,7 @@ static inline int ScaleSpriteTrad(int value) */ static inline int ScaleGUITrad(int value) { - return UnScaleGUI(value * ZOOM_LVL_BASE); -} - -/** - * Short-hand to apply font zoom level. - * @param value Pixel amount at #ZOOM_LVL_BEGIN (full zoom in). - * @return Pixel amount at #ZOOM_LVL_FONT (current interface size). - */ -static inline int UnScaleFont(int value) -{ - return UnScaleByZoom(value, ZOOM_LVL_FONT); -} - -/** - * Scale traditional pixel dimensions to Font zoom level. - * @param value Pixel amount at #ZOOM_LVL_BASE (traditional "normal" interface size). - * @return Pixel amount at #ZOOM_LVL_FONT (current interface size). - */ -static inline int ScaleFontTrad(int value) -{ - return UnScaleFont(value * ZOOM_LVL_BASE); + return value * _gui_scale / 100; } #endif /* ZOOM_FUNC_H */ diff --git a/src/zoom_type.h b/src/zoom_type.h index ffa70f7611..7ccc142ef3 100644 --- a/src/zoom_type.h +++ b/src/zoom_type.h @@ -15,8 +15,6 @@ static uint const ZOOM_LVL_SHIFT = 2; static uint const ZOOM_LVL_BASE = 1 << ZOOM_LVL_SHIFT; -static const int8 ZOOM_LVL_CFG_AUTO = -1; - /** All zoom levels we know. */ enum ZoomLevel : byte { /* Our possible zoom-levels */ @@ -50,12 +48,13 @@ enum ZoomLevel : byte { }; DECLARE_POSTFIX_INCREMENT(ZoomLevel) -extern int8 _gui_zoom_cfg; -extern int8 _font_zoom_cfg; +extern int _gui_scale; +extern int _gui_scale_cfg; extern ZoomLevel _gui_zoom; -extern ZoomLevel _font_zoom; #define ZOOM_LVL_GUI (_gui_zoom) -#define ZOOM_LVL_FONT (_font_zoom) + +static const int MIN_INTERFACE_SCALE = 100; +static const int MAX_INTERFACE_SCALE = 500; #endif /* ZOOM_TYPE_H */