• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Return-To-The-Roots / s25client / 24281818037

11 Apr 2026 11:47AM UTC coverage: 50.196% (-0.2%) from 50.371%
24281818037

Pull #1890

github

web-flow
Merge 7778f6b51 into 58cb9475f
Pull Request #1890: Add support for borderless Windows

155 of 626 new or added lines in 44 files covered. (24.76%)

30 existing lines in 10 files now uncovered.

23074 of 45968 relevant lines covered (50.2%)

42880.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/libs/s25main/desktops/dskOptions.cpp
1
// Copyright (C) 2005 - 2026 Settlers Freaks (sf-team at siedler25.org)
2
//
3
// SPDX-License-Identifier: GPL-2.0-or-later
4

5
#include "dskOptions.h"
6
#include "GlobalGameSettings.h"
7
#include "Loader.h"
8
#include "MusicPlayer.h"
9
#include "Settings.h"
10
#include "WindowManager.h"
11
#include "controls/ctrlComboBox.h"
12
#include "controls/ctrlEdit.h"
13
#include "controls/ctrlGroup.h"
14
#include "controls/ctrlImageButton.h"
15
#include "controls/ctrlOptionGroup.h"
16
#include "controls/ctrlProgress.h"
17
#include "controls/ctrlTextButton.h"
18
#include "driver/VideoDriver.h"
19
#include "drivers/AudioDriverWrapper.h"
20
#include "drivers/VideoDriverWrapper.h"
21
#include "dskMainMenu.h"
22
#include "helpers/containerUtils.h"
23
#include "helpers/format.hpp"
24
#include "helpers/mathFuncs.h"
25
#include "helpers/toString.h"
26
#include "ingameWindows/iwAddons.h"
27
#include "ingameWindows/iwMsgbox.h"
28
#include "ingameWindows/iwMusicPlayer.h"
29
#include "ingameWindows/iwTextfile.h"
30
#include "languages.h"
31
#include "ogl/FontStyle.h"
32
#include "gameData/PortraitConsts.h"
33
#include "s25util/StringConversion.h"
34
#include "s25util/colors.h"
35
#include <mygettext/mygettext.h>
36
#include <sstream>
37

38
namespace {
39
using Offset = DrawPoint;
40

41
enum
42
{
43
    ID_btBack = dskMenuBase::ID_FIRST_FREE,
44
    ID_txtOptions,
45
    ID_btAddons,
46
    ID_grpOptions,
47
    ID_btCommon,
48
    ID_btGraphics,
49
    ID_btSound,
50
    ID_grpCommon,
51
    ID_grpGraphics,
52
    ID_grpSound,
53
    ID_txtName,
54
    ID_edtName,
55
    ID_txtLanguage,
56
    ID_cbLanguage,
57
    ID_txtKeyboardLayout,
58
    ID_btKeyboardLayout,
59
    ID_txtPort,
60
    ID_edtPort,
61
    ID_txtIpv6,
62
    ID_grpIpv6,
63
    ID_txtProxy,
64
    ID_edtProxy,
65
    ID_edtProxyPort,
66
    ID_txtProxyType,
67
    ID_cbProxyType,
68
    ID_txtDebugData,
69
    ID_grpDebugData,
70
    ID_grpUPNP,
71
    ID_txtMapScrollMode,
72
    ID_cbMapScrollMode,
73
    ID_grpSmartCursor,
74
    ID_grpWindowPinning,
75
    ID_grpGFInfo,
76
    ID_grpResolution,
77
    ID_txtResolution,
78
    ID_cbResolution,
79
    ID_grpWindowSize,
80
    ID_txtWindowSize,
81
    ID_cbWindowSize,
82
    ID_txtDisplayMode,
83
    ID_cbDisplayMode,
84
    ID_grpLockWindowSize,
85
    ID_txtFramerate,
86
    ID_cbFramerate,
87
    ID_grpVBO,
88
    ID_txtVideoDriver,
89
    ID_cbVideoDriver,
90
    ID_grpOptTextures,
91
    ID_txtGuiScale,
92
    ID_cbGuiScale,
93
    ID_txtAudioDriver,
94
    ID_cbAudioDriver,
95
    ID_grpMusic,
96
    ID_pgMusicVol,
97
    ID_grpEffects,
98
    ID_pgEffectsVol,
99
    ID_btMusicPlayer,
100
    ID_txtCommonPortrait,
101
    ID_btCommonPortrait,
102
    ID_cbCommonPortrait,
103
    ID_grpBirdSounds,
104
    ID_txtsStart, // First ID for texts used by options (ID of option is used as offset on top)
105
};
106
// Use these as IDs in dedicated groups
107
constexpr auto ID_btOn = 1;
108
constexpr auto ID_btOff = 0;
109
// Special case: Submit debug data uses "2" for "ask user" and "0" for "unset, ask at start"
110
constexpr auto ID_btSubmitDebugOn = 1;
111
constexpr auto ID_btSubmitDebugAsk = 2;
112

113
constexpr auto rowHeight = 30;
114
constexpr auto sectionSpacing = 20;
115
constexpr auto sectionSpacingCommon = 10;
116
constexpr auto optionRowsStartPosition = DrawPoint(80, 75);
117
constexpr auto tabButtonsStartPosition = optionRowsStartPosition + Offset(0, static_cast<int>(rowHeight * 15.5));
118

119
constexpr Offset ctrlOffset(200, -5);                       // Offset of control to its description text
120
constexpr Offset ctrlOffset2 = ctrlOffset + Offset(200, 0); // Offset of 2nd control to its description text
121
constexpr Extent ctrlSize(190, 22);
122
constexpr Extent ctrlSizeLarge = ctrlSize + Extent(ctrlOffset2 - ctrlOffset);
123

NEW
124
VideoMode getAspectRatio(const VideoMode vm)
×
125
{
126
    // First some a bit off values where the aspect ratio is defined by convention
127
    if(vm == VideoMode(1360, 1024))
×
128
        return VideoMode(4, 3);
×
129
    else if(vm == VideoMode(1360, 768) || vm == VideoMode(1366, 768))
×
130
        return VideoMode(16, 9);
×
131

132
    // Normally Aspect ration is simply width/height as integer numbers (e.g. 4:3)
133
    int divisor = helpers::gcd(vm.width, vm.height);
×
134
    VideoMode ratio(vm.width / divisor, vm.height / divisor);
×
135
    // But there are some special cases:
136
    if(ratio == VideoMode(8, 5))
×
137
        return VideoMode(16, 10);
×
138
    else if(ratio == VideoMode(5, 3))
×
139
        return VideoMode(15, 9);
×
140
    else
141
        return ratio;
×
142
}
143

144
enum class ButtonSize
145
{
146
    Normal,
147
    Half /// Both buttons take up the same space as a single button
148
};
149

NEW
150
ctrlOptionGroup& addOnOffOption(ctrlGroup& parentGroup, DrawPoint pos, unsigned id, const std::string& title,
×
151
                                bool value, ButtonSize btSize = ButtonSize::Normal)
152
{
NEW
153
    constexpr auto spacing = 10;
×
NEW
154
    auto size = ctrlSize;
×
NEW
155
    if(btSize == ButtonSize::Half)
×
NEW
156
        size.x = (ctrlSize.x - spacing) / 2;
×
157

NEW
158
    parentGroup.AddText(ID_txtsStart + id, pos, title, COLOR_YELLOW, FontStyle{}, NormalFont);
×
NEW
159
    auto* option = parentGroup.AddOptionGroup(id, GroupSelectType::Check);
×
NEW
160
    pos += ctrlOffset;
×
NEW
161
    option->AddTextButton(ID_btOn, pos, size, TextureColor::Grey, _("On"), NormalFont);
×
NEW
162
    pos.x += size.x + spacing;
×
NEW
163
    option->AddTextButton(ID_btOff, pos, size, TextureColor::Grey, _("Off"), NormalFont);
×
NEW
164
    option->SetSelection(value);
×
NEW
165
    return *option;
×
166
}
167

168
} // namespace
169

UNCOV
170
dskOptions::dskOptions() : Desktop(LOADER.GetImageN("setup013", 0))
×
171
{
172
    AddText(ID_txtOptions, DrawPoint(400, 10), _("Options"), COLOR_YELLOW, FontStyle::CENTER, LargeFont);
×
173

174
    ctrlOptionGroup* mainGroup = AddOptionGroup(ID_grpOptions, GroupSelectType::Check);
×
175

176
    DrawPoint curPos = tabButtonsStartPosition;
×
177
    mainGroup->AddTextButton(ID_btCommon, DrawPoint(curPos.x, curPos.y), Extent(200, 22), TextureColor::Green2,
×
178
                             _("Common"), NormalFont);
×
179
    mainGroup->AddTextButton(ID_btGraphics, DrawPoint(curPos.x + 220, curPos.y), Extent(200, 22), TextureColor::Green2,
×
180
                             _("Graphics"), NormalFont);
×
181
    mainGroup->AddTextButton(ID_btSound, DrawPoint(curPos.x + 440, curPos.y), Extent(200, 22), TextureColor::Green2,
×
182
                             _("Sound/Music"), NormalFont);
×
183
    curPos.y += rowHeight;
×
184

185
    AddTextButton(ID_btBack, DrawPoint(curPos.x + 220, curPos.y), Extent(200, 22), TextureColor::Red1, _("Back"),
×
186
                  NormalFont);
×
187
    AddTextButton(ID_btAddons, DrawPoint(curPos.x + 440, curPos.y), Extent(200, 22), TextureColor::Green2, _("Addons"),
×
188
                  NormalFont);
×
189

190
    ctrlGroup* groupCommon = AddGroup(ID_grpCommon);
×
191
    ctrlGroup* groupGraphics = AddGroup(ID_grpGraphics);
×
192
    ctrlGroup* groupSound = AddGroup(ID_grpSound);
×
193
    ctrlComboBox* combo;
194

195
    // Common
196
    // {
197

198
    curPos = optionRowsStartPosition;
×
199

200
    groupCommon->AddText(ID_txtName, curPos, _("Name in Game:"), COLOR_YELLOW, FontStyle{}, NormalFont);
×
201
    ctrlEdit* name =
202
      groupCommon->AddEdit(ID_edtName, curPos + ctrlOffset, ctrlSize, TextureColor::Grey, NormalFont, 15);
×
203
    name->SetText(SETTINGS.lobby.name);
×
204

205
    const auto& currentPortrait = Portraits[SETTINGS.lobby.portraitIndex];
×
206
    groupCommon->AddImageButton(ID_btCommonPortrait, DrawPoint(500, curPos.y + ctrlOffset.y), Extent(40, rowHeight * 2),
×
207
                                TextureColor::Grey,
208
                                LOADER.GetImageN(currentPortrait.resourceId, currentPortrait.resourceIndex));
×
209
    curPos.y += rowHeight;
×
210

211
    groupCommon->AddText(ID_txtCommonPortrait, curPos, _("Portrait:"), COLOR_YELLOW, FontStyle{}, NormalFont);
×
212
    combo =
213
      groupCommon->AddComboBox(ID_cbCommonPortrait, curPos + ctrlOffset, ctrlSize, TextureColor::Grey, NormalFont, 100);
×
214

215
    for(unsigned i = 0; i < Portraits.size(); ++i)
×
216
    {
NEW
217
        combo->AddItem(_(Portraits[i].name));
×
218
        if(SETTINGS.lobby.portraitIndex == i)
×
219
            combo->SetSelection(i);
×
220
    }
221
    curPos.y += rowHeight;
×
222

223
    groupCommon->AddText(ID_txtLanguage, curPos, _("Language:"), COLOR_YELLOW, FontStyle{}, NormalFont);
×
224
    combo = groupCommon->AddComboBox(ID_cbLanguage, curPos + ctrlOffset, ctrlSize, TextureColor::Grey, NormalFont, 100);
×
225

226
    bool selected = false;
×
227
    for(unsigned i = 0; i < LANGUAGES.size(); ++i)
×
228
    {
229
        const Language& l = LANGUAGES.getLanguage(i);
×
230

NEW
231
        combo->AddItem(_(l.name));
×
232
        if(SETTINGS.language.language == l.code)
×
233
        {
234
            combo->SetSelection(static_cast<unsigned short>(i));
×
235
            selected = true;
×
236
        }
237
    }
238
    if(!selected)
×
239
        combo->SetSelection(0);
×
240
    curPos.y += rowHeight;
×
241

242
    groupCommon->AddTextButton(ID_btKeyboardLayout, curPos + ctrlOffset, ctrlSizeLarge, TextureColor::Grey,
×
243
                               _("Keyboard layout"), NormalFont);
×
244
    curPos.y += rowHeight;
×
245

246
    curPos.y += sectionSpacingCommon;
×
247
    groupCommon->AddText(ID_txtPort, curPos, _("Local Port:"), COLOR_YELLOW, FontStyle{}, NormalFont);
×
248
    ctrlEdit* edtPort =
249
      groupCommon->AddEdit(ID_edtPort, curPos + ctrlOffset, ctrlSize, TextureColor::Grey, NormalFont, 15);
×
250
    edtPort->SetNumberOnly(true);
×
251
    edtPort->SetText(SETTINGS.server.localPort);
×
252
    curPos.y += rowHeight;
×
253

254
    // IPv4/6
NEW
255
    auto& grpIPv6 = addOnOffOption(*groupCommon, curPos, ID_grpIpv6, _("Use IPv6:"), SETTINGS.server.ipv6);
×
NEW
256
    grpIPv6.GetCtrl<ctrlTextButton>(ID_btOn)->SetText(_("IPv6"));
×
NEW
257
    grpIPv6.GetCtrl<ctrlTextButton>(ID_btOff)->SetText(_("IPv4"));
×
258
    // Enable/disable the IPv6 field if necessary
NEW
259
    grpIPv6.GetCtrl<ctrlButton>(ID_btOn)->SetEnabled(SETTINGS.proxy.type != ProxyType::Socks5); //-V807
×
260
    curPos.y += rowHeight;
×
261

262
    curPos.y += sectionSpacingCommon;
×
263
    // Proxy server
264
    groupCommon->AddText(ID_txtProxy, curPos, _("Proxyserver:"), COLOR_YELLOW, FontStyle{}, NormalFont);
×
265
    ctrlEdit* proxy = groupCommon->AddEdit(ID_edtProxy, curPos + ctrlOffset, ctrlSize, TextureColor::Grey, NormalFont);
×
266
    proxy->SetText(SETTINGS.proxy.hostname);
×
267
    proxy =
268
      groupCommon->AddEdit(ID_edtProxyPort, curPos + ctrlOffset2, Extent(50, 22), TextureColor::Grey, NormalFont, 5);
×
269
    proxy->SetNumberOnly(true);
×
270
    proxy->SetText(SETTINGS.proxy.port);
×
271
    curPos.y += rowHeight;
×
272

NEW
273
    addOnOffOption(*groupCommon, curPos, ID_grpUPNP, _("Use UPnP"), SETTINGS.global.useUPNP);
×
274
    curPos.y += rowHeight;
×
275

276
    // Proxy type
277
    groupCommon->AddText(ID_txtProxyType, curPos, _("Proxytyp:"), COLOR_YELLOW, FontStyle{}, NormalFont);
×
278
    combo =
279
      groupCommon->AddComboBox(ID_cbProxyType, curPos + ctrlOffset, ctrlSizeLarge, TextureColor::Grey, NormalFont, 100);
×
NEW
280
    combo->AddItem(_("No Proxy"));
×
NEW
281
    combo->AddItem(_("Socks v4"));
×
282
    // TODO: not implemented
283
    // combo->AddString(_("Socks v5"));
284

285
    switch(SETTINGS.proxy.type)
×
286
    {
287
        default: combo->SetSelection(0); break;
×
288
        case ProxyType::Socks4: combo->SetSelection(1); break;
×
289
        case ProxyType::Socks5: combo->SetSelection(2); break;
×
290
    }
291
    curPos.y += rowHeight;
×
292

293
    curPos.y += sectionSpacingCommon;
×
294
    groupCommon->AddText(ID_txtMapScrollMode, curPos, _("Map scroll mode:"), COLOR_YELLOW, FontStyle{}, NormalFont);
×
295
    combo = groupCommon->AddComboBox(ID_cbMapScrollMode, curPos + ctrlOffset, ctrlSizeLarge, TextureColor::Grey,
×
296
                                     NormalFont, 100);
×
NEW
297
    combo->AddItem(_("Scroll same (Map moves in the same direction the mouse is moved when scrolling/panning.)"));
×
NEW
298
    combo->AddItem(
×
299
      _("Scroll opposite (Map moves in the opposite direction the mouse is moved when scrolling/panning.)"));
NEW
300
    combo->AddItem(_("Grab and drag (Map moves with your cursor when scrolling/panning.)"));
×
301
    combo->SetSelection(static_cast<int>(SETTINGS.interface.mapScrollMode));
×
302
    curPos.y += rowHeight;
×
303

304
    auto& grpSmartCursor =
NEW
305
      addOnOffOption(*groupCommon, curPos, ID_grpSmartCursor, _("Smart Cursor"), SETTINGS.global.smartCursor);
×
NEW
306
    grpSmartCursor.GetCtrl<ctrlButton>(ID_btOn)->SetTooltip(
×
307
      _("Place cursor on default button for new dialogs / action windows (default)"));
NEW
308
    grpSmartCursor.GetCtrl<ctrlButton>(ID_btOff)->SetTooltip(
×
309
      _("Don't move cursor automatically\nUseful e.g. for split-screen / dual-mice multiplayer (see wiki)"));
310
    curPos.y += rowHeight;
×
311

312
    auto& grpWindowPinning = addOnOffOption(*groupCommon, curPos, ID_grpWindowPinning, _("Window pinning"),
NEW
313
                                            SETTINGS.interface.enableWindowPinning);
×
NEW
314
    grpWindowPinning.GetCtrl<ctrlButton>(ID_btOn)->SetTooltip(
×
315
      _("Replace minimize button on windows by pin button avoiding closing the window with "
316
        "ESC.\nMinimize by double-clicking the title bar."));
UNCOV
317
    curPos.y += rowHeight;
×
318

319
    curPos.y += sectionSpacingCommon;
×
320
    groupCommon->AddText(ID_txtDebugData, curPos, _("Submit debug data:"), COLOR_YELLOW, FontStyle{}, NormalFont);
×
321
    mainGroup = groupCommon->AddOptionGroup(ID_grpDebugData, GroupSelectType::Check);
×
322
    mainGroup->AddTextButton(ID_btSubmitDebugOn, curPos + ctrlOffset, ctrlSize, TextureColor::Grey, _("On"),
×
323
                             NormalFont);
×
324
    mainGroup->AddTextButton(ID_btSubmitDebugAsk, curPos + ctrlOffset2, ctrlSize, TextureColor::Grey, _("Ask always"),
×
325
                             NormalFont);
×
326

NEW
327
    mainGroup->SetSelection((SETTINGS.global.submitDebugData == 1) ? ID_btSubmitDebugOn : ID_btSubmitDebugAsk); //-V807
×
UNCOV
328
    curPos.y += rowHeight;
×
329

NEW
330
    addOnOffOption(*groupCommon, curPos, ID_grpGFInfo, _("Show GameFrame Info:"), SETTINGS.global.showGFInfo);
×
331

332
    curPos = optionRowsStartPosition;
×
333

NEW
334
    groupGraphics->AddText(ID_txtDisplayMode, curPos, _("Mode:"), COLOR_YELLOW, FontStyle{}, NormalFont);
×
NEW
335
    ctrlComboBox* cbDisplayMode = groupGraphics->AddComboBox(ID_cbDisplayMode, curPos + ctrlOffset, ctrlSizeLarge,
×
NEW
336
                                                             TextureColor::Grey, NormalFont, 100);
×
NEW
337
    cbDisplayMode->AddItem(_("Windowed"));
×
NEW
338
    cbDisplayMode->AddItem(_("Fullscreen"));
×
NEW
339
    cbDisplayMode->AddItem(_("Borderless window"));
×
NEW
340
    cbDisplayMode->SetSelection(rttr::enum_cast(SETTINGS.video.displayMode.type));
×
NEW
341
    curPos.y += rowHeight;
×
342

NEW
343
    auto* grpResolution = groupGraphics->AddGroup(ID_grpResolution);
×
NEW
344
    grpResolution->AddText(ID_txtResolution, curPos, _("Fullscreen resolution:"), COLOR_YELLOW, FontStyle{},
×
345
                           NormalFont);
×
NEW
346
    grpResolution->AddComboBox(ID_cbResolution, curPos + ctrlOffset, ctrlSize, TextureColor::Grey, NormalFont, 150);
×
NEW
347
    auto* grpWindowSize = groupGraphics->AddGroup(ID_grpWindowSize);
×
NEW
348
    grpWindowSize->AddText(ID_txtWindowSize, curPos, _("Window size:"), COLOR_YELLOW, FontStyle{}, NormalFont);
×
NEW
349
    grpWindowSize->AddComboBox(ID_cbWindowSize, curPos + ctrlOffset, ctrlSize, TextureColor::Grey, NormalFont, 150);
×
UNCOV
350
    curPos.y += rowHeight;
×
351

352
    addOnOffOption(*grpWindowSize, curPos, ID_grpLockWindowSize, _("Lock window size:"),
NEW
353
                   !SETTINGS.video.displayMode.resizeable);
×
UNCOV
354
    curPos.y += rowHeight;
×
355

356
    curPos.y += sectionSpacing;
×
357
    groupGraphics->AddText(ID_txtFramerate, curPos, _("Limit Framerate:"), COLOR_YELLOW, FontStyle{}, NormalFont);
×
358
    groupGraphics->AddComboBox(ID_cbFramerate, curPos + ctrlOffset, ctrlSizeLarge, TextureColor::Grey, NormalFont, 150);
×
359
    curPos.y += rowHeight;
×
360

361
    curPos.y += sectionSpacing;
×
NEW
362
    addOnOffOption(*groupGraphics, curPos, ID_grpVBO, _("Vertex Buffer Objects:"), SETTINGS.video.vbo);
×
363
    curPos.y += rowHeight;
×
364

365
    curPos.y += sectionSpacing;
×
366
    groupGraphics->AddText(ID_txtVideoDriver, curPos, _("Graphics Driver"), COLOR_YELLOW, FontStyle{}, NormalFont);
×
367
    combo = groupGraphics->AddComboBox(ID_cbVideoDriver, curPos + ctrlOffset, ctrlSizeLarge, TextureColor::Grey,
×
368
                                       NormalFont, 100);
×
369

370
    const auto video_drivers = drivers::DriverWrapper::LoadDriverList(drivers::DriverType::Video);
×
371

372
    for(const auto& video_driver : video_drivers)
×
373
    {
NEW
374
        combo->AddItem(video_driver.GetName());
×
375
        if(video_driver.GetName() == SETTINGS.driver.video)
×
376
            combo->SetSelection(combo->GetNumItems() - 1);
×
377
    }
378
    curPos.y += rowHeight;
×
379

380
    curPos.y += sectionSpacing;
×
NEW
381
    addOnOffOption(*groupGraphics, curPos, ID_grpOptTextures, _("Optimized Textures:"), SETTINGS.video.sharedTextures);
×
382
    curPos.y += rowHeight;
×
383

384
    curPos.y += sectionSpacing;
×
385
    groupGraphics->AddText(ID_txtGuiScale, curPos, _("GUI Scale:"), COLOR_YELLOW, FontStyle{}, NormalFont);
×
386
    groupGraphics->AddComboBox(ID_cbGuiScale, curPos + ctrlOffset, ctrlSize, TextureColor::Grey, NormalFont, 100);
×
387
    updateGuiScale();
×
388

389
    curPos = optionRowsStartPosition;
×
390

NEW
391
    addOnOffOption(*groupSound, curPos, ID_grpEffects, _("Effects"), SETTINGS.sound.effectsEnabled, ButtonSize::Half);
×
392

393
    ctrlProgress* FXvolume =
NEW
394
      groupSound->AddProgress(ID_pgEffectsVol, curPos + ctrlOffset2, ctrlSize, TextureColor::Grey, 139, 138, 100);
×
395
    FXvolume->SetPosition((SETTINGS.sound.effectsVolume * 100) / 255);
×
396
    curPos.y += rowHeight;
×
397

398
    curPos.y += sectionSpacing;
×
NEW
399
    addOnOffOption(*groupSound, curPos, ID_grpBirdSounds, _("Bird sounds"), SETTINGS.sound.birdsEnabled,
×
NEW
400
                   ButtonSize::Half);
×
UNCOV
401
    curPos.y += rowHeight;
×
402

403
    curPos.y += sectionSpacing;
×
NEW
404
    addOnOffOption(*groupSound, curPos, ID_grpMusic, _("Music"), SETTINGS.sound.musicEnabled, ButtonSize::Half);
×
405

406
    ctrlProgress* Mvolume =
NEW
407
      groupSound->AddProgress(ID_pgMusicVol, curPos + ctrlOffset2, ctrlSize, TextureColor::Grey, 139, 138, 100);
×
408
    Mvolume->SetPosition((SETTINGS.sound.musicVolume * 100) / 255); //-V807
×
409
    curPos.y += rowHeight;
×
410

411
    curPos.y += sectionSpacing;
×
412
    groupSound->AddTextButton(ID_btMusicPlayer, curPos + ctrlOffset, ctrlSize, TextureColor::Grey, _("Music player"),
×
413
                              NormalFont);
×
414
    curPos.y += rowHeight;
×
415

416
    curPos.y += sectionSpacing;
×
417
    groupSound->AddText(ID_txtAudioDriver, curPos, _("Sounddriver"), COLOR_YELLOW, FontStyle{}, NormalFont);
×
418
    combo = groupSound->AddComboBox(ID_cbAudioDriver, curPos + ctrlOffset, ctrlSizeLarge, TextureColor::Grey,
×
419
                                    NormalFont, 100);
×
420

421
    const auto audio_drivers = drivers::DriverWrapper::LoadDriverList(drivers::DriverType::Audio);
×
422

423
    for(const auto& audio_driver : audio_drivers)
×
424
    {
NEW
425
        combo->AddItem(audio_driver.GetName());
×
426
        if(audio_driver.GetName() == SETTINGS.driver.audio)
×
427
            combo->SetSelection(combo->GetNumItems() - 1);
×
428
    }
429

430
    // Select "General"
431
    mainGroup = GetCtrl<ctrlOptionGroup>(ID_grpOptions);
×
432
    mainGroup->SetSelection(ID_btCommon, true);
×
433

434
    // Graphics
435
    // {
436

437
    loadVideoModes();
×
438

439
    // and add to the combo box
NEW
440
    ctrlComboBox& cbVideoModes = *grpResolution->GetCtrl<ctrlComboBox>(ID_cbResolution);
×
NEW
441
    for(const auto& videoMode : videoModes_)
×
442
    {
443
        VideoMode ratio = getAspectRatio(videoMode);
×
444
        s25util::ClassicImbuedStream<std::ostringstream> str;
×
445
        str << videoMode.width << "x" << videoMode.height;
×
446
        // Make the length always the same as 'iiiixiiii' to align the ratio
447
        int len = str.str().length();
×
448
        for(int i = len; i < 4 + 1 + 4; i++)
×
449
            str << " ";
×
450
        str << " (" << ratio.width << ":" << ratio.height << ")";
×
451

NEW
452
        cbVideoModes.AddItem(str.str());
×
453

454
        // Select, if this is the current resolution
455
        if(videoMode == SETTINGS.video.fullscreenSize) //-V807
×
456
            cbVideoModes.SetSelection(cbVideoModes.GetNumItems() - 1);
×
457
    }
NEW
458
    ctrlComboBox& cbWindowSize = *grpWindowSize->GetCtrl<ctrlComboBox>(ID_cbWindowSize);
×
NEW
459
    cbWindowSize.AddItem(""); // Placeholder for current window size
×
NEW
460
    for(const auto& size : windowSizes_)
×
461
    {
NEW
462
        s25util::ClassicImbuedStream<std::ostringstream> str;
×
NEW
463
        str << size.width << "x" << size.height;
×
NEW
464
        cbWindowSize.AddItem(str.str());
×
465
    }
NEW
466
    updateWindowSizeComboBox();
×
NEW
467
    updateResolutionGroups();
×
468

469
    // Fill "Limit Framerate"
470
    auto* cbFrameRate = groupGraphics->GetCtrl<ctrlComboBox>(ID_cbFramerate);
×
471
    if(VIDEODRIVER.HasVSync())
×
NEW
472
        cbFrameRate->AddItem(_("Dynamic (Limits to display refresh rate, works with most drivers)"));
×
473
    for(int framerate : Settings::SCREEN_REFRESH_RATES)
×
474
    {
475
        if(framerate == -1)
×
NEW
476
            cbFrameRate->AddItem(_("Disabled"));
×
477
        else
NEW
478
            cbFrameRate->AddItem(helpers::toString(framerate) + " FPS");
×
479
        if(SETTINGS.video.framerate == framerate)
×
480
            cbFrameRate->SetSelection(cbFrameRate->GetNumItems() - 1);
×
481
    }
482
    if(!cbFrameRate->GetSelection())
×
483
        cbFrameRate->SetSelection(0);
×
484

485
    // }
486

487
    // Sound
488
    // {
489

490
    groupSound->GetCtrl<ctrlOptionGroup>(ID_grpEffects)->SetSelection(SETTINGS.sound.effectsEnabled);
×
491
    groupSound->GetCtrl<ctrlOptionGroup>(ID_grpBirdSounds)->SetSelection(SETTINGS.sound.birdsEnabled);
×
492
    groupSound->GetCtrl<ctrlOptionGroup>(ID_grpMusic)->SetSelection(SETTINGS.sound.musicEnabled);
×
493

494
    // }
495

496
    // Load game settings
497
    ggs.LoadSettings();
×
498
}
×
499

500
dskOptions::~dskOptions()
×
501
{
502
    // Save game settings
503
    ggs.SaveSettings();
×
504
}
×
505

506
void dskOptions::Msg_Group_ProgressChange(const unsigned /*group_id*/, const unsigned ctrl_id,
×
507
                                          const unsigned short position)
508
{
509
    switch(ctrl_id)
×
510
    {
511
        case ID_pgEffectsVol:
×
512
            SETTINGS.sound.effectsVolume = static_cast<uint8_t>((position * 255) / 100);
×
513
            AUDIODRIVER.SetMasterEffectVolume(SETTINGS.sound.effectsVolume);
×
514
            break;
×
515
        case ID_pgMusicVol:
×
516
            SETTINGS.sound.musicVolume = static_cast<uint8_t>((position * 255) / 100);
×
517
            AUDIODRIVER.SetMusicVolume(SETTINGS.sound.musicVolume);
×
518
            break;
×
519
    }
520
}
×
521

522
void dskOptions::Msg_Group_ComboSelectItem(const unsigned group_id, const unsigned ctrl_id, const unsigned selection)
×
523
{
524
    auto* group = GetCtrl<ctrlGroup>(group_id);
×
525
    auto* combo = group->GetCtrl<ctrlComboBox>(ctrl_id);
×
526

527
    switch(ctrl_id)
×
528
    {
529
        case ID_cbCommonPortrait:
×
530
            SETTINGS.lobby.portraitIndex = selection;
×
531
            updatePortraitControls();
×
532
            break;
×
533
        case ID_cbLanguage:
×
534
        {
535
            // Language changed?
536
            std::string old_lang = SETTINGS.language.language; //-V807
×
537
            SETTINGS.language.language = LANGUAGES.setLanguage(selection);
×
538
            if(SETTINGS.language.language != old_lang)
×
539
                WINDOWMANAGER.Switch(std::make_unique<dskOptions>());
×
540
        }
541
        break;
×
542
        case ID_cbProxyType:
×
543
            switch(selection)
544
            {
545
                case 0: SETTINGS.proxy.type = ProxyType::None; break;
×
546
                case 1: SETTINGS.proxy.type = ProxyType::Socks4; break;
×
547
                case 2: SETTINGS.proxy.type = ProxyType::Socks5; break;
×
548
            }
549

550
            // Disable IPv6 visually
551
            if(SETTINGS.proxy.type == ProxyType::Socks4 && SETTINGS.server.ipv6)
×
552
            {
553
                GetCtrl<ctrlGroup>(ID_grpCommon)->GetCtrl<ctrlOptionGroup>(ID_grpIpv6)->SetSelection(0);
×
554
                GetCtrl<ctrlGroup>(ID_grpCommon)
×
555
                  ->GetCtrl<ctrlOptionGroup>(ID_grpIpv6)
×
556
                  ->GetCtrl<ctrlButton>(1)
557
                  ->SetEnabled(false);
×
558
                SETTINGS.server.ipv6 = false;
×
559
            }
560

561
            if(SETTINGS.proxy.type != ProxyType::Socks4)
×
562
                GetCtrl<ctrlGroup>(ID_grpCommon)
×
563
                  ->GetCtrl<ctrlOptionGroup>(ID_grpIpv6)
×
564
                  ->GetCtrl<ctrlButton>(1)
565
                  ->SetEnabled(true);
×
566
            break;
×
567
        case ID_cbMapScrollMode: SETTINGS.interface.mapScrollMode = static_cast<MapScrollMode>(selection); break;
×
NEW
568
        case ID_cbResolution: SETTINGS.video.fullscreenSize = videoModes_[selection]; break;
×
NEW
569
        case ID_cbWindowSize:
×
NEW
570
            if(selection > 0)
×
571
            {
NEW
572
                SETTINGS.video.windowedSize = windowSizes_[selection - 1];
×
NEW
573
                if(SETTINGS.video.displayMode == DisplayMode::Windowed
×
NEW
574
                   && VIDEODRIVER.GetDisplayMode() == DisplayMode::Windowed)
×
NEW
575
                    VIDEODRIVER.ResizeScreen(SETTINGS.video.windowedSize, DisplayMode::Windowed);
×
576
            }
NEW
577
            break;
×
578
        case ID_cbFramerate:
×
579
            if(VIDEODRIVER.HasVSync())
×
580
            {
581
                if(selection == 0)
×
582
                    SETTINGS.video.framerate = 0;
×
583
                else
584
                    SETTINGS.video.framerate = Settings::SCREEN_REFRESH_RATES[selection - 1];
×
585
            } else
586
                SETTINGS.video.framerate = Settings::SCREEN_REFRESH_RATES[selection];
×
587

588
            VIDEODRIVER.setTargetFramerate(SETTINGS.video.framerate);
×
589
            break;
×
590
        case ID_cbVideoDriver: SETTINGS.driver.video = combo->GetText(selection); break;
×
591
        case ID_cbGuiScale:
×
592
            SETTINGS.video.guiScale = guiScales_[selection];
×
593
            VIDEODRIVER.setGuiScalePercent(SETTINGS.video.guiScale);
×
594
            break;
×
595
        case ID_cbAudioDriver: SETTINGS.driver.audio = combo->GetText(selection); break;
×
NEW
596
        case ID_cbDisplayMode:
×
NEW
597
            SETTINGS.video.displayMode = DisplayMode(selection);
×
NEW
598
            updateResolutionGroups();
×
NEW
599
            break;
×
600
    }
601
}
×
602

603
void dskOptions::Msg_Group_OptionGroupChange(const unsigned /*group_id*/, const unsigned ctrl_id,
×
604
                                             const unsigned selection)
605
{
606
    const bool enabled = selection == ID_btOn;
×
607
    switch(ctrl_id)
×
608
    {
609
        case ID_grpIpv6: SETTINGS.server.ipv6 = enabled; break;
×
NEW
610
        case ID_grpLockWindowSize:
×
611
        {
NEW
612
            SETTINGS.video.displayMode.resizeable = !enabled;
×
NEW
613
            const auto newDisplayMode = SETTINGS.video.displayMode;
×
NEW
614
            if(newDisplayMode == DisplayMode::Windowed && VIDEODRIVER.GetDisplayMode() == DisplayMode::Windowed)
×
NEW
615
                VIDEODRIVER.ResizeScreen(VIDEODRIVER.GetWindowSize(), newDisplayMode);
×
616
        }
NEW
617
        break;
×
618
        case ID_grpVBO: SETTINGS.video.vbo = enabled; break;
×
NEW
619
        case ID_grpOptTextures: SETTINGS.video.sharedTextures = enabled; break;
×
620
        case ID_grpEffects: SETTINGS.sound.effectsEnabled = enabled; break;
×
621
        case ID_grpBirdSounds: SETTINGS.sound.birdsEnabled = enabled; break;
×
622
        case ID_grpMusic:
×
623
            SETTINGS.sound.musicEnabled = enabled;
×
624
            if(enabled)
×
625
                MUSICPLAYER.Play();
×
626
            else
627
                MUSICPLAYER.Stop();
×
628
            break;
×
629
        case ID_grpDebugData:
×
630
            // Special case: Uses e.g. ID_btSubmitDebugOn directly
NEW
631
            SETTINGS.global.submitDebugData = selection;
×
632
            break;
×
NEW
633
        case ID_grpUPNP: SETTINGS.global.useUPNP = enabled; break;
×
634
        case ID_grpSmartCursor:
×
635
            SETTINGS.global.smartCursor = enabled;
×
636
            VIDEODRIVER.SetMouseWarping(enabled);
×
637
            break;
×
638
        case ID_grpWindowPinning: SETTINGS.interface.enableWindowPinning = enabled; break;
×
639
        case ID_grpGFInfo: SETTINGS.global.showGFInfo = enabled; break;
×
NEW
640
        default: RTTR_Assert(false);
×
641
    }
642
}
×
643

644
void dskOptions::Msg_OptionGroupChange(const unsigned ctrl_id, const unsigned selection)
×
645
{
646
    if(ctrl_id == ID_grpOptions)
×
647
    {
648
        const auto visGrp = selection + ID_grpCommon - ID_btCommon;
×
649
        for(const unsigned id : {ID_grpCommon, ID_grpGraphics, ID_grpSound})
×
650
            GetCtrl<ctrlGroup>(id)->SetVisible(id == visGrp);
×
651
    }
652
}
×
653

654
/// Check that the port is valid and sets outPort to it. Shows an error otherwise
655
static bool validatePort(const std::string& sPort, uint16_t& outPort)
×
656
{
657
    boost::optional<uint16_t> port = validate::checkPort(sPort);
×
658
    if(port)
×
659
        outPort = *port;
×
660
    else
661
    {
662
        WINDOWMANAGER.Show(std::make_unique<iwMsgbox>(_("Error"),
×
663
                                                      _("Invalid port. The valid port-range is 1 to 65535!"), nullptr,
×
664
                                                      MsgboxButton::Ok, MsgboxIcon::ExclamationRed, 1));
×
665
    }
666
    return static_cast<bool>(port);
×
667
}
668

669
void dskOptions::Msg_ButtonClick(const unsigned ctrl_id)
×
670
{
671
    switch(ctrl_id)
×
672
    {
673
        case ID_btBack:
×
674
        {
675
            auto* groupCommon = GetCtrl<ctrlGroup>(ID_grpCommon);
×
676

677
            // Save the name
678
            SETTINGS.lobby.name = groupCommon->GetCtrl<ctrlEdit>(ID_edtName)->GetText();
×
679
            if(!validatePort(groupCommon->GetCtrl<ctrlEdit>(ID_edtPort)->GetText(), SETTINGS.server.localPort))
×
680
                return;
×
681

682
            SETTINGS.proxy.hostname = groupCommon->GetCtrl<ctrlEdit>(ID_edtProxy)->GetText();
×
683
            if(!validatePort(groupCommon->GetCtrl<ctrlEdit>(ID_edtProxyPort)->GetText(), SETTINGS.proxy.port))
×
684
                return;
×
685

686
            SETTINGS.Save();
×
687

688
            // Is the selected backend required to support GUI scaling to fulfill the user's choice?
689
            // If so, warn the user if the backend is unable to support GUI scaling.
NEW
690
            const auto requestedGuiScale = SETTINGS.video.guiScale;
×
NEW
691
            const bool autoGuiScale = requestedGuiScale == 0;
×
NEW
692
            if((!autoGuiScale && requestedGuiScale != VIDEODRIVER.getGuiScale().percent())
×
NEW
693
               || (autoGuiScale
×
NEW
694
                   && VIDEODRIVER.getGuiScaleRange().recommendedPercent != VIDEODRIVER.getGuiScale().percent()))
×
695

696
            {
697
                WINDOWMANAGER.Show(std::make_unique<iwMsgbox>(
×
698
                  _("Sorry!"), _("The selected video driver does not support GUI scaling! Setting won't be used."),
×
699
                  this, MsgboxButton::Ok, MsgboxIcon::ExclamationGreen, 1));
×
700
            }
701

NEW
702
            const auto fullscreen = SETTINGS.video.displayMode == DisplayMode::Fullscreen;
×
NEW
703
            if((fullscreen && SETTINGS.video.fullscreenSize != VIDEODRIVER.GetWindowSize()) //-V807
×
NEW
704
               || VIDEODRIVER.GetDisplayMode() != SETTINGS.video.displayMode)
×
705
            {
NEW
706
                const auto screenSize = fullscreen ? SETTINGS.video.fullscreenSize : SETTINGS.video.windowedSize;
×
NEW
707
                if(!VIDEODRIVER.ResizeScreen(screenSize, SETTINGS.video.displayMode))
×
708
                {
709
                    WINDOWMANAGER.Show(std::make_unique<iwMsgbox>(
×
710
                      _("Sorry!"), _("You need to restart your game to change the screen resolution!"), this,
×
711
                      MsgboxButton::Ok, MsgboxIcon::ExclamationGreen, 1));
×
712
                    return;
×
713
                }
714
            }
715
            if(SETTINGS.driver.video != VIDEODRIVER.GetName() || SETTINGS.driver.audio != AUDIODRIVER.GetName())
×
716
            {
717
                WINDOWMANAGER.Show(std::make_unique<iwMsgbox>(
×
718
                  _("Sorry!"), _("You need to restart your game to change the video or audio driver!"), this,
×
719
                  MsgboxButton::Ok, MsgboxIcon::ExclamationGreen, 1));
×
720
                return;
×
721
            }
722

723
            WINDOWMANAGER.Switch(std::make_unique<dskMainMenu>());
×
724
        }
725
        break;
×
726
        case ID_btAddons: WINDOWMANAGER.ToggleWindow(std::make_unique<iwAddons>(ggs)); break;
×
727
    }
728
}
729

730
void dskOptions::Msg_Group_ButtonClick(const unsigned /*group_id*/, const unsigned ctrl_id)
×
731
{
732
    switch(ctrl_id)
×
733
    {
734
        default: break;
×
735
        case ID_btCommonPortrait:
×
736
            SETTINGS.lobby.portraitIndex = (SETTINGS.lobby.portraitIndex + 1) % Portraits.size();
×
737
            updatePortraitControls();
×
738
            break;
×
739
        case ID_btMusicPlayer: WINDOWMANAGER.ToggleWindow(std::make_unique<iwMusicPlayer>()); break;
×
740
        case ID_btKeyboardLayout:
×
741
            WINDOWMANAGER.ToggleWindow(std::make_unique<iwTextfile>("keyboardlayout.txt", _("Keyboard layout")));
×
742
            break;
×
743
    }
744
}
×
745

746
void dskOptions::Msg_MsgBoxResult(const unsigned msgbox_id, const MsgboxResult /*mbr*/)
×
747
{
748
    switch(msgbox_id)
×
749
    {
750
        default: break;
×
751
        // "You need to restart your game ..."
752
        // "The selected video driver does not support GUI scaling!"
753
        case 1: WINDOWMANAGER.Switch(std::make_unique<dskMainMenu>()); break;
×
754
    }
755
}
×
756

757
static bool cmpVideoModes(const VideoMode& left, const VideoMode& right)
×
758
{
759
    if(left.width == right.width)
×
760
        return left.height > right.height;
×
761
    else
762
        return left.width > right.width;
×
763
}
764

765
void dskOptions::loadVideoModes()
×
766
{
767
    // Get available modes
NEW
768
    videoModes_ = VIDEODRIVER.ListVideoModes();
×
769
    // Sort by aspect ratio
NEW
770
    helpers::sort(videoModes_, cmpVideoModes);
×
NEW
771
    windowSizes_ = VIDEODRIVER.GetDefaultWindowSizes();
×
NEW
772
    std::sort(windowSizes_.begin(), windowSizes_.end(), cmpVideoModes);
×
UNCOV
773
}
×
774

775
void dskOptions::Msg_ScreenResize(const ScreenResizeEvent& sr)
×
776
{
777
    Desktop::Msg_ScreenResize(sr);
×
778
    updateGuiScale();
×
NEW
779
    updateWindowSizeComboBox();
×
UNCOV
780
}
×
781

782
bool dskOptions::Msg_WheelUp(const MouseCoords& mc)
×
783
{
784
    if(VIDEODRIVER.GetModKeyState().ctrl)
×
785
    {
786
        scrollGuiScale(true);
×
787
        return true;
×
788
    } else
789
        return Desktop::Msg_WheelUp(mc);
×
790
}
791

792
bool dskOptions::Msg_WheelDown(const MouseCoords& mc)
×
793
{
794
    if(VIDEODRIVER.GetModKeyState().ctrl)
×
795
    {
796
        scrollGuiScale(false);
×
797
        return true;
×
798
    } else
799
        return Desktop::Msg_WheelDown(mc);
×
800
}
801

802
void dskOptions::updateGuiScale()
×
803
{
804
    // generate GUI scale percentages in 10% increments
805
    constexpr auto stepSize = 10u;
×
806
    const auto roundGuiScale = [=](unsigned percent) {
×
807
        return helpers::iround<unsigned>(static_cast<float>(percent) / stepSize) * stepSize;
×
808
    };
809

810
    const auto range = VIDEODRIVER.getGuiScaleRange();
×
811
    const auto recommendedPercentRounded = roundGuiScale(range.recommendedPercent);
×
812
    auto* combo = GetCtrl<ctrlGroup>(ID_grpGraphics)->GetCtrl<ctrlComboBox>(ID_cbGuiScale);
×
813

814
    guiScales_.clear();
×
815
    combo->DeleteAllItems();
×
816

817
    guiScales_.push_back(0);
×
NEW
818
    combo->AddItem(helpers::format(_("Auto (%u%%)"), range.recommendedPercent));
×
819
    if(SETTINGS.video.guiScale == 0)
×
820
        combo->SetSelection(0);
×
821

822
    for(unsigned percent = roundGuiScale(range.minPercent); percent <= range.maxPercent; percent += stepSize)
×
823
    {
824
        if(percent == recommendedPercentRounded)
×
825
            recommendedGuiScaleIndex_ = guiScales_.size();
×
826
        guiScales_.push_back(percent);
×
827

NEW
828
        combo->AddItem(helpers::toString(percent) + "%");
×
829
        if(percent == SETTINGS.video.guiScale)
×
830
            combo->SetSelection(combo->GetNumItems() - 1);
×
831
    }
832

833
    // if GUI scale exceeds maximum, lower it to keep UI elements on screen
834
    if(SETTINGS.video.guiScale > guiScales_.back())
×
835
    {
836
        combo->SetSelection(combo->GetNumItems() - 1);
×
837
        SETTINGS.video.guiScale = guiScales_.back();
×
838
        VIDEODRIVER.setGuiScalePercent(SETTINGS.video.guiScale);
×
839
    }
840
}
×
841

842
void dskOptions::scrollGuiScale(bool up)
×
843
{
844
    auto* combo = GetCtrl<ctrlGroup>(ID_grpGraphics)->GetCtrl<ctrlComboBox>(ID_cbGuiScale);
×
845
    const auto& selection = combo->GetSelection();
×
846
    unsigned newSelection = 0;
×
847
    if(!selection || *selection == 0) // No selection or "Auto" item selected
×
848
        newSelection = recommendedGuiScaleIndex_;
×
849
    else
850
        newSelection = std::clamp<unsigned>(*selection + (up ? 1 : -1), 1, combo->GetNumItems() - 1);
×
851

852
    if(newSelection != selection)
×
853
    {
854
        combo->SetSelection(newSelection);
×
855
        SETTINGS.video.guiScale = guiScales_[newSelection];
×
856
        VIDEODRIVER.setGuiScalePercent(SETTINGS.video.guiScale);
×
857
    }
858
}
×
859

860
void dskOptions::updatePortraitControls()
×
861
{
862
    const auto& newPortrait = Portraits[SETTINGS.lobby.portraitIndex];
×
863
    auto* groupCommon = GetCtrl<ctrlGroup>(ID_grpCommon);
×
864

865
    auto* portraitButton = groupCommon->GetCtrl<ctrlImageButton>(ID_btCommonPortrait);
×
866
    auto* newPortraitTexture = LOADER.GetTextureN(newPortrait.resourceId, newPortrait.resourceIndex);
×
867
    portraitButton->SetImage(newPortraitTexture);
×
868

869
    auto* portraitCombo = groupCommon->GetCtrl<ctrlComboBox>(ID_cbCommonPortrait);
×
870
    portraitCombo->SetSelection(SETTINGS.lobby.portraitIndex);
×
871
}
×
872

NEW
873
void dskOptions::updateWindowSizeComboBox()
×
874
{
875
    auto* cbWindowSize =
NEW
876
      GetCtrl<ctrlGroup>(ID_grpGraphics)->GetCtrl<ctrlGroup>(ID_grpWindowSize)->GetCtrl<ctrlComboBox>(ID_cbWindowSize);
×
877

878
    const VideoMode currentSize =
NEW
879
      VIDEODRIVER.GetDisplayMode() == DisplayMode::Windowed ? VIDEODRIVER.GetWindowSize() : SETTINGS.video.windowedSize;
×
NEW
880
    s25util::ClassicImbuedStream<std::ostringstream> curStr;
×
NEW
881
    curStr << currentSize.width << "x" << currentSize.height;
×
NEW
882
    cbWindowSize->SetText(0, curStr.str());
×
883
    // Not found == -1 -> First entry selected
NEW
884
    cbWindowSize->SetSelection(static_cast<unsigned>(helpers::indexOf(windowSizes_, currentSize) + 1));
×
NEW
885
}
×
886

NEW
887
void dskOptions::updateResolutionGroups()
×
888
{
NEW
889
    const auto currentDisplayMode = SETTINGS.video.displayMode;
×
NEW
890
    auto& grpGraphics = *GetCtrl<ctrlGroup>(ID_grpGraphics);
×
NEW
891
    grpGraphics.GetCtrl<ctrlGroup>(ID_grpResolution)->SetVisible(currentDisplayMode == DisplayMode::Fullscreen);
×
NEW
892
    grpGraphics.GetCtrl<ctrlGroup>(ID_grpWindowSize)->SetVisible(currentDisplayMode == DisplayMode::Windowed);
×
NEW
893
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc