~ppsspp/ppsspp/ppsspp_1.3.0

« back to all changes in this revision

Viewing changes to UI/GameSettingsScreen.cpp

  • Committer: Sérgio Benjamim
  • Date: 2017-01-02 00:12:05 UTC
  • Revision ID: sergio_br2@yahoo.com.br-20170102001205-cxbta9za203nmjwm
1.3.0 source (from ppsspp_1.3.0-r160.p5.l1762.a165.t83~56~ubuntu16.04.1.tar.xz).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (c) 2013- PPSSPP Project.
 
2
 
 
3
// This program is free software: you can redistribute it and/or modify
 
4
// it under the terms of the GNU General Public License as published by
 
5
// the Free Software Foundation, version 2.0 or later versions.
 
6
 
 
7
// This program is distributed in the hope that it will be useful,
 
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
// GNU General Public License 2.0 for more details.
 
11
 
 
12
// A copy of the GPL 2.0 should have been included with the program.
 
13
// If not, see http://www.gnu.org/licenses/
 
14
 
 
15
// Official git repository and contact information can be found at
 
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
 
17
 
 
18
#include "base/display.h"  // Only to check screen aspect ratio with pixel_yres/pixel_xres
 
19
 
 
20
#include "base/colorutil.h"
 
21
#include "base/timeutil.h"
 
22
#include "math/curves.h"
 
23
#include "gfx_es2/gpu_features.h"
 
24
#include "gfx_es2/draw_buffer.h"
 
25
#include "i18n/i18n.h"
 
26
#include "ui/view.h"
 
27
#include "ui/viewgroup.h"
 
28
#include "ui/ui_context.h"
 
29
#include "UI/EmuScreen.h"
 
30
#include "UI/GameSettingsScreen.h"
 
31
#include "UI/GameInfoCache.h"
 
32
#include "UI/GamepadEmu.h"
 
33
#include "UI/MiscScreens.h"
 
34
#include "UI/ControlMappingScreen.h"
 
35
#include "UI/DevScreens.h"
 
36
#include "UI/DisplayLayoutScreen.h"
 
37
#include "UI/RemoteISOScreen.h"
 
38
#include "UI/SavedataScreen.h"
 
39
#include "UI/TouchControlLayoutScreen.h"
 
40
#include "UI/TouchControlVisibilityScreen.h"
 
41
#include "UI/TiltAnalogSettingsScreen.h"
 
42
#include "UI/TiltEventProcessor.h"
 
43
#include "UI/ComboKeyMappingScreen.h"
 
44
 
 
45
#include "Common/KeyMap.h"
 
46
#include "Common/FileUtil.h"
 
47
#include "Core/Config.h"
 
48
#include "Core/Host.h"
 
49
#include "Core/System.h"
 
50
#include "Core/Reporting.h"
 
51
#include "android/jni/TestRunner.h"
 
52
#include "GPU/GPUInterface.h"
 
53
#include "GPU/GLES/Framebuffer.h"
 
54
 
 
55
#if defined(_WIN32)
 
56
#pragma warning(disable:4091)  // workaround bug in VS2015 headers
 
57
#include "Windows/MainWindow.h"
 
58
#include <shlobj.h>
 
59
#include "util/text/utf8.h"
 
60
#include "Windows/W32Util/ShellUtil.h"
 
61
#include "Windows/W32Util/Misc.h"
 
62
 
 
63
#endif
 
64
 
 
65
#ifdef IOS
 
66
extern bool iosCanUseJit;
 
67
extern bool targetIsJailbroken;
 
68
#endif
 
69
 
 
70
GameSettingsScreen::GameSettingsScreen(std::string gamePath, std::string gameID, bool editThenRestore)
 
71
        : UIDialogScreenWithGameBackground(gamePath), gameID_(gameID), enableReports_(false), editThenRestore_(editThenRestore) {
 
72
        lastVertical_ = UseVerticalLayout();
 
73
}
 
74
 
 
75
bool GameSettingsScreen::UseVerticalLayout() const {
 
76
        return dp_yres > dp_xres * 1.1f;
 
77
}
 
78
 
 
79
void GameSettingsScreen::CreateViews() {
 
80
        GameInfo *info = g_gameInfoCache->GetInfo(NULL, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE);
 
81
 
 
82
        if (editThenRestore_) {
 
83
                g_Config.loadGameConfig(gameID_);
 
84
        }
 
85
 
 
86
        cap60FPS_ = g_Config.iForceMaxEmulatedFPS == 60;
 
87
 
 
88
        iAlternateSpeedPercent_ = (g_Config.iFpsLimit * 100) / 60;
 
89
 
 
90
        bool vertical = UseVerticalLayout();
 
91
 
 
92
        // Information in the top left.
 
93
        // Back button to the bottom left.
 
94
        // Scrolling action menu to the right.
 
95
        using namespace UI;
 
96
 
 
97
        I18NCategory *di = GetI18NCategory("Dialog");
 
98
        I18NCategory *gr = GetI18NCategory("Graphics");
 
99
        I18NCategory *co = GetI18NCategory("Controls");
 
100
        I18NCategory *a = GetI18NCategory("Audio");
 
101
        I18NCategory *sa = GetI18NCategory("Savedata");
 
102
        I18NCategory *sy = GetI18NCategory("System");
 
103
        I18NCategory *n = GetI18NCategory("Networking");
 
104
        I18NCategory *ms = GetI18NCategory("MainSettings");
 
105
        I18NCategory *dev = GetI18NCategory("Developer");
 
106
 
 
107
        root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT));
 
108
 
 
109
        TabHolder *tabHolder;
 
110
        if (vertical) {
 
111
                LinearLayout *verticalLayout = new LinearLayout(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, FILL_PARENT));
 
112
                tabHolder = new TabHolder(ORIENT_HORIZONTAL, 200, new LinearLayoutParams(1.0f));
 
113
                verticalLayout->Add(tabHolder);
 
114
                verticalLayout->Add(new Choice(di->T("Back"), "", false, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 0.0f, Margins(0))))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
 
115
                root_->Add(verticalLayout);
 
116
        } else {
 
117
                tabHolder = new TabHolder(ORIENT_VERTICAL, 200, new AnchorLayoutParams(10, 0, 10, 0, false));
 
118
                root_->Add(tabHolder);
 
119
                AddStandardBack(root_);
 
120
        }
 
121
        tabHolder->SetTag("GameSettings");
 
122
        root_->SetDefaultFocusView(tabHolder);
 
123
 
 
124
        float leftSide = 40.0f;
 
125
        if (!vertical) {
 
126
                leftSide += 200.0f;
 
127
        }
 
128
        settingInfo_ = new SettingInfoMessage(ALIGN_CENTER | FLAG_WRAP_TEXT, new AnchorLayoutParams(dp_xres - leftSide - 40.0f, WRAP_CONTENT, leftSide, dp_yres - 80.0f - 40.0f, NONE, NONE));
 
129
        settingInfo_->SetBottomCutoff(dp_yres - 200.0f);
 
130
        root_->Add(settingInfo_);
 
131
 
 
132
        // TODO: These currently point to global settings, not game specific ones.
 
133
 
 
134
        // Graphics
 
135
        ViewGroup *graphicsSettingsScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
 
136
        graphicsSettingsScroll->SetTag("GameSettingsGraphics");
 
137
        LinearLayout *graphicsSettings = new LinearLayout(ORIENT_VERTICAL);
 
138
        graphicsSettings->SetSpacing(0);
 
139
        graphicsSettingsScroll->Add(graphicsSettings);
 
140
        tabHolder->AddTab(ms->T("Graphics"), graphicsSettingsScroll);
 
141
 
 
142
        graphicsSettings->Add(new ItemHeader(gr->T("Rendering Mode")));
 
143
        static const char *renderingBackend[] = { "OpenGL", "Direct3D 9", "Direct3D 11", "Vulkan (experimental)" };
 
144
        PopupMultiChoice *renderingBackendChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iGPUBackend, gr->T("Backend"), renderingBackend, GPU_BACKEND_OPENGL, ARRAY_SIZE(renderingBackend), gr->GetName(), screenManager()));
 
145
        renderingBackendChoice->OnChoice.Handle(this, &GameSettingsScreen::OnRenderingBackend);
 
146
#if !defined(_WIN32)
 
147
        renderingBackendChoice->HideChoice(1);  // D3D9
 
148
        renderingBackendChoice->HideChoice(2);  // D3D11
 
149
#else
 
150
        renderingBackendChoice->HideChoice(2);  // D3D11
 
151
#endif
 
152
#if !defined(_WIN32)
 
153
        // TODO: Add dynamic runtime check for Vulkan support on Android
 
154
        renderingBackendChoice->HideChoice(3);
 
155
#endif
 
156
        static const char *renderingMode[] = { "Non-Buffered Rendering", "Buffered Rendering", "Read Framebuffers To Memory (CPU)", "Read Framebuffers To Memory (GPU)"};
 
157
        PopupMultiChoice *renderingModeChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iRenderingMode, gr->T("Mode"), renderingMode, 0, ARRAY_SIZE(renderingMode), gr->GetName(), screenManager()));
 
158
        renderingModeChoice->OnChoice.Add([=](EventParams &e) {
 
159
                switch (g_Config.iRenderingMode) {
 
160
                case FB_NON_BUFFERED_MODE:
 
161
                        settingInfo_->Show(gr->T("RenderingMode NonBuffered Tip", "Faster, but nothing may draw in some games"), e.v);
 
162
                        break;
 
163
                case FB_BUFFERED_MODE:
 
164
                        break;
 
165
#ifndef USING_GLES2
 
166
                case FB_READFBOMEMORY_CPU:
 
167
#endif
 
168
                case FB_READFBOMEMORY_GPU:
 
169
                        settingInfo_->Show(gr->T("RenderingMode ReadFromMemory Tip", "Causes crashes in many games, not recommended"), e.v);
 
170
                        break;
 
171
                }
 
172
                return UI::EVENT_CONTINUE;
 
173
        });
 
174
        renderingModeChoice->OnChoice.Handle(this, &GameSettingsScreen::OnRenderingMode);
 
175
        renderingModeChoice->SetDisabledPtr(&g_Config.bSoftwareRendering);
 
176
        CheckBox *blockTransfer = graphicsSettings->Add(new CheckBox(&g_Config.bBlockTransferGPU, gr->T("Simulate Block Transfer", "Simulate Block Transfer (unfinished)")));
 
177
        blockTransfer->SetDisabledPtr(&g_Config.bSoftwareRendering);
 
178
 
 
179
        graphicsSettings->Add(new ItemHeader(gr->T("Frame Rate Control")));
 
180
        static const char *frameSkip[] = {"Off", "1", "2", "3", "4", "5", "6", "7", "8"};
 
181
        graphicsSettings->Add(new PopupMultiChoice(&g_Config.iFrameSkip, gr->T("Frame Skipping"), frameSkip, 0, ARRAY_SIZE(frameSkip), gr->GetName(), screenManager()));
 
182
        frameSkipAuto_ = graphicsSettings->Add(new CheckBox(&g_Config.bAutoFrameSkip, gr->T("Auto FrameSkip")));
 
183
        frameSkipAuto_->OnClick.Handle(this, &GameSettingsScreen::OnAutoFrameskip);
 
184
        graphicsSettings->Add(new CheckBox(&cap60FPS_, gr->T("Force max 60 FPS (helps GoW)")));
 
185
 
 
186
        PopupSliderChoice *altSpeed = graphicsSettings->Add(new PopupSliderChoice(&iAlternateSpeedPercent_, 0, 600, gr->T("Alternative Speed", "Alternative speed"), 5, screenManager(), gr->T("%, 0:unlimited")));
 
187
        altSpeed->SetFormat("%i%%");
 
188
        altSpeed->SetZeroLabel(gr->T("Unlimited"));
 
189
 
 
190
        graphicsSettings->Add(new ItemHeader(gr->T("Features")));
 
191
        I18NCategory *ps = GetI18NCategory("PostShaders");
 
192
        postProcChoice_ = graphicsSettings->Add(new ChoiceWithValueDisplay(&g_Config.sPostShaderName, gr->T("Postprocessing Shader"), ps->GetName()));
 
193
        postProcChoice_->OnClick.Handle(this, &GameSettingsScreen::OnPostProcShader);
 
194
        postProcEnable_ = !g_Config.bSoftwareRendering && (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE);
 
195
        postProcChoice_->SetEnabledPtr(&postProcEnable_);
 
196
 
 
197
#if !defined(MOBILE_DEVICE)
 
198
        graphicsSettings->Add(new CheckBox(&g_Config.bFullScreen, gr->T("FullScreen")))->OnClick.Handle(this, &GameSettingsScreen::OnFullscreenChange);
 
199
#endif
 
200
        // Display Layout Editor: To avoid overlapping touch controls on large tablets, meet geeky demands for integer zoom/unstretched image etc.
 
201
        displayEditor_ = graphicsSettings->Add(new Choice(gr->T("Display layout editor")));
 
202
        displayEditor_->OnClick.Handle(this, &GameSettingsScreen::OnDisplayLayoutEditor);
 
203
 
 
204
#ifdef ANDROID
 
205
        // Hide Immersive Mode on pre-kitkat Android
 
206
        if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 19) {
 
207
                graphicsSettings->Add(new CheckBox(&g_Config.bImmersiveMode, gr->T("Immersive Mode")))->OnClick.Handle(this, &GameSettingsScreen::OnImmersiveModeChange);
 
208
        }
 
209
#endif
 
210
 
 
211
        graphicsSettings->Add(new ItemHeader(gr->T("Performance")));
 
212
#ifndef MOBILE_DEVICE
 
213
        static const char *internalResolutions[] = {"Auto (1:1)", "1x PSP", "2x PSP", "3x PSP", "4x PSP", "5x PSP", "6x PSP", "7x PSP", "8x PSP", "9x PSP", "10x PSP" };
 
214
#else
 
215
        static const char *internalResolutions[] = {"Auto (1:1)", "1x PSP", "2x PSP", "3x PSP", "4x PSP", "5x PSP" };
 
216
#endif
 
217
        resolutionChoice_ = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iInternalResolution, gr->T("Rendering Resolution"), internalResolutions, 0, ARRAY_SIZE(internalResolutions), gr->GetName(), screenManager()));
 
218
        resolutionChoice_->OnChoice.Handle(this, &GameSettingsScreen::OnResolutionChange);
 
219
        resolutionEnable_ = !g_Config.bSoftwareRendering && (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE);
 
220
        resolutionChoice_->SetEnabledPtr(&resolutionEnable_);
 
221
 
 
222
#ifdef ANDROID
 
223
        static const char *deviceResolutions[] = { "Native device resolution", "Auto (same as Rendering)", "1x PSP", "2x PSP", "3x PSP", "4x PSP", "5x PSP" };
 
224
        int max_res_temp = std::max(System_GetPropertyInt(SYSPROP_DISPLAY_XRES), System_GetPropertyInt(SYSPROP_DISPLAY_YRES)) / 480 + 2;
 
225
        if (max_res_temp == 3)
 
226
                max_res_temp = 4;  // At least allow 2x
 
227
        int max_res = std::min(max_res_temp, (int)ARRAY_SIZE(deviceResolutions));
 
228
        UI::PopupMultiChoice *hwscale = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iAndroidHwScale, gr->T("Display Resolution (HW scaler)"), deviceResolutions, 0, max_res, gr->GetName(), screenManager()));
 
229
        hwscale->OnChoice.Handle(this, &GameSettingsScreen::OnHwScaleChange);  // To refresh the display mode
 
230
#endif
 
231
 
 
232
#ifdef _WIN32
 
233
        graphicsSettings->Add(new CheckBox(&g_Config.bVSync, gr->T("VSync")));
 
234
#endif
 
235
        CheckBox *mipmapping = graphicsSettings->Add(new CheckBox(&g_Config.bMipMap, gr->T("Mipmapping")));
 
236
        mipmapping->SetDisabledPtr(&g_Config.bSoftwareRendering);
 
237
 
 
238
        CheckBox *hwTransform = graphicsSettings->Add(new CheckBox(&g_Config.bHardwareTransform, gr->T("Hardware Transform")));
 
239
        hwTransform->OnClick.Handle(this, &GameSettingsScreen::OnHardwareTransform);
 
240
        hwTransform->SetDisabledPtr(&g_Config.bSoftwareRendering);
 
241
 
 
242
        CheckBox *swSkin = graphicsSettings->Add(new CheckBox(&g_Config.bSoftwareSkinning, gr->T("Software Skinning")));
 
243
        swSkin->SetDisabledPtr(&g_Config.bSoftwareRendering);
 
244
 
 
245
        CheckBox *vtxCache = graphicsSettings->Add(new CheckBox(&g_Config.bVertexCache, gr->T("Vertex Cache")));
 
246
        vtxCache->OnClick.Add([=](EventParams &e) {
 
247
                settingInfo_->Show(gr->T("VertexCache Tip", "Faster, but may cause temporary flicker"), e.v);
 
248
                return UI::EVENT_CONTINUE;
 
249
        });
 
250
        vtxCacheEnable_ = !g_Config.bSoftwareRendering && g_Config.bHardwareTransform;
 
251
        vtxCache->SetEnabledPtr(&vtxCacheEnable_);
 
252
 
 
253
        CheckBox *texBackoff = graphicsSettings->Add(new CheckBox(&g_Config.bTextureBackoffCache, gr->T("Lazy texture caching", "Lazy texture caching (speedup)")));
 
254
        texBackoff->SetDisabledPtr(&g_Config.bSoftwareRendering);
 
255
 
 
256
        CheckBox *texSecondary_ = graphicsSettings->Add(new CheckBox(&g_Config.bTextureSecondaryCache, gr->T("Retain changed textures", "Retain changed textures (speedup, mem hog)")));
 
257
        texSecondary_->OnClick.Add([=](EventParams &e) {
 
258
                settingInfo_->Show(gr->T("RetainChangedTextures Tip", "Makes many games slower, but some games a lot faster"), e.v);
 
259
                return UI::EVENT_CONTINUE;
 
260
        });
 
261
        texSecondary_->SetDisabledPtr(&g_Config.bSoftwareRendering);
 
262
 
 
263
        CheckBox *framebufferSlowEffects = graphicsSettings->Add(new CheckBox(&g_Config.bDisableSlowFramebufEffects, gr->T("Disable slower effects (speedup)")));
 
264
        framebufferSlowEffects->SetDisabledPtr(&g_Config.bSoftwareRendering);
 
265
 
 
266
        // Seems solid, so we hide the setting.
 
267
        // CheckBox *vtxJit = graphicsSettings->Add(new CheckBox(&g_Config.bVertexDecoderJit, gr->T("Vertex Decoder JIT")));
 
268
 
 
269
        // if (PSP_IsInited()) {
 
270
                // vtxJit->SetEnabled(false);
 
271
        // }
 
272
 
 
273
        static const char *quality[] = { "Low", "Medium", "High"};
 
274
        PopupMultiChoice *beziersChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iSplineBezierQuality, gr->T("LowCurves", "Spline/Bezier curves quality"), quality, 0, ARRAY_SIZE(quality), gr->GetName(), screenManager()));
 
275
        beziersChoice->SetDisabledPtr(&g_Config.bSoftwareRendering);
 
276
 
 
277
        // In case we're going to add few other antialiasing option like MSAA in the future.
 
278
        // graphicsSettings->Add(new CheckBox(&g_Config.bFXAA, gr->T("FXAA")));
 
279
        graphicsSettings->Add(new ItemHeader(gr->T("Texture Scaling")));
 
280
#ifndef MOBILE_DEVICE
 
281
        static const char *texScaleLevelsNPOT[] = {"Auto", "Off", "2x", "3x", "4x", "5x"};
 
282
#else
 
283
        static const char *texScaleLevelsNPOT[] = {"Auto", "Off", "2x", "3x"};
 
284
#endif
 
285
 
 
286
        static const char **texScaleLevels = texScaleLevelsNPOT;
 
287
        static int numTexScaleLevels = ARRAY_SIZE(texScaleLevelsNPOT);
 
288
        PopupMultiChoice *texScalingChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iTexScalingLevel, gr->T("Upscale Level"), texScaleLevels, 0, numTexScaleLevels, gr->GetName(), screenManager()));
 
289
        // TODO: Better check?  When it won't work, it scales down anyway.
 
290
        if (!gl_extensions.OES_texture_npot && GetGPUBackend() == GPUBackend::OPENGL) {
 
291
                texScalingChoice->HideChoice(3); // 3x
 
292
                texScalingChoice->HideChoice(5); // 5x
 
293
        }
 
294
        texScalingChoice->OnChoice.Add([=](EventParams &e) {
 
295
                if (g_Config.iTexScalingLevel != 1) {
 
296
                        settingInfo_->Show(gr->T("UpscaleLevel Tip", "CPU heavy - some scaling may be delayed to avoid stutter"), e.v);
 
297
                }
 
298
                return UI::EVENT_CONTINUE;
 
299
        });
 
300
        texScalingChoice->SetDisabledPtr(&g_Config.bSoftwareRendering);
 
301
 
 
302
        static const char *texScaleAlgos[] = { "xBRZ", "Hybrid", "Bicubic", "Hybrid + Bicubic", };
 
303
        PopupMultiChoice *texScalingType = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iTexScalingType, gr->T("Upscale Type"), texScaleAlgos, 0, ARRAY_SIZE(texScaleAlgos), gr->GetName(), screenManager()));
 
304
        texScalingType->SetDisabledPtr(&g_Config.bSoftwareRendering);
 
305
 
 
306
        CheckBox *deposterize = graphicsSettings->Add(new CheckBox(&g_Config.bTexDeposterize, gr->T("Deposterize")));
 
307
        deposterize->SetDisabledPtr(&g_Config.bSoftwareRendering);
 
308
 
 
309
        graphicsSettings->Add(new ItemHeader(gr->T("Texture Filtering")));
 
310
        static const char *anisoLevels[] = { "Off", "2x", "4x", "8x", "16x" };
 
311
        PopupMultiChoice *anisoFiltering = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iAnisotropyLevel, gr->T("Anisotropic Filtering"), anisoLevels, 0, ARRAY_SIZE(anisoLevels), gr->GetName(), screenManager()));
 
312
        anisoFiltering->SetDisabledPtr(&g_Config.bSoftwareRendering);
 
313
 
 
314
        static const char *texFilters[] = { "Auto", "Nearest", "Linear", "Linear on FMV", };
 
315
        PopupMultiChoice *texFilter = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iTexFiltering, gr->T("Texture Filter"), texFilters, 1, ARRAY_SIZE(texFilters), gr->GetName(), screenManager()));
 
316
        texFilter->SetDisabledPtr(&g_Config.bSoftwareRendering);
 
317
 
 
318
        static const char *bufFilters[] = { "Linear", "Nearest", };
 
319
        graphicsSettings->Add(new PopupMultiChoice(&g_Config.iBufFilter, gr->T("Screen Scaling Filter"), bufFilters, 1, ARRAY_SIZE(bufFilters), gr->GetName(), screenManager()));
 
320
 
 
321
#ifdef ANDROID
 
322
        graphicsSettings->Add(new ItemHeader(gr->T("Cardboard Settings", "Cardboard Settings")));
 
323
        CheckBox *cardboardMode = graphicsSettings->Add(new CheckBox(&g_Config.bEnableCardboard, gr->T("Enable Cardboard", "Enable Cardboard")));
 
324
        cardboardMode->SetDisabledPtr(&g_Config.bSoftwareRendering);
 
325
        PopupSliderChoice * cardboardScreenSize = graphicsSettings->Add(new PopupSliderChoice(&g_Config.iCardboardScreenSize, 30, 100, gr->T("Cardboard Screen Size", "Screen Size (in % of the viewport)"), 1, screenManager(), gr->T("% of viewport")));
 
326
        cardboardScreenSize->SetDisabledPtr(&g_Config.bSoftwareRendering);
 
327
        PopupSliderChoice *cardboardXShift = graphicsSettings->Add(new PopupSliderChoice(&g_Config.iCardboardXShift, -100, 100, gr->T("Cardboard Screen X Shift", "X Shift (in % of the void)"), 1, screenManager(), gr->T("% of the void")));
 
328
        cardboardXShift->SetDisabledPtr(&g_Config.bSoftwareRendering);
 
329
        PopupSliderChoice *cardboardYShift = graphicsSettings->Add(new PopupSliderChoice(&g_Config.iCardboardYShift, -100, 100, gr->T("Cardboard Screen Y Shift", "Y Shift (in % of the void)"), 1, screenManager(), gr->T("% of the void")));
 
330
        cardboardYShift->SetDisabledPtr(&g_Config.bSoftwareRendering);
 
331
#endif
 
332
 
 
333
        graphicsSettings->Add(new ItemHeader(gr->T("Hack Settings", "Hack Settings (these WILL cause glitches)")));
 
334
        graphicsSettings->Add(new CheckBox(&g_Config.bTimerHack, gr->T("Timer Hack")));
 
335
        CheckBox *alphaHack = graphicsSettings->Add(new CheckBox(&g_Config.bDisableAlphaTest, gr->T("Disable Alpha Test (PowerVR speedup)")));
 
336
        alphaHack->OnClick.Add([=](EventParams &e) {
 
337
                settingInfo_->Show(gr->T("DisableAlphaTest Tip", "Faster by sometimes drawing ugly boxes around things"), e.v);
 
338
                return UI::EVENT_CONTINUE;
 
339
        });
 
340
        alphaHack->OnClick.Handle(this, &GameSettingsScreen::OnShaderChange);
 
341
        alphaHack->SetDisabledPtr(&g_Config.bSoftwareRendering);
 
342
 
 
343
        CheckBox *stencilTest = graphicsSettings->Add(new CheckBox(&g_Config.bDisableStencilTest, gr->T("Disable Stencil Test")));
 
344
        stencilTest->SetDisabledPtr(&g_Config.bSoftwareRendering);
 
345
 
 
346
        CheckBox *depthWrite = graphicsSettings->Add(new CheckBox(&g_Config.bAlwaysDepthWrite, gr->T("Always Depth Write")));
 
347
        depthWrite->SetDisabledPtr(&g_Config.bSoftwareRendering);
 
348
 
 
349
        graphicsSettings->Add(new CheckBox(&g_Config.bPrescaleUV, gr->T("Texture Coord Speedhack")));
 
350
        depthWrite->SetDisabledPtr(&g_Config.bSoftwareRendering);
 
351
 
 
352
        static const char *bloomHackOptions[] = { "Off", "Safe", "Balanced", "Aggressive" };
 
353
        PopupMultiChoice *bloomHack = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iBloomHack, gr->T("Lower resolution for effects (reduces artifacts)"), bloomHackOptions, 0, ARRAY_SIZE(bloomHackOptions), gr->GetName(), screenManager()));
 
354
        bloomHackEnable_ = !g_Config.bSoftwareRendering && (g_Config.iInternalResolution != 1);
 
355
        bloomHack->SetEnabledPtr(&bloomHackEnable_);
 
356
 
 
357
        graphicsSettings->Add(new ItemHeader(gr->T("Overlay Information")));
 
358
        static const char *fpsChoices[] = {
 
359
                "None", "Speed", "FPS", "Both"
 
360
#ifdef BLACKBERRY
 
361
     , "Statistics"
 
362
#endif
 
363
        };
 
364
        graphicsSettings->Add(new PopupMultiChoice(&g_Config.iShowFPSCounter, gr->T("Show FPS Counter"), fpsChoices, 0, ARRAY_SIZE(fpsChoices), gr->GetName(), screenManager()));
 
365
        graphicsSettings->Add(new CheckBox(&g_Config.bShowDebugStats, gr->T("Show Debug Statistics")))->OnClick.Handle(this, &GameSettingsScreen::OnJitAffectingSetting);
 
366
 
 
367
        // Developer tools are not accessible ingame, so it goes here.
 
368
        graphicsSettings->Add(new ItemHeader(gr->T("Debugging")));
 
369
        Choice *dump = graphicsSettings->Add(new Choice(gr->T("Dump next frame to log")));
 
370
        dump->OnClick.Handle(this, &GameSettingsScreen::OnDumpNextFrameToLog);
 
371
        if (!PSP_IsInited())
 
372
                dump->SetEnabled(false);
 
373
 
 
374
        // We normally use software rendering to debug so put it in debugging.
 
375
        CheckBox *softwareGPU = graphicsSettings->Add(new CheckBox(&g_Config.bSoftwareRendering, gr->T("Software Rendering", "Software Rendering (experimental)")));
 
376
        softwareGPU->OnClick.Add([=](EventParams &e) {
 
377
                settingInfo_->Show(gr->T("SoftGPU Tip", "Currently VERY slow"), e.v);
 
378
                return UI::EVENT_CONTINUE;
 
379
        });
 
380
        softwareGPU->OnClick.Handle(this, &GameSettingsScreen::OnSoftwareRendering);
 
381
 
 
382
        if (PSP_IsInited())
 
383
                softwareGPU->SetEnabled(false);
 
384
 
 
385
        // Audio
 
386
        ViewGroup *audioSettingsScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
 
387
        audioSettingsScroll->SetTag("GameSettingsAudio");
 
388
        LinearLayout *audioSettings = new LinearLayout(ORIENT_VERTICAL);
 
389
        audioSettings->SetSpacing(0);
 
390
        audioSettingsScroll->Add(audioSettings);
 
391
        tabHolder->AddTab(ms->T("Audio"), audioSettingsScroll);
 
392
 
 
393
        audioSettings->Add(new ItemHeader(ms->T("Audio")));
 
394
 
 
395
        audioSettings->Add(new CheckBox(&g_Config.bEnableSound, a->T("Enable Sound")));
 
396
 
 
397
        PopupSliderChoice *volume = audioSettings->Add(new PopupSliderChoice(&g_Config.iGlobalVolume, VOLUME_OFF, VOLUME_MAX, a->T("Global volume"), screenManager()));
 
398
        volume->SetEnabledPtr(&g_Config.bEnableSound);
 
399
 
 
400
#ifdef _WIN32
 
401
        if (IsVistaOrHigher()) {
 
402
                static const char *backend[] = { "Auto", "DSound (compatible)", "WASAPI (fast)" };
 
403
                PopupMultiChoice *audioBackend = audioSettings->Add(new PopupMultiChoice(&g_Config.iAudioBackend, a->T("Audio backend", "Audio backend (restart req.)"), backend, 0, ARRAY_SIZE(backend), a->GetName(), screenManager()));
 
404
                audioBackend->SetEnabledPtr(&g_Config.bEnableSound);
 
405
        }
 
406
#endif
 
407
 
 
408
        static const char *latency[] = { "Low", "Medium", "High" };
 
409
        PopupMultiChoice *lowAudio = audioSettings->Add(new PopupMultiChoice(&g_Config.iAudioLatency, a->T("Audio Latency"), latency, 0, ARRAY_SIZE(latency), gr->GetName(), screenManager()));
 
410
 
 
411
        lowAudio->SetEnabledPtr(&g_Config.bEnableSound);
 
412
        if (System_GetPropertyInt(SYSPROP_AUDIO_SAMPLE_RATE) == 44100) {
 
413
                CheckBox *resampling = audioSettings->Add(new CheckBox(&g_Config.bAudioResampler, a->T("Audio sync", "Audio sync (resampling)")));
 
414
                resampling->SetEnabledPtr(&g_Config.bEnableSound);
 
415
        }
 
416
 
 
417
        audioSettings->Add(new ItemHeader(a->T("Audio hacks")));
 
418
        audioSettings->Add(new CheckBox(&g_Config.bSoundSpeedHack, a->T("Sound speed hack (DOA etc.)")));
 
419
 
 
420
        // Control
 
421
        ViewGroup *controlsSettingsScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
 
422
        controlsSettingsScroll->SetTag("GameSettingsControls");
 
423
        LinearLayout *controlsSettings = new LinearLayout(ORIENT_VERTICAL);
 
424
        controlsSettings->SetSpacing(0);
 
425
        controlsSettingsScroll->Add(controlsSettings);
 
426
        tabHolder->AddTab(ms->T("Controls"), controlsSettingsScroll);
 
427
        controlsSettings->Add(new ItemHeader(ms->T("Controls")));
 
428
        controlsSettings->Add(new Choice(co->T("Control Mapping")))->OnClick.Handle(this, &GameSettingsScreen::OnControlMapping);
 
429
 
 
430
#if defined(USING_WIN_UI)
 
431
        controlsSettings->Add(new CheckBox(&g_Config.bGamepadOnlyFocused, co->T("Ignore gamepads when not focused")));
 
432
#endif
 
433
 
 
434
#if defined(MOBILE_DEVICE)
 
435
        controlsSettings->Add(new CheckBox(&g_Config.bHapticFeedback, co->T("HapticFeedback", "Haptic Feedback (vibration)")));
 
436
        static const char *tiltTypes[] = { "None (Disabled)", "Analog Stick", "D-PAD", "PSP Action Buttons", "L/R Trigger Buttons"};
 
437
        controlsSettings->Add(new PopupMultiChoice(&g_Config.iTiltInputType, co->T("Tilt Input Type"), tiltTypes, 0, ARRAY_SIZE(tiltTypes), co->GetName(), screenManager()))->OnClick.Handle(this, &GameSettingsScreen::OnTiltTypeChange);
 
438
 
 
439
        Choice *customizeTilt = controlsSettings->Add(new Choice(co->T("Customize tilt")));
 
440
        customizeTilt->OnClick.Handle(this, &GameSettingsScreen::OnTiltCustomize);
 
441
        customizeTilt->SetEnabledPtr((bool *)&g_Config.iTiltInputType); //<- dirty int-to-bool cast
 
442
#endif
 
443
 
 
444
        // TVs don't have touch control, at least not yet.
 
445
        if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) != DEVICE_TYPE_TV) {
 
446
                controlsSettings->Add(new ItemHeader(co->T("OnScreen", "On-Screen Touch Controls")));
 
447
                controlsSettings->Add(new CheckBox(&g_Config.bShowTouchControls, co->T("OnScreen", "On-Screen Touch Controls")));
 
448
                layoutEditorChoice_ = controlsSettings->Add(new Choice(co->T("Custom layout...")));
 
449
                layoutEditorChoice_->OnClick.Handle(this, &GameSettingsScreen::OnTouchControlLayout);
 
450
                layoutEditorChoice_->SetEnabledPtr(&g_Config.bShowTouchControls);
 
451
 
 
452
                // Re-centers itself to the touch location on touch-down.
 
453
                CheckBox *floatingAnalog = controlsSettings->Add(new CheckBox(&g_Config.bAutoCenterTouchAnalog, co->T("Auto-centering analog stick")));
 
454
                floatingAnalog->SetEnabledPtr(&g_Config.bShowTouchControls);
 
455
 
 
456
                // Combo key setup
 
457
                Choice *comboKey = controlsSettings->Add(new Choice(co->T("Combo Key Setup")));
 
458
                comboKey->OnClick.Handle(this, &GameSettingsScreen::OnCombo_key);
 
459
                comboKey->SetEnabledPtr(&g_Config.bShowTouchControls);
 
460
 
 
461
                // On systems that aren't Symbian, iOS, and Maemo, offer to let the user see this button.
 
462
                // Some Windows touch devices don't have a back button or other button to call up the menu.
 
463
#if !defined(__SYMBIAN32__) && !defined(IOS) && !defined(MAEMO)
 
464
                CheckBox *enablePauseBtn = controlsSettings->Add(new CheckBox(&g_Config.bShowTouchPause, co->T("Show Touch Pause Menu Button")));
 
465
 
 
466
                // Don't allow the user to disable it once in-game, so they can't lock themselves out of the menu.
 
467
                if (!PSP_IsInited()) {
 
468
                        enablePauseBtn->SetEnabledPtr(&g_Config.bShowTouchControls);
 
469
                } else {
 
470
                        enablePauseBtn->SetEnabled(false);
 
471
                }
 
472
#endif
 
473
 
 
474
                CheckBox *disableDiags = controlsSettings->Add(new CheckBox(&g_Config.bDisableDpadDiagonals, co->T("Disable D-Pad diagonals (4-way touch)")));
 
475
                disableDiags->SetEnabledPtr(&g_Config.bShowTouchControls);
 
476
                PopupSliderChoice *opacity = controlsSettings->Add(new PopupSliderChoice(&g_Config.iTouchButtonOpacity, 0, 100, co->T("Button Opacity"), screenManager(), "%"));
 
477
                opacity->SetEnabledPtr(&g_Config.bShowTouchControls);
 
478
                opacity->SetFormat("%i%%");
 
479
                PopupSliderChoice *autoHide = controlsSettings->Add(new PopupSliderChoice(&g_Config.iTouchButtonHideSeconds, 0, 300, co->T("Auto-hide buttons after seconds"), screenManager(), co->T("seconds, 0 : off")));
 
480
                autoHide->SetEnabledPtr(&g_Config.bShowTouchControls);
 
481
                autoHide->SetFormat("%is");
 
482
                autoHide->SetZeroLabel(co->T("Off"));
 
483
                static const char *touchControlStyles[] = {"Classic", "Thin borders"};
 
484
                View *style = controlsSettings->Add(new PopupMultiChoice(&g_Config.iTouchButtonStyle, co->T("Button style"), touchControlStyles, 0, ARRAY_SIZE(touchControlStyles), co->GetName(), screenManager()));
 
485
                style->SetEnabledPtr(&g_Config.bShowTouchControls);
 
486
        }
 
487
 
 
488
#ifdef _WIN32
 
489
        static const char *inverseDeadzoneModes[] = { "Off", "X", "Y", "X + Y" };
 
490
 
 
491
        controlsSettings->Add(new ItemHeader(co->T("DInput Analog Settings", "DInput Analog Settings")));
 
492
        controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fDInputAnalogDeadzone, 0.0f, 1.0f, co->T("Deadzone Radius"), 0.01f, screenManager(), "/ 1.0"));
 
493
        controlsSettings->Add(new PopupMultiChoice(&g_Config.iDInputAnalogInverseMode, co->T("Analog Mapper Mode"), inverseDeadzoneModes, 0, ARRAY_SIZE(inverseDeadzoneModes), co->GetName(), screenManager()));
 
494
        controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fDInputAnalogInverseDeadzone, 0.0f, 1.0f, co->T("Analog Mapper Low End", "Analog Mapper Low End (Inverse Deadzone)"), 0.01f, screenManager(), "/ 1.0"));
 
495
        controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fDInputAnalogSensitivity, 0.0f, 10.0f, co->T("Analog Mapper High End", "Analog Mapper High End (Axis Sensitivity)"), 0.01f, screenManager(), "x"));
 
496
 
 
497
        controlsSettings->Add(new ItemHeader(co->T("XInput Analog Settings", "XInput Analog Settings")));
 
498
        controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fXInputAnalogDeadzone, 0.0f, 1.0f, co->T("Deadzone Radius"), 0.01f, screenManager(), "/ 1.0"));
 
499
        controlsSettings->Add(new PopupMultiChoice(&g_Config.iXInputAnalogInverseMode, co->T("Analog Mapper Mode"), inverseDeadzoneModes, 0, ARRAY_SIZE(inverseDeadzoneModes), co->GetName(), screenManager()));
 
500
        controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fXInputAnalogInverseDeadzone, 0.0f, 1.0f, co->T("Analog Mapper Low End", "Analog Mapper Low End (Inverse Deadzone)"), 0.01f, screenManager(), "/ 1.0"));
 
501
        controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fXInputAnalogSensitivity, 0.0f, 10.0f, co->T("Analog Mapper High End", "Analog Mapper High End (Axis Sensitivity)"), 0.01f, screenManager(), "x"));
 
502
#endif
 
503
 
 
504
        controlsSettings->Add(new ItemHeader(co->T("Keyboard", "Keyboard Control Settings")));
 
505
#if defined(USING_WIN_UI)
 
506
        controlsSettings->Add(new CheckBox(&g_Config.bIgnoreWindowsKey, co->T("Ignore Windows Key")));
 
507
#endif // #if defined(USING_WIN_UI)
 
508
        auto analogLimiter = new PopupSliderChoiceFloat(&g_Config.fAnalogLimiterDeadzone, 0.0f, 1.0f, co->T("Analog Limiter"), 0.10f, screenManager(), "/ 1.0");
 
509
        controlsSettings->Add(analogLimiter);
 
510
        analogLimiter->OnChange.Add([=](EventParams &e) {
 
511
                settingInfo_->Show(co->T("AnalogLimiter Tip", "When the analog limiter button is pressed"), e.v);
 
512
                return UI::EVENT_CONTINUE;
 
513
        });
 
514
 
 
515
        ViewGroup *networkingSettingsScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
 
516
        networkingSettingsScroll->SetTag("GameSettingsNetworking");
 
517
        LinearLayout *networkingSettings = new LinearLayout(ORIENT_VERTICAL);
 
518
        networkingSettings->SetSpacing(0);
 
519
        networkingSettingsScroll->Add(networkingSettings);
 
520
        tabHolder->AddTab(ms->T("Networking"), networkingSettingsScroll);
 
521
 
 
522
        networkingSettings->Add(new ItemHeader(ms->T("Networking")));
 
523
 
 
524
        networkingSettings->Add(new Choice(n->T("Adhoc Multiplayer forum")))->OnClick.Handle(this, &GameSettingsScreen::OnAdhocGuides);
 
525
 
 
526
        networkingSettings->Add(new CheckBox(&g_Config.bEnableWlan, n->T("Enable networking", "Enable networking/wlan (beta)")));
 
527
 
 
528
#ifdef _WIN32
 
529
        networkingSettings->Add(new PopupTextInputChoice(&g_Config.proAdhocServer, n->T("Change proAdhocServer Address"), "", 255, screenManager()));
 
530
#elif defined(ANDROID)
 
531
        networkingSettings->Add(new ChoiceWithValueDisplay(&g_Config.proAdhocServer, n->T("Change proAdhocServer Address"), nullptr))->OnClick.Handle(this, &GameSettingsScreen::OnChangeproAdhocServerAddress);
 
532
#else
 
533
        networkingSettings->Add(new ChoiceWithValueDisplay(&g_Config.proAdhocServer, n->T("Change proAdhocServer Address"), nullptr))->OnClick.Handle(this, &GameSettingsScreen::OnChangeproAdhocServerAddress);
 
534
#endif
 
535
        networkingSettings->Add(new CheckBox(&g_Config.bEnableAdhocServer, n->T("Enable built-in PRO Adhoc Server", "Enable built-in PRO Adhoc Server")));
 
536
        networkingSettings->Add(new ChoiceWithValueDisplay(&g_Config.sMACAddress, n->T("Change Mac Address"), nullptr))->OnClick.Handle(this, &GameSettingsScreen::OnChangeMacAddress);
 
537
        networkingSettings->Add(new PopupSliderChoice(&g_Config.iPortOffset, 0, 60000, n->T("Port offset", "Port offset(0 = PSP compatibility)"), 100, screenManager()));
 
538
 
 
539
        ViewGroup *toolsScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
 
540
        toolsScroll->SetTag("GameSettingsTools");
 
541
        LinearLayout *tools = new LinearLayout(ORIENT_VERTICAL);
 
542
        tools->SetSpacing(0);
 
543
        toolsScroll->Add(tools);
 
544
        tabHolder->AddTab(ms->T("Tools"), toolsScroll);
 
545
 
 
546
        tools->Add(new ItemHeader(ms->T("Tools")));
 
547
        // These were moved here so use the wrong translation objects, to avoid having to change all inis... This isn't a sustainable situation :P
 
548
        tools->Add(new Choice(sa->T("Savedata Manager")))->OnClick.Handle(this, &GameSettingsScreen::OnSavedataManager);
 
549
        tools->Add(new Choice(dev->T("System Information")))->OnClick.Handle(this, &GameSettingsScreen::OnSysInfo);
 
550
        tools->Add(new Choice(sy->T("Developer Tools")))->OnClick.Handle(this, &GameSettingsScreen::OnDeveloperTools);
 
551
        tools->Add(new Choice(sy->T("Remote disc streaming")))->OnClick.Handle(this, &GameSettingsScreen::OnRemoteISO);
 
552
 
 
553
        // System
 
554
        ViewGroup *systemSettingsScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
 
555
        systemSettingsScroll->SetTag("GameSettingsSystem");
 
556
        LinearLayout *systemSettings = new LinearLayout(ORIENT_VERTICAL);
 
557
        systemSettings->SetSpacing(0);
 
558
        systemSettingsScroll->Add(systemSettings);
 
559
        tabHolder->AddTab(ms->T("System"), systemSettingsScroll);
 
560
 
 
561
        systemSettings->Add(new ItemHeader(sy->T("UI Language")));
 
562
        systemSettings->Add(new Choice(dev->T("Language", "Language")))->OnClick.Handle(this, &GameSettingsScreen::OnLanguage);
 
563
 
 
564
        systemSettings->Add(new ItemHeader(sy->T("Help the PPSSPP team")));
 
565
        enableReports_ = Reporting::IsEnabled();
 
566
        enableReportsCheckbox_ = new CheckBox(&enableReports_, sy->T("Enable Compatibility Server Reports"));
 
567
        enableReportsCheckbox_->SetEnabled(Reporting::IsSupported());
 
568
        systemSettings->Add(enableReportsCheckbox_);
 
569
 
 
570
        systemSettings->Add(new ItemHeader(sy->T("Emulation")));
 
571
 
 
572
        systemSettings->Add(new CheckBox(&g_Config.bFastMemory, sy->T("Fast Memory", "Fast Memory (Unstable)")))->OnClick.Handle(this, &GameSettingsScreen::OnJitAffectingSetting);
 
573
 
 
574
        auto separateCPUThread = new CheckBox(&g_Config.bSeparateCPUThread, sy->T("Multithreaded (experimental)"));
 
575
        systemSettings->Add(separateCPUThread);
 
576
        separateCPUThread->OnClick.Add([=](EventParams &e) {
 
577
                settingInfo_->Show(sy->T("Mulithreaded Tip", "Not always faster, causes glitches/crashing"), e.v);
 
578
                return UI::EVENT_CONTINUE;
 
579
        });
 
580
        systemSettings->Add(new CheckBox(&g_Config.bSeparateIOThread, sy->T("I/O on thread (experimental)")))->SetEnabled(!PSP_IsInited());
 
581
        static const char *ioTimingMethods[] = { "Fast (lag on slow storage)", "Host (bugs, less lag)", "Simulate UMD delays" };
 
582
        View *ioTimingMethod = systemSettings->Add(new PopupMultiChoice(&g_Config.iIOTimingMethod, sy->T("IO timing method"), ioTimingMethods, 0, ARRAY_SIZE(ioTimingMethods), sy->GetName(), screenManager()));
 
583
        ioTimingMethod->SetEnabledPtr(&g_Config.bSeparateIOThread);
 
584
        systemSettings->Add(new CheckBox(&g_Config.bForceLagSync, sy->T("Force real clock sync (slower, less lag)")));
 
585
        PopupSliderChoice *lockedMhz = systemSettings->Add(new PopupSliderChoice(&g_Config.iLockedCPUSpeed, 0, 1000, sy->T("Change CPU Clock", "Change CPU Clock (unstable)"), screenManager(), sy->T("MHz, 0:default")));
 
586
        lockedMhz->SetZeroLabel(sy->T("Auto"));
 
587
        PopupSliderChoice *rewindFreq = systemSettings->Add(new PopupSliderChoice(&g_Config.iRewindFlipFrequency, 0, 1800, sy->T("Rewind Snapshot Frequency", "Rewind Snapshot Frequency (mem hog)"), screenManager(), sy->T("frames, 0:off")));
 
588
        rewindFreq->SetZeroLabel(sy->T("Off"));
 
589
 
 
590
        systemSettings->Add(new CheckBox(&g_Config.bMemStickInserted, sy->T("Memory Stick inserted")));
 
591
 
 
592
        systemSettings->Add(new ItemHeader(sy->T("General")));
 
593
 
 
594
#ifdef ANDROID
 
595
        if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_MOBILE) {
 
596
                static const char *screenRotation[] = {"Auto", "Landscape", "Portrait", "Landscape Reversed", "Portrait Reversed"};
 
597
                PopupMultiChoice *rot = systemSettings->Add(new PopupMultiChoice(&g_Config.iScreenRotation, co->T("Screen Rotation"), screenRotation, 0, ARRAY_SIZE(screenRotation), co->GetName(), screenManager()));
 
598
                rot->OnChoice.Handle(this, &GameSettingsScreen::OnScreenRotation);
 
599
        }
 
600
#endif
 
601
 
 
602
        systemSettings->Add(new CheckBox(&g_Config.bCheckForNewVersion, sy->T("VersionCheck", "Check for new versions of PPSSPP")));
 
603
        if (g_Config.iMaxRecent > 0)
 
604
                systemSettings->Add(new Choice(sy->T("Clear Recent Games List")))->OnClick.Handle(this, &GameSettingsScreen::OnClearRecents);
 
605
        systemSettings->Add(new Choice(sy->T("Restore Default Settings")))->OnClick.Handle(this, &GameSettingsScreen::OnRestoreDefaultSettings);
 
606
        systemSettings->Add(new CheckBox(&g_Config.bEnableAutoLoad, sy->T("Auto Load Newest Savestate")));
 
607
 
 
608
#if defined(USING_WIN_UI)
 
609
        systemSettings->Add(new CheckBox(&g_Config.bBypassOSKWithKeyboard, sy->T("Enable Windows native keyboard", "Enable Windows native keyboard")));
 
610
#endif
 
611
#if defined(_WIN32)
 
612
        SavePathInMyDocumentChoice = systemSettings->Add(new CheckBox(&installed_, sy->T("Save path in My Documents", "Save path in My Documents")));
 
613
        SavePathInMyDocumentChoice->OnClick.Handle(this, &GameSettingsScreen::OnSavePathMydoc);
 
614
        SavePathInOtherChoice = systemSettings->Add(new CheckBox(&otherinstalled_, sy->T("Save path in installed.txt", "Save path in installed.txt")));
 
615
        SavePathInOtherChoice->SetEnabled(false);
 
616
        SavePathInOtherChoice->OnClick.Handle(this, &GameSettingsScreen::OnSavePathOther);
 
617
        wchar_t myDocumentsPath[MAX_PATH];
 
618
        const HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, myDocumentsPath);
 
619
        const std::string PPSSPPpath = File::GetExeDirectory();
 
620
        const std::string installedFile = PPSSPPpath + "installed.txt";
 
621
        installed_ = File::Exists(installedFile);
 
622
        otherinstalled_ = false;
 
623
        if (!installed_ && result == S_OK) {
 
624
                if (File::CreateEmptyFile(PPSSPPpath + "installedTEMP.txt")) {
 
625
                        // Disable the setting whether cannot create & delete file
 
626
                        if (!(File::Delete(PPSSPPpath + "installedTEMP.txt")))
 
627
                                SavePathInMyDocumentChoice->SetEnabled(false);
 
628
                        else
 
629
                                SavePathInOtherChoice->SetEnabled(true);
 
630
                } else
 
631
                        SavePathInMyDocumentChoice->SetEnabled(false);
 
632
        } else {
 
633
                if (installed_ && (result == S_OK)) {
 
634
                        std::ifstream inputFile(ConvertUTF8ToWString(installedFile));
 
635
                        if (!inputFile.fail() && inputFile.is_open()) {
 
636
                                std::string tempString;
 
637
                                std::getline(inputFile, tempString);
 
638
 
 
639
                                // Skip UTF-8 encoding bytes if there are any. There are 3 of them.
 
640
                                if (tempString.substr(0, 3) == "\xEF\xBB\xBF")
 
641
                                        tempString = tempString.substr(3);
 
642
                                SavePathInOtherChoice->SetEnabled(true);
 
643
                                if (!(tempString == "")) {
 
644
                                        installed_ = false;
 
645
                                        otherinstalled_ = true;
 
646
                                }
 
647
                        }
 
648
                        inputFile.close();
 
649
                } else if (result != S_OK)
 
650
                        SavePathInMyDocumentChoice->SetEnabled(false);
 
651
        }
 
652
#endif
 
653
 
 
654
#if defined(_M_X64)
 
655
        systemSettings->Add(new CheckBox(&g_Config.bCacheFullIsoInRam, sy->T("Cache ISO in RAM", "Cache full ISO in RAM")));
 
656
#endif
 
657
 
 
658
//#ifndef ANDROID
 
659
        systemSettings->Add(new ItemHeader(sy->T("Cheats", "Cheats (experimental, see forums)")));
 
660
        systemSettings->Add(new CheckBox(&g_Config.bEnableCheats, sy->T("Enable Cheats")));
 
661
//#endif
 
662
        systemSettings->SetSpacing(0);
 
663
 
 
664
        systemSettings->Add(new ItemHeader(sy->T("PSP Settings")));
 
665
        static const char *models[] = {"PSP-1000" , "PSP-2000/3000"};
 
666
        systemSettings->Add(new PopupMultiChoice(&g_Config.iPSPModel, sy->T("PSP Model"), models, 0, ARRAY_SIZE(models), sy->GetName(), screenManager()))->SetEnabled(!PSP_IsInited());
 
667
        // TODO: Come up with a way to display a keyboard for mobile users,
 
668
        // so until then, this is Windows/Desktop only.
 
669
#if defined(_WIN32)  // TODO: Add all platforms where KEY_CHAR support is added
 
670
        systemSettings->Add(new PopupTextInputChoice(&g_Config.sNickName, sy->T("Change Nickname"), "", 32, screenManager()));
 
671
#elif defined(USING_QT_UI)
 
672
        systemSettings->Add(new Choice(sy->T("Change Nickname")))->OnClick.Handle(this, &GameSettingsScreen::OnChangeNickname);
 
673
#elif defined(ANDROID)
 
674
        systemSettings->Add(new ChoiceWithValueDisplay(&g_Config.sNickName, sy->T("Change Nickname"), nullptr))->OnClick.Handle(this, &GameSettingsScreen::OnChangeNickname);
 
675
#endif
 
676
#if defined(_WIN32) || (defined(USING_QT_UI) && !defined(MOBILE_DEVICE))
 
677
        // Screenshot functionality is not yet available on non-Windows/non-Qt
 
678
        systemSettings->Add(new CheckBox(&g_Config.bScreenshotsAsPNG, sy->T("Screenshots as PNG")));
 
679
        systemSettings->Add(new CheckBox(&g_Config.bDumpFrames, sy->T("Record Display")));
 
680
        systemSettings->Add(new CheckBox(&g_Config.bUseFFV1, sy->T("Use Lossless Video Codec (FFV1)")));
 
681
        systemSettings->Add(new CheckBox(&g_Config.bDumpAudio, sy->T("Record Audio")));
 
682
#endif
 
683
        systemSettings->Add(new CheckBox(&g_Config.bDayLightSavings, sy->T("Day Light Saving")));
 
684
        static const char *dateFormat[] = { "YYYYMMDD", "MMDDYYYY", "DDMMYYYY"};
 
685
        systemSettings->Add(new PopupMultiChoice(&g_Config.iDateFormat, sy->T("Date Format"), dateFormat, 1, 3, sy->GetName(), screenManager()));
 
686
        static const char *timeFormat[] = { "12HR", "24HR"};
 
687
        systemSettings->Add(new PopupMultiChoice(&g_Config.iTimeFormat, sy->T("Time Format"), timeFormat, 1, 2, sy->GetName(), screenManager()));
 
688
        static const char *buttonPref[] = { "Use O to confirm", "Use X to confirm" };
 
689
        systemSettings->Add(new PopupMultiChoice(&g_Config.iButtonPreference, sy->T("Confirmation Button"), buttonPref, 0, 2, sy->GetName(), screenManager()));
 
690
}
 
691
 
 
692
UI::EventReturn GameSettingsScreen::OnAutoFrameskip(UI::EventParams &e) {
 
693
        if (g_Config.bAutoFrameSkip && g_Config.iFrameSkip == 0) {
 
694
                g_Config.iFrameSkip = 1;
 
695
        }
 
696
        if (g_Config.bAutoFrameSkip && g_Config.iRenderingMode == FB_NON_BUFFERED_MODE) {
 
697
                g_Config.iRenderingMode = FB_BUFFERED_MODE;
 
698
        }
 
699
        return UI::EVENT_DONE;
 
700
}
 
701
 
 
702
UI::EventReturn GameSettingsScreen::OnSoftwareRendering(UI::EventParams &e) {
 
703
        vtxCacheEnable_ = !g_Config.bSoftwareRendering && g_Config.bHardwareTransform;
 
704
        postProcEnable_ = !g_Config.bSoftwareRendering && (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE);
 
705
        resolutionEnable_ = !g_Config.bSoftwareRendering && (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE);
 
706
        return UI::EVENT_DONE;
 
707
}
 
708
 
 
709
UI::EventReturn GameSettingsScreen::OnHardwareTransform(UI::EventParams &e) {
 
710
        vtxCacheEnable_ = !g_Config.bSoftwareRendering && g_Config.bHardwareTransform;
 
711
        return UI::EVENT_DONE;
 
712
}
 
713
 
 
714
UI::EventReturn GameSettingsScreen::OnScreenRotation(UI::EventParams &e) {
 
715
        ILOG("New display rotation: %d", g_Config.iScreenRotation);
 
716
        ILOG("Sending rotate");
 
717
        System_SendMessage("rotate", "");
 
718
        ILOG("Got back from rotate");
 
719
        return UI::EVENT_DONE;
 
720
}
 
721
 
 
722
static void RecreateActivity() {
 
723
        const int SYSTEM_JELLYBEAN = 16;
 
724
        if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= SYSTEM_JELLYBEAN) {
 
725
                ILOG("Sending recreate");
 
726
                System_SendMessage("recreate", "");
 
727
                ILOG("Got back from recreate");
 
728
        } else {
 
729
                I18NCategory *gr = GetI18NCategory("Graphics");
 
730
                System_SendMessage("toast", gr->T("Must Restart", "You must restart PPSSPP for this change to take effect"));
 
731
        }
 
732
}
 
733
 
 
734
UI::EventReturn GameSettingsScreen::OnAdhocGuides(UI::EventParams &e) {
 
735
        LaunchBrowser("http://forums.ppsspp.org/forumdisplay.php?fid=34");
 
736
        return UI::EVENT_DONE;
 
737
}
 
738
 
 
739
UI::EventReturn GameSettingsScreen::OnImmersiveModeChange(UI::EventParams &e) {
 
740
        System_SendMessage("immersive", "");
 
741
        const int SYSTEM_JELLYBEAN = 16;
 
742
        // recreate doesn't seem reliable on earlier versions.
 
743
        if (g_Config.iAndroidHwScale != 0) {
 
744
                RecreateActivity();
 
745
        }
 
746
        return UI::EVENT_DONE;
 
747
}
 
748
 
 
749
UI::EventReturn GameSettingsScreen::OnRenderingMode(UI::EventParams &e) {
 
750
        // We do not want to report when rendering mode is Framebuffer to memory - so many issues
 
751
        // are caused by that (framebuffer copies overwriting display lists, etc).
 
752
        Reporting::UpdateConfig();
 
753
        enableReports_ = Reporting::IsEnabled();
 
754
        enableReportsCheckbox_->SetEnabled(Reporting::IsSupported());
 
755
 
 
756
        postProcEnable_ = !g_Config.bSoftwareRendering && (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE);
 
757
        resolutionEnable_ = !g_Config.bSoftwareRendering && (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE);
 
758
 
 
759
        if (g_Config.iRenderingMode == FB_NON_BUFFERED_MODE) {
 
760
                g_Config.bAutoFrameSkip = false;
 
761
        }
 
762
        return UI::EVENT_DONE;
 
763
}
 
764
 
 
765
UI::EventReturn GameSettingsScreen::OnJitAffectingSetting(UI::EventParams &e) {
 
766
        NativeMessageReceived("clear jit", "");
 
767
        return UI::EVENT_DONE;
 
768
}
 
769
 
 
770
#ifdef _WIN32
 
771
 
 
772
UI::EventReturn GameSettingsScreen::OnSavePathMydoc(UI::EventParams &e) {
 
773
        const std::string PPSSPPpath = File::GetExeDirectory();
 
774
        const std::string installedFile = PPSSPPpath + "installed.txt";
 
775
        installed_ = File::Exists(installedFile);
 
776
        if (otherinstalled_) {
 
777
                File::Delete(PPSSPPpath + "installed.txt");
 
778
                File::CreateEmptyFile(PPSSPPpath + "installed.txt");
 
779
                otherinstalled_ = false;
 
780
                wchar_t myDocumentsPath[MAX_PATH];
 
781
                const HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, myDocumentsPath);
 
782
                const std::string myDocsPath = ConvertWStringToUTF8(myDocumentsPath) + "/PPSSPP/";
 
783
                g_Config.memStickDirectory = myDocsPath;
 
784
        }
 
785
        else if (installed_) {
 
786
                File::Delete(PPSSPPpath + "installed.txt");
 
787
                installed_ = false;
 
788
                g_Config.memStickDirectory = PPSSPPpath + "memstick/";
 
789
        }
 
790
        else {
 
791
                std::ofstream myfile;
 
792
                myfile.open(PPSSPPpath + "installed.txt");
 
793
                if (myfile.is_open()){
 
794
                        myfile.close();
 
795
                }
 
796
 
 
797
                wchar_t myDocumentsPath[MAX_PATH];
 
798
                const HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, myDocumentsPath);
 
799
                const std::string myDocsPath = ConvertWStringToUTF8(myDocumentsPath) + "/PPSSPP/";
 
800
                g_Config.memStickDirectory = myDocsPath;
 
801
                installed_ = true;
 
802
        }
 
803
        return UI::EVENT_DONE;
 
804
}
 
805
 
 
806
UI::EventReturn GameSettingsScreen::OnSavePathOther(UI::EventParams &e) {
 
807
        const std::string PPSSPPpath = File::GetExeDirectory();
 
808
        if (otherinstalled_) {
 
809
                I18NCategory *di = GetI18NCategory("Dialog");
 
810
                std::string folder = W32Util::BrowseForFolder(MainWindow::GetHWND(), di->T("Choose PPSSPP save folder"));
 
811
                if (folder.size()) {
 
812
                        g_Config.memStickDirectory = folder;
 
813
                        FILE *f = File::OpenCFile(PPSSPPpath + "installed.txt", "wb");
 
814
                        if (f) {
 
815
                                std::string utfstring("\xEF\xBB\xBF");
 
816
                                utfstring.append(folder);
 
817
                                fwrite(utfstring.c_str(), 1, utfstring.length(), f);
 
818
                                fclose(f);
 
819
                        }
 
820
                        installed_ = false;
 
821
                }
 
822
                else
 
823
                        otherinstalled_ = false;
 
824
        }
 
825
        else {
 
826
                File::Delete(PPSSPPpath + "installed.txt");
 
827
                SavePathInMyDocumentChoice->SetEnabled(true);
 
828
                otherinstalled_ = false;
 
829
                installed_ = false;
 
830
                g_Config.memStickDirectory = PPSSPPpath + "memstick/";
 
831
        }
 
832
        return UI::EVENT_DONE;
 
833
}
 
834
 
 
835
#endif
 
836
 
 
837
UI::EventReturn GameSettingsScreen::OnClearRecents(UI::EventParams &e) {
 
838
        g_Config.recentIsos.clear();
 
839
        OnRecentChanged.Trigger(e);
 
840
        return UI::EVENT_DONE;
 
841
}
 
842
 
 
843
UI::EventReturn GameSettingsScreen::OnReloadCheats(UI::EventParams &e) {
 
844
        // Hmm, strange mechanism.
 
845
        g_Config.bReloadCheats = true;
 
846
        return UI::EVENT_DONE;
 
847
}
 
848
 
 
849
UI::EventReturn GameSettingsScreen::OnFullscreenChange(UI::EventParams &e) {
 
850
#if defined(USING_WIN_UI) || defined(USING_QT_UI)
 
851
        host->GoFullscreen(g_Config.bFullScreen);
 
852
#else
 
853
        // SDL, basically.
 
854
        System_SendMessage("toggle_fullscreen", "");
 
855
#endif
 
856
        return UI::EVENT_DONE;
 
857
}
 
858
 
 
859
UI::EventReturn GameSettingsScreen::OnDisplayLayoutEditor(UI::EventParams &e) {
 
860
        screenManager()->push(new DisplayLayoutScreen());
 
861
        return UI::EVENT_DONE;
 
862
};
 
863
 
 
864
UI::EventReturn GameSettingsScreen::OnResolutionChange(UI::EventParams &e) {
 
865
        if (gpu) {
 
866
                gpu->Resized();
 
867
        }
 
868
        if (g_Config.iAndroidHwScale == 1) {
 
869
                RecreateActivity();
 
870
        }
 
871
        Reporting::UpdateConfig();
 
872
        return UI::EVENT_DONE;
 
873
}
 
874
 
 
875
UI::EventReturn GameSettingsScreen::OnHwScaleChange(UI::EventParams &e) {
 
876
        RecreateActivity();
 
877
        return UI::EVENT_DONE;
 
878
}
 
879
 
 
880
UI::EventReturn GameSettingsScreen::OnShaderChange(UI::EventParams &e) {
 
881
        if (gpu) {
 
882
                gpu->ClearShaderCache();
 
883
        }
 
884
        return UI::EVENT_DONE;
 
885
}
 
886
 
 
887
UI::EventReturn GameSettingsScreen::OnDumpNextFrameToLog(UI::EventParams &e) {
 
888
        if (gpu) {
 
889
                gpu->DumpNextFrame();
 
890
        }
 
891
        return UI::EVENT_DONE;
 
892
}
 
893
 
 
894
void GameSettingsScreen::update(InputState &input) {
 
895
        UIScreen::update(input);
 
896
        g_Config.iForceMaxEmulatedFPS = cap60FPS_ ? 60 : 0;
 
897
 
 
898
        g_Config.iFpsLimit = (iAlternateSpeedPercent_ * 60) / 100;
 
899
 
 
900
        bool vertical = UseVerticalLayout();
 
901
        if (vertical != lastVertical_) {
 
902
                RecreateViews();
 
903
                lastVertical_ = vertical;
 
904
        }
 
905
}
 
906
 
 
907
void GameSettingsScreen::sendMessage(const char *message, const char *value) {
 
908
        // Always call the base class method first to handle the most common messages.
 
909
        UIDialogScreenWithBackground::sendMessage(message, value);
 
910
 
 
911
        if (!strcmp(message, "control mapping")) {
 
912
                UpdateUIState(UISTATE_MENU);
 
913
                screenManager()->push(new ControlMappingScreen());
 
914
        }
 
915
        if (!strcmp(message, "display layout editor")) {
 
916
                UpdateUIState(UISTATE_MENU);
 
917
                screenManager()->push(new DisplayLayoutScreen());
 
918
        }
 
919
}
 
920
 
 
921
void GameSettingsScreen::onFinish(DialogResult result) {
 
922
        if (g_Config.bEnableSound) {
 
923
                if (PSP_IsInited() && !IsAudioInitialised())
 
924
                        Audio_Init();
 
925
        }
 
926
 
 
927
        Reporting::Enable(enableReports_, "report.ppsspp.org");
 
928
        Reporting::UpdateConfig();
 
929
        g_Config.Save();
 
930
        if (editThenRestore_) {
 
931
                g_Config.unloadGameConfig();
 
932
        }
 
933
 
 
934
        host->UpdateUI();
 
935
 
 
936
        KeyMap::UpdateNativeMenuKeys();
 
937
}
 
938
 
 
939
/*
 
940
void GlobalSettingsScreen::CreateViews() {
 
941
        using namespace UI;
 
942
        root_ = new ScrollView(ORIENT_VERTICAL);
 
943
 
 
944
        enableReports_ = Reporting::IsEnabled();
 
945
}*/
 
946
 
 
947
void GameSettingsScreen::CallbackRenderingBackend(bool yes) {
 
948
#if defined(_WIN32)
 
949
        // If the user ends up deciding not to restart, set the config back to the current backend
 
950
        // so it doesn't get switched by accident.
 
951
        if (yes) {
 
952
                g_Config.bRestartRequired = true;
 
953
                PostMessage(MainWindow::GetHWND(), WM_CLOSE, 0, 0);
 
954
        } else {
 
955
                g_Config.iGPUBackend = (int)GetGPUBackend();
 
956
        }
 
957
#endif
 
958
}
 
959
 
 
960
UI::EventReturn GameSettingsScreen::OnRenderingBackend(UI::EventParams &e) {
 
961
#if defined(_WIN32)
 
962
        I18NCategory *di = GetI18NCategory("Dialog");
 
963
 
 
964
        // It only makes sense to show the restart prompt if the backend was actually changed.
 
965
        if (g_Config.iGPUBackend != (int)GetGPUBackend()) {
 
966
                screenManager()->push(new PromptScreen(di->T("ChangingGPUBackends", "Changing GPU backends requires PPSSPP to restart. Restart now?"), di->T("Yes"), di->T("No"),
 
967
                        std::bind(&GameSettingsScreen::CallbackRenderingBackend, this, placeholder::_1)));
 
968
        }
 
969
#endif
 
970
        return UI::EVENT_DONE;
 
971
}
 
972
 
 
973
UI::EventReturn GameSettingsScreen::OnChangeNickname(UI::EventParams &e) {
 
974
#if defined(_WIN32) || defined(USING_QT_UI)
 
975
        const size_t name_len = 256;
 
976
 
 
977
        char name[name_len];
 
978
        memset(name, 0, sizeof(name));
 
979
 
 
980
        if (System_InputBoxGetString("Enter a new PSP nickname", g_Config.sNickName.c_str(), name, name_len)) {
 
981
                g_Config.sNickName = name;
 
982
        }
 
983
#elif defined(ANDROID)
 
984
        System_SendMessage("inputbox", ("nickname:" + g_Config.sNickName).c_str());
 
985
#endif
 
986
        return UI::EVENT_DONE;
 
987
}
 
988
 
 
989
UI::EventReturn GameSettingsScreen::OnChangeproAdhocServerAddress(UI::EventParams &e) {
 
990
#if defined(_WIN32) || defined(USING_QT_UI)
 
991
        if (!g_Config.bFullScreen) {
 
992
                const size_t name_len = 256;
 
993
 
 
994
                char name[name_len];
 
995
                memset(name, 0, sizeof(name));
 
996
 
 
997
                if (System_InputBoxGetString("Enter an IP address", g_Config.proAdhocServer.c_str(), name, name_len)) {
 
998
                        g_Config.proAdhocServer = name;
 
999
                }
 
1000
        }
 
1001
        else
 
1002
                screenManager()->push(new ProAdhocServerScreen);
 
1003
#elif defined(ANDROID)
 
1004
        System_SendMessage("inputbox", ("IP:" + g_Config.proAdhocServer).c_str());
 
1005
#else
 
1006
        screenManager()->push(new ProAdhocServerScreen);
 
1007
#endif
 
1008
 
 
1009
        return UI::EVENT_DONE;
 
1010
}
 
1011
 
 
1012
UI::EventReturn GameSettingsScreen::OnChangeMacAddress(UI::EventParams &e) {
 
1013
        g_Config.sMACAddress = std::string(CreateRandMAC());
 
1014
 
 
1015
        return UI::EVENT_DONE;
 
1016
}
 
1017
 
 
1018
UI::EventReturn GameSettingsScreen::OnCombo_key(UI::EventParams &e) {
 
1019
        screenManager()->push(new Combo_keyScreen(&g_Config.iComboMode));
 
1020
        return UI::EVENT_DONE;
 
1021
}
 
1022
 
 
1023
UI::EventReturn GameSettingsScreen::OnLanguage(UI::EventParams &e) {
 
1024
        I18NCategory *dev = GetI18NCategory("Developer");
 
1025
        auto langScreen = new NewLanguageScreen(dev->T("Language"));
 
1026
        langScreen->OnChoice.Handle(this, &GameSettingsScreen::OnLanguageChange);
 
1027
        screenManager()->push(langScreen);
 
1028
        return UI::EVENT_DONE;
 
1029
}
 
1030
 
 
1031
UI::EventReturn GameSettingsScreen::OnLanguageChange(UI::EventParams &e) {
 
1032
        screenManager()->RecreateAllViews();
 
1033
 
 
1034
        if (host) {
 
1035
                host->UpdateUI();
 
1036
        }
 
1037
        return UI::EVENT_DONE;
 
1038
}
 
1039
 
 
1040
UI::EventReturn GameSettingsScreen::OnPostProcShader(UI::EventParams &e) {
 
1041
        I18NCategory *gr = GetI18NCategory("Graphics");
 
1042
        auto procScreen = new PostProcScreen(gr->T("Postprocessing Shader"));
 
1043
        procScreen->OnChoice.Handle(this, &GameSettingsScreen::OnPostProcShaderChange);
 
1044
        screenManager()->push(procScreen);
 
1045
        return UI::EVENT_DONE;
 
1046
}
 
1047
 
 
1048
UI::EventReturn GameSettingsScreen::OnPostProcShaderChange(UI::EventParams &e) {
 
1049
        if (gpu) {
 
1050
                gpu->Resized();
 
1051
        }
 
1052
        Reporting::UpdateConfig();
 
1053
        return UI::EVENT_DONE;
 
1054
}
 
1055
 
 
1056
UI::EventReturn GameSettingsScreen::OnDeveloperTools(UI::EventParams &e) {
 
1057
        screenManager()->push(new DeveloperToolsScreen());
 
1058
        return UI::EVENT_DONE;
 
1059
}
 
1060
 
 
1061
UI::EventReturn GameSettingsScreen::OnRemoteISO(UI::EventParams &e) {
 
1062
        screenManager()->push(new RemoteISOScreen());
 
1063
        return UI::EVENT_DONE;
 
1064
}
 
1065
 
 
1066
UI::EventReturn GameSettingsScreen::OnControlMapping(UI::EventParams &e) {
 
1067
        screenManager()->push(new ControlMappingScreen());
 
1068
        return UI::EVENT_DONE;
 
1069
}
 
1070
 
 
1071
UI::EventReturn GameSettingsScreen::OnTouchControlLayout(UI::EventParams &e) {
 
1072
        screenManager()->push(new TouchControlLayoutScreen());
 
1073
        return UI::EVENT_DONE;
 
1074
}
 
1075
 
 
1076
//when the tilt event type is modified, we need to reset all tilt settings.
 
1077
//refer to the ResetTiltEvents() function for a detailed explanation.
 
1078
UI::EventReturn GameSettingsScreen::OnTiltTypeChange(UI::EventParams &e){
 
1079
        TiltEventProcessor::ResetTiltEvents();
 
1080
        return UI::EVENT_DONE;
 
1081
};
 
1082
 
 
1083
UI::EventReturn GameSettingsScreen::OnTiltCustomize(UI::EventParams &e){
 
1084
        screenManager()->push(new TiltAnalogSettingsScreen());
 
1085
        return UI::EVENT_DONE;
 
1086
};
 
1087
 
 
1088
UI::EventReturn GameSettingsScreen::OnSavedataManager(UI::EventParams &e) {
 
1089
        auto saveData = new SavedataScreen("");
 
1090
        screenManager()->push(saveData);
 
1091
        return UI::EVENT_DONE;
 
1092
}
 
1093
 
 
1094
UI::EventReturn GameSettingsScreen::OnSysInfo(UI::EventParams &e) {
 
1095
        screenManager()->push(new SystemInfoScreen());
 
1096
        return UI::EVENT_DONE;
 
1097
}
 
1098
 
 
1099
void DeveloperToolsScreen::CreateViews() {
 
1100
        using namespace UI;
 
1101
        root_ = new ScrollView(ORIENT_VERTICAL);
 
1102
        root_->SetTag("DevToolsSettings");
 
1103
 
 
1104
        I18NCategory *di = GetI18NCategory("Dialog");
 
1105
        I18NCategory *dev = GetI18NCategory("Developer");
 
1106
        I18NCategory *gr = GetI18NCategory("Graphics");
 
1107
        I18NCategory *a = GetI18NCategory("Audio");
 
1108
        I18NCategory *sy = GetI18NCategory("System");
 
1109
 
 
1110
        LinearLayout *list = root_->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)));
 
1111
        list->SetSpacing(0);
 
1112
        list->Add(new ItemHeader(sy->T("General")));
 
1113
 
 
1114
        bool canUseJit = true;
 
1115
        // iOS can now use JIT on all modes, apparently.
 
1116
        // The bool may come in handy for future non-jit platforms though (UWP XB1?)
 
1117
 
 
1118
        static const char *cpuCores[] = { "Interpreter", "Dynarec (JIT)", "IR Interpreter" };
 
1119
        PopupMultiChoice *core = list->Add(new PopupMultiChoice(&g_Config.iCpuCore, gr->T("CPU Core"), cpuCores, 0, ARRAY_SIZE(cpuCores), sy->GetName(), screenManager()));
 
1120
        core->OnChoice.Handle(this, &DeveloperToolsScreen::OnJitAffectingSetting);
 
1121
        if (!canUseJit) {
 
1122
                core->HideChoice(1);
 
1123
        }
 
1124
 
 
1125
        list->Add(new CheckBox(&g_Config.bShowDeveloperMenu, dev->T("Show Developer Menu")));
 
1126
        list->Add(new CheckBox(&g_Config.bDumpDecryptedEboot, dev->T("Dump Decrypted Eboot", "Dump Decrypted EBOOT.BIN (If Encrypted) When Booting Game")));
 
1127
 
 
1128
        Choice *cpuTests = new Choice(dev->T("Run CPU Tests"));
 
1129
        list->Add(cpuTests)->OnClick.Handle(this, &DeveloperToolsScreen::OnRunCPUTests);
 
1130
#ifdef IOS
 
1131
        const std::string testDirectory = g_Config.flash0Directory + "../";
 
1132
#else
 
1133
        const std::string testDirectory = g_Config.memStickDirectory;
 
1134
#endif
 
1135
        if (!File::Exists(testDirectory + "pspautotests/tests/")) {
 
1136
                cpuTests->SetEnabled(false);
 
1137
        }
 
1138
 
 
1139
        list->Add(new CheckBox(&g_Config.bEnableLogging, dev->T("Enable Logging")))->OnClick.Handle(this, &DeveloperToolsScreen::OnLoggingChanged);
 
1140
        list->Add(new Choice(dev->T("Logging Channels")))->OnClick.Handle(this, &DeveloperToolsScreen::OnLogConfig);
 
1141
        list->Add(new ItemHeader(dev->T("Language")));
 
1142
        list->Add(new Choice(dev->T("Load language ini")))->OnClick.Handle(this, &DeveloperToolsScreen::OnLoadLanguageIni);
 
1143
        list->Add(new Choice(dev->T("Save language ini")))->OnClick.Handle(this, &DeveloperToolsScreen::OnSaveLanguageIni);
 
1144
        list->Add(new ItemHeader(dev->T("Texture Replacement")));
 
1145
        list->Add(new CheckBox(&g_Config.bSaveNewTextures, dev->T("Save new textures")));
 
1146
        list->Add(new CheckBox(&g_Config.bReplaceTextures, dev->T("Replace textures")));
 
1147
#if !defined(MOBILE_DEVICE)
 
1148
        list->Add(new Choice(dev->T("Create/Open textures.ini file for current game")))->OnClick.Handle(this, &DeveloperToolsScreen::OnOpenTexturesIniFile);
 
1149
#endif
 
1150
        list->Add(new ItemHeader(""));
 
1151
        list->Add(new Choice(di->T("Back")))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
 
1152
}
 
1153
 
 
1154
void DeveloperToolsScreen::onFinish(DialogResult result) {
 
1155
        g_Config.Save();
 
1156
}
 
1157
 
 
1158
void GameSettingsScreen::CallbackRestoreDefaults(bool yes) {
 
1159
        if (yes)
 
1160
                g_Config.RestoreDefaults();
 
1161
        host->UpdateUI();
 
1162
}
 
1163
 
 
1164
UI::EventReturn GameSettingsScreen::OnRestoreDefaultSettings(UI::EventParams &e) {
 
1165
        I18NCategory *dev = GetI18NCategory("Developer");
 
1166
        I18NCategory *di = GetI18NCategory("Dialog");
 
1167
        if (g_Config.bGameSpecific)
 
1168
        {
 
1169
                screenManager()->push(
 
1170
                        new PromptScreen(dev->T("RestoreGameDefaultSettings", "Are you sure you want to restore the game-specific settings back to the ppsspp defaults?\n"), di->T("OK"), di->T("Cancel"),
 
1171
                        std::bind(&GameSettingsScreen::CallbackRestoreDefaults, this, placeholder::_1)));
 
1172
        }
 
1173
        else
 
1174
        {
 
1175
                screenManager()->push(
 
1176
                        new PromptScreen(dev->T("RestoreDefaultSettings", "Are you sure you want to restore all settings(except control mapping)\nback to their defaults?\nYou can't undo this.\nPlease restart PPSSPP after restoring settings."), di->T("OK"), di->T("Cancel"),
 
1177
                        std::bind(&GameSettingsScreen::CallbackRestoreDefaults, this, placeholder::_1)));
 
1178
        }
 
1179
 
 
1180
        return UI::EVENT_DONE;
 
1181
}
 
1182
 
 
1183
UI::EventReturn DeveloperToolsScreen::OnLoggingChanged(UI::EventParams &e) {
 
1184
        host->ToggleDebugConsoleVisibility();
 
1185
        return UI::EVENT_DONE;
 
1186
}
 
1187
 
 
1188
UI::EventReturn DeveloperToolsScreen::OnRunCPUTests(UI::EventParams &e) {
 
1189
        RunTests();
 
1190
        return UI::EVENT_DONE;
 
1191
}
 
1192
 
 
1193
UI::EventReturn DeveloperToolsScreen::OnSaveLanguageIni(UI::EventParams &e) {
 
1194
        i18nrepo.SaveIni(g_Config.sLanguageIni);
 
1195
        return UI::EVENT_DONE;
 
1196
}
 
1197
 
 
1198
UI::EventReturn DeveloperToolsScreen::OnLoadLanguageIni(UI::EventParams &e) {
 
1199
        i18nrepo.LoadIni(g_Config.sLanguageIni);
 
1200
        return UI::EVENT_DONE;
 
1201
}
 
1202
 
 
1203
UI::EventReturn DeveloperToolsScreen::OnOpenTexturesIniFile(UI::EventParams &e) {
 
1204
        std::string gameID = g_paramSFO.GetValueString("DISC_ID");
 
1205
        std::string texturesDirectory = GetSysDirectory(DIRECTORY_TEXTURES) + gameID + "/";
 
1206
        bool enabled_ = !gameID.empty();
 
1207
        if (enabled_) {
 
1208
                if (!File::Exists(texturesDirectory)) {
 
1209
                        File::CreateFullPath(texturesDirectory);
 
1210
                }
 
1211
                if (!File::Exists(texturesDirectory + "textures.ini")) {
 
1212
                        FILE *f = File::OpenCFile(texturesDirectory + "textures.ini", "wb");
 
1213
                        if (f) {
 
1214
                                fwrite("\xEF\xBB\xBF", 0, 3, f);
 
1215
                                fclose(f);
 
1216
                                // Let's also write some defaults
 
1217
                                std::fstream fs;
 
1218
                                File::OpenCPPFile(fs, texturesDirectory + "textures.ini", std::ios::out | std::ios::ate);
 
1219
                                fs << "# This file is optional\n";
 
1220
                                fs << "# for syntax explanation check:\n";
 
1221
                                fs << "# - https://github.com/hrydgard/ppsspp/pull/8715 \n";
 
1222
                                fs << "# - https://github.com/hrydgard/ppsspp/pull/8792 \n";
 
1223
                                fs << "[options]\n";
 
1224
                                fs << "version = 1\n";
 
1225
                                fs << "hash = quick\n";
 
1226
                                fs << "\n";
 
1227
                                fs << "[hashes]\n";
 
1228
                                fs << "\n";
 
1229
                                fs << "[hashranges]\n";
 
1230
                                fs.close();
 
1231
                        }
 
1232
                }
 
1233
                enabled_ = File::Exists(texturesDirectory + "textures.ini");
 
1234
        }
 
1235
        if (enabled_) {
 
1236
                File::openIniFile(texturesDirectory + "textures.ini");
 
1237
        }
 
1238
        return UI::EVENT_DONE;
 
1239
}
 
1240
 
 
1241
UI::EventReturn DeveloperToolsScreen::OnLogConfig(UI::EventParams &e) {
 
1242
        screenManager()->push(new LogConfigScreen());
 
1243
        return UI::EVENT_DONE;
 
1244
}
 
1245
 
 
1246
UI::EventReturn DeveloperToolsScreen::OnJitAffectingSetting(UI::EventParams &e) {
 
1247
        NativeMessageReceived("clear jit", "");
 
1248
        return UI::EVENT_DONE;
 
1249
}
 
1250
 
 
1251
void ProAdhocServerScreen::CreateViews() {
 
1252
        using namespace UI;
 
1253
        I18NCategory *sy = GetI18NCategory("System");
 
1254
        I18NCategory *di = GetI18NCategory("Dialog");
 
1255
 
 
1256
        tempProAdhocServer = g_Config.proAdhocServer;
 
1257
        root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT));
 
1258
        LinearLayout *leftColumn = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
 
1259
 
 
1260
        leftColumn->Add(new ItemHeader(sy->T("proAdhocServer Address:")));
 
1261
        addrView_ = new TextView(tempProAdhocServer, ALIGN_LEFT, false);
 
1262
        leftColumn->Add(addrView_);
 
1263
        LinearLayout *rightColumn = new LinearLayout(ORIENT_HORIZONTAL, new AnchorLayoutParams(0, 120, 10, NONE, NONE,10));
 
1264
        rightColumn->Add(new Button("0"))->OnClick.Handle(this, &ProAdhocServerScreen::On0Click);
 
1265
        rightColumn->Add(new Button("1"))->OnClick.Handle(this, &ProAdhocServerScreen::On1Click);
 
1266
        rightColumn->Add(new Button("2"))->OnClick.Handle(this, &ProAdhocServerScreen::On2Click);
 
1267
        rightColumn->Add(new Button("3"))->OnClick.Handle(this, &ProAdhocServerScreen::On3Click);
 
1268
        rightColumn->Add(new Button("4"))->OnClick.Handle(this, &ProAdhocServerScreen::On4Click);
 
1269
        rightColumn->Add(new Button("5"))->OnClick.Handle(this, &ProAdhocServerScreen::On5Click);
 
1270
        rightColumn->Add(new Button("6"))->OnClick.Handle(this, &ProAdhocServerScreen::On6Click);
 
1271
        rightColumn->Add(new Button("7"))->OnClick.Handle(this, &ProAdhocServerScreen::On7Click);
 
1272
        rightColumn->Add(new Button("8"))->OnClick.Handle(this, &ProAdhocServerScreen::On8Click);
 
1273
        rightColumn->Add(new Button("9"))->OnClick.Handle(this, &ProAdhocServerScreen::On9Click);
 
1274
        rightColumn->Add(new Button("."))->OnClick.Handle(this, &ProAdhocServerScreen::OnPointClick);
 
1275
        rightColumn->Add(new Button(di->T("Delete")))->OnClick.Handle(this, &ProAdhocServerScreen::OnDeleteClick);
 
1276
        rightColumn->Add(new Button(di->T("Delete all")))->OnClick.Handle(this, &ProAdhocServerScreen::OnDeleteAllClick);
 
1277
        rightColumn->Add(new Button(di->T("OK")))->OnClick.Handle(this, &ProAdhocServerScreen::OnOKClick);
 
1278
        rightColumn->Add(new Button(di->T("Cancel")))->OnClick.Handle(this, &ProAdhocServerScreen::OnCancelClick);
 
1279
        root_->Add(leftColumn);
 
1280
        root_->Add(rightColumn);
 
1281
}
 
1282
 
 
1283
UI::EventReturn ProAdhocServerScreen::On0Click(UI::EventParams &e) {
 
1284
        if (tempProAdhocServer.length() > 0)
 
1285
                tempProAdhocServer.append("0");
 
1286
        addrView_->SetText(tempProAdhocServer);
 
1287
        return UI::EVENT_DONE;
 
1288
}
 
1289
 
 
1290
UI::EventReturn ProAdhocServerScreen::On1Click(UI::EventParams &e) {
 
1291
        tempProAdhocServer.append("1");
 
1292
        addrView_->SetText(tempProAdhocServer);
 
1293
        return UI::EVENT_DONE;
 
1294
}
 
1295
 
 
1296
UI::EventReturn ProAdhocServerScreen::On2Click(UI::EventParams &e) {
 
1297
        tempProAdhocServer.append("2");
 
1298
        addrView_->SetText(tempProAdhocServer);
 
1299
        return UI::EVENT_DONE;
 
1300
}
 
1301
 
 
1302
UI::EventReturn ProAdhocServerScreen::On3Click(UI::EventParams &e) {
 
1303
        tempProAdhocServer.append("3");
 
1304
        addrView_->SetText(tempProAdhocServer);
 
1305
        return UI::EVENT_DONE;
 
1306
}
 
1307
 
 
1308
UI::EventReturn ProAdhocServerScreen::On4Click(UI::EventParams &e) {
 
1309
        tempProAdhocServer.append("4");
 
1310
        addrView_->SetText(tempProAdhocServer);
 
1311
        return UI::EVENT_DONE;
 
1312
}
 
1313
 
 
1314
UI::EventReturn ProAdhocServerScreen::On5Click(UI::EventParams &e) {
 
1315
        tempProAdhocServer.append("5");
 
1316
        addrView_->SetText(tempProAdhocServer);
 
1317
        return UI::EVENT_DONE;
 
1318
}
 
1319
 
 
1320
UI::EventReturn ProAdhocServerScreen::On6Click(UI::EventParams &e) {
 
1321
        tempProAdhocServer.append("6");
 
1322
        addrView_->SetText(tempProAdhocServer);
 
1323
        return UI::EVENT_DONE;
 
1324
}
 
1325
 
 
1326
UI::EventReturn ProAdhocServerScreen::On7Click(UI::EventParams &e) {
 
1327
        tempProAdhocServer.append("7");
 
1328
        addrView_->SetText(tempProAdhocServer);
 
1329
        return UI::EVENT_DONE;
 
1330
}
 
1331
 
 
1332
UI::EventReturn ProAdhocServerScreen::On8Click(UI::EventParams &e) {
 
1333
        tempProAdhocServer.append("8");
 
1334
        addrView_->SetText(tempProAdhocServer);
 
1335
        return UI::EVENT_DONE;
 
1336
}
 
1337
 
 
1338
UI::EventReturn ProAdhocServerScreen::On9Click(UI::EventParams &e) {
 
1339
        tempProAdhocServer.append("9");
 
1340
        addrView_->SetText(tempProAdhocServer);
 
1341
        return UI::EVENT_DONE;
 
1342
}
 
1343
 
 
1344
 
 
1345
UI::EventReturn ProAdhocServerScreen::OnPointClick(UI::EventParams &e) {
 
1346
        if (tempProAdhocServer.length() > 0 && tempProAdhocServer.at(tempProAdhocServer.length() - 1) != '.')
 
1347
                tempProAdhocServer.append(".");
 
1348
        addrView_->SetText(tempProAdhocServer);
 
1349
        return UI::EVENT_DONE;
 
1350
}
 
1351
 
 
1352
UI::EventReturn ProAdhocServerScreen::OnDeleteClick(UI::EventParams &e) {
 
1353
        if (tempProAdhocServer.length() > 0)
 
1354
                tempProAdhocServer.erase(tempProAdhocServer.length() -1, 1);
 
1355
        addrView_->SetText(tempProAdhocServer);
 
1356
        return UI::EVENT_DONE;
 
1357
}
 
1358
 
 
1359
UI::EventReturn ProAdhocServerScreen::OnDeleteAllClick(UI::EventParams &e) {
 
1360
        tempProAdhocServer = "";
 
1361
        addrView_->SetText(tempProAdhocServer);
 
1362
        return UI::EVENT_DONE;
 
1363
}
 
1364
 
 
1365
UI::EventReturn ProAdhocServerScreen::OnOKClick(UI::EventParams &e) {
 
1366
        g_Config.proAdhocServer = tempProAdhocServer;
 
1367
        UIScreen::OnBack(e);
 
1368
        return UI::EVENT_DONE;
 
1369
}
 
1370
 
 
1371
UI::EventReturn ProAdhocServerScreen::OnCancelClick(UI::EventParams &e) {
 
1372
        tempProAdhocServer = g_Config.proAdhocServer;
 
1373
        UIScreen::OnBack(e);
 
1374
        return UI::EVENT_DONE;
 
1375
}
 
1376
 
 
1377
void SettingInfoMessage::Show(const std::string &text, UI::View *refView) {
 
1378
        if (refView) {
 
1379
                Bounds b = refView->GetBounds();
 
1380
                const UI::AnchorLayoutParams *lp = GetLayoutParams()->As<UI::AnchorLayoutParams>();
 
1381
                if (b.y >= cutOffY_) {
 
1382
                        ReplaceLayoutParams(new UI::AnchorLayoutParams(lp->width, lp->height, lp->left, 80.0f, lp->right, lp->bottom, lp->center));
 
1383
                } else {
 
1384
                        ReplaceLayoutParams(new UI::AnchorLayoutParams(lp->width, lp->height, lp->left, dp_yres - 80.0f - 40.0f, lp->right, lp->bottom, lp->center));
 
1385
                }
 
1386
        }
 
1387
        SetText(text);
 
1388
        timeShown_ = time_now_d();
 
1389
}
 
1390
 
 
1391
void SettingInfoMessage::GetContentDimensionsBySpec(const UIContext &dc, UI::MeasureSpec horiz, UI::MeasureSpec vert, float &w, float &h) const {
 
1392
        TextView::GetContentDimensionsBySpec(dc, horiz, vert, w, h);
 
1393
        w += 20.0f;
 
1394
        h += 20.0f;
 
1395
}
 
1396
 
 
1397
void SettingInfoMessage::Draw(UIContext &dc) {
 
1398
        static const double FADE_TIME = 1.0;
 
1399
        static const float MAX_ALPHA = 0.9f;
 
1400
 
 
1401
        // Let's show longer messages for more time (guesstimate at reading speed.)
 
1402
        // Note: this will give multibyte characters more time, but they often have shorter words anyway.
 
1403
        double timeToShow = std::max(1.5, GetText().size() * 0.05);
 
1404
 
 
1405
        double sinceShow = time_now_d() - timeShown_;
 
1406
        float alpha = MAX_ALPHA;
 
1407
        if (timeShown_ == 0.0 || sinceShow > timeToShow + FADE_TIME) {
 
1408
                alpha = 0.0f;
 
1409
        } else if (sinceShow > timeToShow) {
 
1410
                alpha = MAX_ALPHA - MAX_ALPHA * (float)((sinceShow - timeToShow) / FADE_TIME);
 
1411
        }
 
1412
 
 
1413
        if (alpha >= 0.1f) {
 
1414
                UI::Style style = dc.theme->popupTitle;
 
1415
                style.background.color = colorAlpha(style.background.color, alpha - 0.1f);
 
1416
                dc.FillRect(style.background, bounds_);
 
1417
        }
 
1418
 
 
1419
        SetTextColor(whiteAlpha(alpha));
 
1420
        // Fake padding by adjusting bounds.
 
1421
        SetBounds(bounds_.Expand(-10.0f));
 
1422
        TextView::Draw(dc);
 
1423
        SetBounds(bounds_.Expand(10.0f));
 
1424
}