Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/UI/DisplayLayoutScreen.cpp
5654 views
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 <algorithm>
19
20
#include "Common/System/Display.h"
21
#include "Common/System/System.h"
22
#include "Common/Render/TextureAtlas.h"
23
#include "Common/Render/DrawBuffer.h"
24
#include "Common/UI/Context.h"
25
#include "Common/UI/View.h"
26
#include "Common/UI/UIScreen.h"
27
#include "Common/UI/TabHolder.h"
28
#include "Common/Math/math_util.h"
29
#include "Common/System/NativeApp.h"
30
#include "Common/VR/PPSSPPVR.h"
31
#include "Common/StringUtils.h"
32
33
#include "Common/Data/Color/RGBAUtil.h"
34
#include "Common/Data/Text/I18n.h"
35
#include "UI/DisplayLayoutScreen.h"
36
#include "UI/Background.h"
37
#include "Core/Config.h"
38
#include "Core/ConfigValues.h"
39
#include "Core/System.h"
40
#include "GPU/GPUCommon.h"
41
#include "GPU/Common/FramebufferManagerCommon.h"
42
#include "GPU/Common/PresentationCommon.h"
43
44
static const int leftColumnWidth = 200;
45
static const float orgRatio = 1.764706f; // 480.0 / 272.0
46
47
enum Mode {
48
MODE_INACTIVE = 0,
49
MODE_MOVE = 1,
50
MODE_RESIZE = 2,
51
};
52
53
static Bounds FRectToBounds(FRect rc) {
54
Bounds b;
55
b.x = rc.x * g_display.dpi_scale_x;
56
b.y = rc.y * g_display.dpi_scale_y;
57
b.w = rc.w * g_display.dpi_scale_x;
58
b.h = rc.h * g_display.dpi_scale_y;
59
return b;
60
}
61
62
class DisplayLayoutBackground : public UI::View {
63
public:
64
DisplayLayoutBackground(UI::ChoiceStrip *mode, DeviceOrientation orientation, UI::LayoutParams *layoutParams) : UI::View(layoutParams), mode_(mode), orientation_(orientation) {}
65
66
bool Touch(const TouchInput &touch) override {
67
int mode = mode_ ? mode_->GetSelection() : 0;
68
69
DisplayLayoutConfig &config = g_Config.GetDisplayLayoutConfig(orientation_);
70
71
if ((touch.flags & TouchInputFlags::MOVE) != 0 && dragging_) {
72
float relativeTouchX = touch.x - startX_;
73
float relativeTouchY = touch.y - startY_;
74
75
switch (mode) {
76
case MODE_MOVE:
77
config.fDisplayOffsetX = clamp_value(startDisplayOffsetX_ + relativeTouchX / bounds_.w, 0.0f, 1.0f);
78
config.fDisplayOffsetY = clamp_value(startDisplayOffsetY_ + relativeTouchY / bounds_.h, 0.0f, 1.0f);
79
break;
80
case MODE_RESIZE:
81
{
82
// Resize. Vertical = scaling; Up should be bigger so let's negate in that direction
83
float diffYProp = -relativeTouchY * 0.007f;
84
config.fDisplayScale = clamp_value(startScale_ * powf(2.0f, diffYProp), 0.2f, 2.0f);
85
break;
86
}
87
}
88
}
89
90
if ((touch.flags & TouchInputFlags::DOWN) != 0 && !dragging_) {
91
// Check that we're in the central 80% of the screen.
92
// If outside, it may be a drag from displaying the back button on phones
93
// where you have to drag from the side, etc.
94
if (touch.x >= bounds_.w * 0.1f && touch.x <= bounds_.w * 0.9f &&
95
touch.y >= bounds_.h * 0.1f && touch.y <= bounds_.h * 0.9f) {
96
dragging_ = true;
97
startX_ = touch.x;
98
startY_ = touch.y;
99
startDisplayOffsetX_ = config.fDisplayOffsetX;
100
startDisplayOffsetY_ = config.fDisplayOffsetY;
101
startScale_ = config.fDisplayScale;
102
}
103
}
104
105
if ((touch.flags & TouchInputFlags::UP) != 0 && dragging_) {
106
dragging_ = false;
107
}
108
109
return true;
110
}
111
112
private:
113
UI::ChoiceStrip *mode_;
114
bool dragging_ = false;
115
const DeviceOrientation orientation_;
116
// Touch down state for drag to resize etc
117
float startX_ = 0.0f;
118
float startY_ = 0.0f;
119
float startScale_ = -1.0f;
120
float startDisplayOffsetX_ = -1.0f;
121
float startDisplayOffsetY_ = -1.0f;
122
};
123
124
DisplayLayoutScreen::DisplayLayoutScreen(const Path &filename) : UIBaseDialogScreen(filename) {}
125
126
void DisplayLayoutScreen::DrawBackground(UIContext &dc) {
127
if (PSP_GetBootState() == BootState::Complete && !g_Config.bSkipBufferEffects) {
128
// We normally rely on the PSP screen showing through.
129
} else {
130
// But if it's not present (we're not in game, or skip buffer effects is used),
131
// we have to draw a substitute ourselves.
132
UIContext &dc = *screenManager()->getUIContext();
133
DisplayLayoutConfig &config = g_Config.GetDisplayLayoutConfig(GetDeviceOrientation());
134
135
// TODO: Clean this up a bit, this GetScreenFrame/CenterDisplay combo is too common.
136
FRect screenFrame = GetScreenFrame(config.bIgnoreScreenInsets, g_display.pixel_xres, g_display.pixel_yres);
137
FRect rc;
138
CalculateDisplayOutputRect(config, &rc, 480.0f, 272.0f, screenFrame, config.iInternalScreenRotation);
139
140
dc.Flush();
141
ImageID bg = ImageID("I_PSP_DISPLAY");
142
dc.Draw()->DrawImageStretch(bg, dc.GetBounds(), 0x7F000000);
143
dc.Draw()->DrawImageStretch(bg, FRectToBounds(rc), 0x7FFFFFFF);
144
}
145
}
146
147
void DisplayLayoutScreen::onFinish(DialogResult reason) {
148
g_Config.Save("DisplayLayoutScreen::onFinish");
149
}
150
151
void DisplayLayoutScreen::dialogFinished(const Screen *dialog, DialogResult result) {
152
RecreateViews();
153
}
154
155
static void NotifyPostChanges() {
156
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
157
System_PostUIMessage(UIMessage::GPU_RENDER_RESIZED); // To deal with shaders that can change render resolution like upscaling.
158
System_PostUIMessage(UIMessage::POSTSHADER_UPDATED);
159
160
if (gpu) {
161
gpu->NotifyConfigChanged();
162
}
163
}
164
165
void DisplayLayoutScreen::OnPostProcShaderChange(UI::EventParams &e) {
166
// Remove the virtual "Off" entry. TODO: Get rid of it generally.
167
g_Config.vPostShaderNames.erase(std::remove(g_Config.vPostShaderNames.begin(), g_Config.vPostShaderNames.end(), "Off"), g_Config.vPostShaderNames.end());
168
FixPostShaderOrder(&g_Config.vPostShaderNames);
169
NotifyPostChanges();
170
}
171
172
static std::string PostShaderTranslateName(std::string_view value) {
173
if (value == "Off") {
174
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
175
// Off is a legacy fake item (gonna migrate off it later).
176
return std::string(gr->T("Add postprocessing shader"));
177
}
178
179
const ShaderInfo *info = GetPostShaderInfo(value);
180
if (info) {
181
auto ps = GetI18NCategory(I18NCat::POSTSHADERS);
182
return std::string(ps->T(value, info->name));
183
} else {
184
return std::string(value);
185
}
186
}
187
188
void DisplayLayoutScreen::sendMessage(UIMessage message, const char *value) {
189
UIBaseDialogScreen::sendMessage(message, value);
190
if (message == UIMessage::POSTSHADER_UPDATED) {
191
g_Config.bShaderChainRequires60FPS = PostShaderChainRequires60FPS(GetFullPostShadersChain(g_Config.vPostShaderNames));
192
RecreateViews();
193
}
194
}
195
196
void DisplayLayoutScreen::CreateViews() {
197
const Bounds &bounds = screenManager()->getUIContext()->GetBounds();
198
199
using namespace UI;
200
201
auto di = GetI18NCategory(I18NCat::DIALOG);
202
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
203
auto co = GetI18NCategory(I18NCat::CONTROLS);
204
auto ps = GetI18NCategory(I18NCat::POSTSHADERS);
205
auto sy = GetI18NCategory(I18NCat::SYSTEM);
206
207
root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT));
208
209
const bool portrait = GetDeviceOrientation() == DeviceOrientation::Portrait;
210
211
// Make it so that a touch can only affect one view. Makes manipulating the background through the buttons
212
// impossible.
213
root_->SetExclusiveTouch(true);
214
215
// Add indicator of the current mode we're editing. Not sure why these strings are in Controls.
216
root_->Add(new TextView(portrait ? co->T("Portrait") : co->T("Landscape"), new AnchorLayoutParams(portrait ? 10.0f : NONE, 10.0f, NONE, NONE)))->SetSmall(true);
217
218
DisplayLayoutConfig &config = g_Config.GetDisplayLayoutConfig(GetDeviceOrientation());
219
bool internalPortrait = config.iInternalScreenRotation == ROTATION_LOCKED_VERTICAL || config.iInternalScreenRotation == ROTATION_LOCKED_VERTICAL180;
220
221
LinearLayout *leftColumn;
222
if (!portrait) {
223
ScrollView *leftScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(420.0f, FILL_PARENT, 0.f, 0.f, NONE, 0.f));
224
leftColumn = new LinearLayout(ORIENT_VERTICAL);
225
leftColumn->padding.SetAll(8.0f);
226
leftScrollView->Add(leftColumn);
227
leftScrollView->SetClickableBackground(true);
228
root_->Add(leftScrollView);
229
}
230
231
ScrollView *rightScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(300.0f, FILL_PARENT, NONE, 0.f, 0.f, 0.f));
232
LinearLayout *rightColumn = new LinearLayout(ORIENT_VERTICAL);
233
rightColumn->padding.SetAll(8.0f);
234
rightColumn->SetSpacing(0.0f);
235
rightScrollView->Add(rightColumn);
236
rightScrollView->SetClickableBackground(true);
237
root_->Add(rightScrollView);
238
239
Choice *back = new Choice(di->T("Back"), ImageID("I_NAVIGATE_BACK"));
240
back->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
241
rightColumn->Add(back);
242
243
LinearLayout *bottomControls;
244
if (portrait) {
245
bottomControls = new LinearLayout(ORIENT_HORIZONTAL);
246
rightColumn->Add(bottomControls);
247
leftColumn = rightColumn;
248
} else {
249
bottomControls = new LinearLayout(ORIENT_HORIZONTAL, new AnchorLayoutParams(NONE, NONE, NONE, 10.0f));
250
root_->Add(bottomControls);
251
}
252
253
// Set backgrounds for readability
254
Drawable backgroundWithAlpha(GetBackgroundColorWithAlpha(*screenManager()->getUIContext()));
255
leftColumn->SetBG(backgroundWithAlpha);
256
rightColumn->SetBG(backgroundWithAlpha);
257
258
if (!IsVREnabled()) {
259
if (portrait == internalPortrait) {
260
// Stretch doesn't make sense in portrait mode (looks crazy), so we only show it in landscape mode.
261
// Vice versa if internal is portrait.
262
auto stretch = new CheckBox(&config.bDisplayStretch, gr->T("Stretch"));
263
stretch->SetDisabledPtr(&config.bDisplayIntegerScale);
264
rightColumn->Add(stretch);
265
}
266
267
PopupSliderChoiceFloat *aspectRatio = new PopupSliderChoiceFloat(&config.fDisplayAspectRatio, 0.1f, 2.0f, 1.0f, gr->T("Aspect Ratio"), screenManager());
268
rightColumn->Add(aspectRatio);
269
aspectRatio->SetEnabledFunc([config]() {
270
return !config.bDisplayStretch && !config.bDisplayIntegerScale;
271
});
272
aspectRatio->SetHasDropShadow(false);
273
aspectRatio->SetLiveUpdate(true);
274
275
rightColumn->Add(new CheckBox(&config.bDisplayIntegerScale, gr->T("Integer scale factor")));
276
277
rightColumn->Add(new Spacer(12.0f));
278
279
bool supportsInsets = false;
280
#if PPSSPP_PLATFORM(ANDROID)
281
supportsInsets = System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 28;
282
#elif PPSSPP_PLATFORM(IOS)
283
supportsInsets = true;
284
#endif
285
// Hide insets option if no insets, or OS too old.
286
if (supportsInsets && (
287
System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT) != 0.0f ||
288
System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_TOP) != 0.0f ||
289
System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_RIGHT) != 0.0f ||
290
System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_BOTTOM) != 0.0f)) {
291
rightColumn->Add(new CheckBox(&config.bIgnoreScreenInsets, gr->T("Ignore camera notch when centering")));
292
}
293
294
static const char *displayRotation[] = { "Landscape", "Portrait", "Landscape Reversed", "Portrait Reversed" };
295
auto rotation = new PopupMultiChoice(&config.iInternalScreenRotation, gr->T("Rotation"), displayRotation, 1, ARRAY_SIZE(displayRotation), I18NCat::CONTROLS, screenManager());
296
rotation->OnChoice.Add([this](UI::EventParams &) {
297
// Affects the presence of the Stretch checkbox.
298
RecreateViews();
299
});
300
rotation->SetEnabledFunc([] {
301
return !g_Config.bSkipBufferEffects || g_Config.bSoftwareRendering;
302
});
303
rotation->SetHideTitle(true);
304
305
rightColumn->Add(new ItemHeader(gr->T("Display rotation")));
306
rightColumn->Add(rotation);
307
rightColumn->Add(new CheckBox(&config.bRotateControlsWithScreen, gr->T("Rotate controls")))->SetEnabledFunc([&config]() -> bool {
308
return (!g_Config.bSkipBufferEffects || g_Config.bSoftwareRendering) && config.iInternalScreenRotation != 1;
309
});
310
311
rightColumn->Add(new Spacer(12.0f));
312
313
Choice *center = new Choice(di->T("Reset"));
314
center->OnClick.Add([&config, portrait](UI::EventParams &) {
315
// Hm, not really ideal to have to use strings here.
316
config.ResetToDefault(portrait ? "DisplayLayout.Portrait" : "DisplayLayout.Landscape");
317
});
318
rightColumn->Add(center);
319
320
mode_ = new ChoiceStrip(ORIENT_HORIZONTAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT));
321
mode_->AddChoice(sy->T("Off"));
322
mode_->AddChoice(ImageID("I_MOVE"));
323
mode_->AddChoice(ImageID("I_RESIZE"));
324
mode_->SetSelection(0, false);
325
bottomControls->Add(mode_);
326
}
327
328
if (portrait) {
329
leftColumn->Add(new Spacer(24.0f));
330
}
331
332
if (!IsVREnabled()) {
333
static const char *bufFilters[] = { "Linear", "Nearest", };
334
leftColumn->Add(new PopupMultiChoice(&config.iDisplayFilter, gr->T("Screen Scaling Filter"), bufFilters, 1, ARRAY_SIZE(bufFilters), I18NCat::GRAPHICS, screenManager()));
335
}
336
337
Draw::DrawContext *draw = screenManager()->getDrawContext();
338
339
bool multiViewSupported = draw->GetDeviceCaps().multiViewSupported;
340
341
auto enableStereo = [=]() -> bool {
342
return g_Config.bStereoRendering && multiViewSupported;
343
};
344
345
leftColumn->Add(new ItemHeader(gr->T("Postprocessing shaders")));
346
347
std::set<std::string> alreadyAddedShader;
348
// If there's a single post shader and we're just entering the dialog,
349
// auto-open the settings.
350
if (settingsVisible_.empty() && g_Config.vPostShaderNames.size() == 1) {
351
settingsVisible_.push_back(true);
352
} else if (settingsVisible_.size() < g_Config.vPostShaderNames.size()) {
353
settingsVisible_.resize(g_Config.vPostShaderNames.size());
354
}
355
356
static const ContextMenuItem postShaderContextMenu[] = {
357
{ "Move Up", "I_ARROW_UP" },
358
{ "Move Down", "I_ARROW_DOWN" },
359
{ "Remove", "I_TRASHCAN" },
360
};
361
362
for (int i = 0; i < (int)g_Config.vPostShaderNames.size() + 1 && i < ARRAY_SIZE(shaderNames_); ++i) {
363
// Vector element pointer get invalidated on resize, cache name to have always a valid reference in the rendering thread
364
shaderNames_[i] = i == g_Config.vPostShaderNames.size() ? "Off" : g_Config.vPostShaderNames[i];
365
366
LinearLayout *shaderRow = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(UI::FILL_PARENT, UI::WRAP_CONTENT));
367
shaderRow->SetSpacing(4.0f);
368
leftColumn->Add(shaderRow);
369
370
if (shaderNames_[i] != "Off") {
371
postProcChoice_ = shaderRow->Add(new ChoiceWithValueDisplay(&shaderNames_[i], "", &PostShaderTranslateName, new LinearLayoutParams(1.0f)));
372
} else {
373
postProcChoice_ = shaderRow->Add(new Choice(ImageID("I_PLUS")));
374
}
375
postProcChoice_->OnClick.Add([=](EventParams &e) {
376
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
377
auto procScreen = new PostProcScreen(gr->T("Postprocessing shaders"), i, false);
378
procScreen->SetHasDropShadow(false);
379
procScreen->OnChoice.Handle(this, &DisplayLayoutScreen::OnPostProcShaderChange);
380
if (e.v)
381
procScreen->SetPopupOrigin(e.v);
382
screenManager()->push(procScreen);
383
});
384
postProcChoice_->SetEnabledFunc([=] {
385
return !g_Config.bSkipBufferEffects && !enableStereo();
386
});
387
388
if (i < g_Config.vPostShaderNames.size()) {
389
bool hasSettings = false;
390
std::vector<const ShaderInfo *> shaderChain = GetPostShaderChain(g_Config.vPostShaderNames[i]);
391
for (auto shaderInfo : shaderChain) {
392
for (size_t i = 0; i < ARRAY_SIZE(shaderInfo->settings); ++i) {
393
auto &setting = shaderInfo->settings[i];
394
if (!setting.name.empty()) {
395
hasSettings = true;
396
break;
397
}
398
}
399
}
400
if (hasSettings) {
401
CheckBox *checkBox = new CheckBox(&settingsVisible_[i], ImageID("I_SLIDERS"), new LinearLayoutParams(0.0f));
402
auto settingsButton = shaderRow->Add(checkBox);
403
settingsButton->OnClick.Add([=](EventParams &e) {
404
RecreateViews();
405
});
406
}
407
408
auto removeButton = shaderRow->Add(new Choice(ImageID("I_TRASHCAN"), new LinearLayoutParams(0.0f)));
409
removeButton->OnClick.Add([=](EventParams &e) -> void {
410
// Protect against possible race conditions.
411
if (i < g_Config.vPostShaderNames.size()) {
412
g_Config.vPostShaderNames.erase(g_Config.vPostShaderNames.begin() + i);
413
FixPostShaderOrder(&g_Config.vPostShaderNames);
414
NotifyPostChanges();
415
RecreateViews();
416
}
417
});
418
419
auto moreButton = shaderRow->Add(new Choice(ImageID("I_THREE_DOTS"), new LinearLayoutParams(0.0f)));
420
moreButton->OnClick.Add([=](EventParams &e) -> void {
421
if (i >= g_Config.vPostShaderNames.size()) {
422
// Protect against possible race conditions.
423
return;
424
}
425
426
PopupContextMenuScreen *contextMenu = new UI::PopupContextMenuScreen(postShaderContextMenu, ARRAY_SIZE(postShaderContextMenu), I18NCat::DIALOG, moreButton);
427
screenManager()->push(contextMenu);
428
const ShaderInfo *info = GetPostShaderInfo(g_Config.vPostShaderNames[i]);
429
bool usesLastFrame = info ? info->usePreviousFrame : false;
430
contextMenu->SetEnabled(0, i > 0 && !usesLastFrame);
431
contextMenu->SetEnabled(1, i < g_Config.vPostShaderNames.size() - 1);
432
contextMenu->OnChoice.Add([=](EventParams &e) -> void {
433
switch (e.a) {
434
case 0: // Move up
435
std::swap(g_Config.vPostShaderNames[i - 1], g_Config.vPostShaderNames[i]);
436
break;
437
case 1: // Move down
438
std::swap(g_Config.vPostShaderNames[i], g_Config.vPostShaderNames[i + 1]);
439
break;
440
case 2: // Remove
441
g_Config.vPostShaderNames.erase(g_Config.vPostShaderNames.begin() + i);
442
break;
443
default:
444
return;
445
}
446
FixPostShaderOrder(&g_Config.vPostShaderNames);
447
NotifyPostChanges();
448
RecreateViews();
449
});
450
});
451
}
452
453
454
// No need for settings on the last one.
455
if (i == g_Config.vPostShaderNames.size())
456
continue;
457
458
if (!settingsVisible_[i])
459
continue;
460
461
std::vector<const ShaderInfo *> shaderChain = GetPostShaderChain(g_Config.vPostShaderNames[i]);
462
for (auto shaderInfo : shaderChain) {
463
// Disable duplicated shader slider
464
bool duplicated = alreadyAddedShader.find(shaderInfo->section) != alreadyAddedShader.end();
465
alreadyAddedShader.insert(shaderInfo->section);
466
467
LinearLayout *settingContainer = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(UI::FILL_PARENT, UI::WRAP_CONTENT, UI::Margins(24.0f, 0.0f, 0.0f, 0.0f)));
468
leftColumn->Add(settingContainer);
469
for (size_t i = 0; i < ARRAY_SIZE(shaderInfo->settings); ++i) {
470
auto &setting = shaderInfo->settings[i];
471
if (!setting.name.empty()) {
472
// This map lookup will create the setting in the mPostShaderSetting map if it doesn't exist, with a default value of 0.0.
473
std::string key = StringFromFormat("%sSettingCurrentValue%d", shaderInfo->section.c_str(), i + 1);
474
bool keyExisted = g_Config.mPostShaderSetting.find(key) != g_Config.mPostShaderSetting.end();
475
auto &value = g_Config.mPostShaderSetting[key];
476
if (!keyExisted)
477
value = setting.value;
478
479
if (duplicated) {
480
auto sliderName = StringFromFormat("%s %s", ps->T_cstr(setting.name.c_str()), ps->T_cstr("(duplicated setting, previous slider will be used)"));
481
PopupSliderChoiceFloat *settingValue = settingContainer->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, setting.value, sliderName, setting.step, screenManager()));
482
settingValue->SetEnabled(false);
483
} else {
484
PopupSliderChoiceFloat *settingValue = settingContainer->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, setting.value, ps->T(setting.name), setting.step, screenManager()));
485
settingValue->SetLiveUpdate(true);
486
settingValue->SetHasDropShadow(false);
487
settingValue->SetEnabledFunc([=] {
488
return !g_Config.bSkipBufferEffects && !enableStereo();
489
});
490
}
491
}
492
}
493
}
494
}
495
496
root_->Add(new DisplayLayoutBackground(mode_, GetDeviceOrientation(), new AnchorLayoutParams(FILL_PARENT, FILL_PARENT, 0.0f, 0.0f, 0.0f, 0.0f)));
497
}
498
499
void PostProcScreen::CreateViews() {
500
auto ps = GetI18NCategory(I18NCat::POSTSHADERS);
501
ReloadAllPostShaderInfo(screenManager()->getDrawContext());
502
shaders_ = GetAllPostShaderInfo();
503
std::vector<std::string> items;
504
int selected = -1;
505
const std::string selectedName = id_ >= (int)g_Config.vPostShaderNames.size() ? "Off" : g_Config.vPostShaderNames[id_];
506
507
for (int i = 0; i < (int)shaders_.size(); i++) {
508
if (!shaders_[i].visible)
509
continue;
510
if (shaders_[i].isStereo != showStereoShaders_)
511
continue;
512
if (shaders_[i].section == selectedName)
513
selected = (int)indexTranslation_.size();
514
items.push_back(std::string(ps->T(shaders_[i].section.c_str(), shaders_[i].name.c_str())));
515
indexTranslation_.push_back(i);
516
}
517
adaptor_ = UI::StringVectorListAdaptor(items, selected);
518
ListPopupScreen::CreateViews();
519
}
520
521
void PostProcScreen::OnCompleted(DialogResult result) {
522
if (result != DR_OK)
523
return;
524
const std::string &value = shaders_[indexTranslation_[listView_->GetSelected()]].section;
525
// I feel this logic belongs more in the caller, but eh...
526
if (showStereoShaders_) {
527
if (g_Config.sStereoToMonoShader != value) {
528
g_Config.sStereoToMonoShader = value;
529
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
530
}
531
} else {
532
if (id_ < (int)g_Config.vPostShaderNames.size()) {
533
if (g_Config.vPostShaderNames[id_] != value) {
534
g_Config.vPostShaderNames[id_] = value;
535
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
536
}
537
} else {
538
g_Config.vPostShaderNames.push_back(value);
539
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
540
}
541
}
542
}
543
544