Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/manual_generate_apk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ jobs:
# with:
# ndk-version: r21e

- name: Test androidGitVersion
run: |
echo "count=${{steps.valid-tags.outputs.count}}"
gradle --quiet androidGitVersion
#- name: Test androidGitVersion
# run: |
# echo "count=${{steps.valid-tags.outputs.count}}"
# gradle --quiet androidGitVersion

- name: Assemble APK
run: ./gradlew assemble${{ github.event.inputs.buildVariant }} --stacktrace
Expand Down
32 changes: 25 additions & 7 deletions Common/UI/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <algorithm>

#include "Common/System/Display.h"
#include "Core/Config.h"
#include "Common/System/System.h"
#include "Common/UI/UI.h"
#include "Common/UI/View.h"
Expand Down Expand Up @@ -42,15 +43,32 @@ void UIContext::Init(Draw::DrawContext *thin3d, Draw::Pipeline *uipipe, Draw::Pi

void UIContext::BeginFrame() {
frameStartTime_ = time_now_d();
// Per-game config is loaded when a game starts, after UIContext may already
// have created its atlas. Detect the setting change here so the first game
// frame rebuilds the atlas without requiring the user to revisit Settings.
if (lastTouchButtonAtlasScale_ != g_Config.iTouchButtonAtlasScale) {
lastTouchButtonAtlasScale_ = g_Config.iTouchButtonAtlasScale;
atlasInvalid_ = true;
}
if (atlasInvalid_ || !uitexture_) {
if (uitexture_) {
uitexture_->Release();
}
// Build the replacement before releasing the current texture. Atlas generation may
// fail on devices with limited texture memory, especially at high SVG quality.
AtlasData data = atlasProvider_(draw_, AtlasChoice::General, 1.0f / g_display.dpi_scale_x, atlasInvalid_);
uitexture_ = data.texture;
_dbg_assert_(uitexture_);
ui_draw2d.SetAtlas(data.atlas);
atlasInvalid_ = false;
if (!data.texture || !data.atlas) {
WARN_LOG(Log::G3D, "Failed to create UI atlas texture; keeping the previous atlas if available");
if (!uitexture_) {
// There is no valid atlas to draw with yet. Avoid binding a null texture.
return;
}
atlasInvalid_ = false;
} else {
if (uitexture_) {
uitexture_->Release();
}
uitexture_ = data.texture;
ui_draw2d.SetAtlas(data.atlas);
atlasInvalid_ = false;
}
}

if (!fontTexture_) {
Expand Down
1 change: 1 addition & 0 deletions Common/UI/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,5 @@ class UIContext {

UIAtlasProviderFunc atlasProvider_{};
bool atlasInvalid_ = false;
int lastTouchButtonAtlasScale_ = -1;
};
140 changes: 140 additions & 0 deletions Core/Config.cpp

Large diffs are not rendered by default.

43 changes: 42 additions & 1 deletion Core/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -503,9 +503,17 @@ struct Config : public ConfigBlock {
bool bDisableDpadDiagonals;
bool bGamepadOnlyFocused;

// Control Style
// On-screen button appearance and pressed feedback.
int iTouchButtonStyle;
int iTouchButtonPressedStyle;
int iTouchButtonOpacity;
int iTouchButtonSurfaceAlpha;
int iTouchAnalogHeadOpacity;
int iTouchButtonEnlargePercent;
int iTouchButtonShrinkPercent;
int iTouchButtonAtlasScale;
bool bDisableTouchButtonShadows = false;
bool bDisableTouchButtonThemeColor = false;
int iTouchButtonHideSeconds;

// Snap touch control position
Expand All @@ -524,8 +532,18 @@ struct Config : public ConfigBlock {
TouchControlConfig touchControlsLandscape;
TouchControlConfig touchControlsPortrait;

// Secondary touch layout used by the Swap Layout virtual key.
TouchControlConfig touchControlsLandscapeLayout2;
TouchControlConfig touchControlsPortraitLayout2;
int iTouchLayoutSelection = 1;
int iTouchLayoutSelectionSaved = 1;

// These are shared between portrait and landscape, just the positions aren't.
ConfigCustomButton CustomButton[TouchControlConfig::CUSTOM_BUTTON_COUNT];
bool bCustomButtonSummary[TouchControlConfig::CUSTOM_BUTTON_COUNT]{};
std::string sCustomButtonSummaryText[TouchControlConfig::CUSTOM_BUTTON_COUNT];
int iCustomButtonSummaryPosition[TouchControlConfig::CUSTOM_BUTTON_COUNT]{};
int iCustomButtonSummaryMargin[TouchControlConfig::CUSTOM_BUTTON_COUNT]{};

// Ignored on iOS and other platforms that lack pause.
bool bShowTouchPause;
Expand Down Expand Up @@ -794,7 +812,30 @@ struct Config : public ConfigBlock {
return orientation == DeviceOrientation::Portrait ? touchControlsPortrait : touchControlsLandscape;
}

// Get the touched control config based on current layout selection
const TouchControlConfig &GetCurrentTouchControlsConfig(DeviceOrientation orientation) const {
if (iTouchLayoutSelection == 2) {
return orientation == DeviceOrientation::Portrait ? touchControlsPortraitLayout2 : touchControlsLandscapeLayout2;
}
return orientation == DeviceOrientation::Portrait ? touchControlsPortrait : touchControlsLandscape;
}
TouchControlConfig &GetCurrentTouchControlsConfig(DeviceOrientation orientation) {
if (iTouchLayoutSelection == 2) {
return orientation == DeviceOrientation::Portrait ? touchControlsPortraitLayout2 : touchControlsLandscapeLayout2;
}
return orientation == DeviceOrientation::Portrait ? touchControlsPortrait : touchControlsLandscape;
}

// Exchange layout selections between mode 1 and 2
void SwapTouchControlsLayouts();

// Ensure layout2 is initialized as a copy of layout1 if empty
void EnsureSecondaryLayoutsInitialized();

static int GetDefaultValueInt(int *configSetting);
// Initialize Layout 2 as copy of Layout 1 if not already configured
void InitializeLayout2IfNeeded();


void DoNotSaveSetting(void *configSetting) {
settingsNotToSave_.push_back(configSetting);
Expand Down
1 change: 1 addition & 0 deletions Core/KeyMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,7 @@ const KeyMap_IntStrPair psp_button_names[] = {
#endif
{VIRTKEY_TOGGLE_DEBUGGER, "Toggle Debugger"},
{VIRTKEY_TOGGLE_TILT, "Toggle tilt control"},
{VIRTKEY_SWAP_LAYOUT, "Swap layout"},

{VIRTKEY_OPENCHAT, "OpenChat" },

Expand Down
1 change: 1 addition & 0 deletions Core/KeyMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ enum VirtKey : u32 {
VIRTKEY_TOGGLE_TILT = 0x40000035,
VIRTKEY_AXIS_SWAP_HOLD = 0x40000036,
VIRTKEY_CREATE_FRAME_DUMP = 0x40000037,
VIRTKEY_SWAP_LAYOUT = 0x40000038,
VIRTKEY_LAST,
VIRTKEY_COUNT = VIRTKEY_LAST - VIRTKEY_FIRST
};
Expand Down
21 changes: 20 additions & 1 deletion UI/CustomButtonMappingScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,15 +132,25 @@ void CustomButtonMappingScreen::CreateDialogViews(UI::ViewGroup *parent) {
LinearLayout *leftColumn = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(120, FILL_PARENT));
auto di = GetI18NCategory(I18NCat::DIALOG);

TouchControlConfig &touch = g_Config.GetTouchControlsConfig(deviceOrientation_);
TouchControlConfig &touch = g_Config.GetCurrentTouchControlsConfig(deviceOrientation_);
static const char *summaryPositionLabels[] = { "Center", "Left", "Down", "Right", "Up" };
static const char *summaryMarginLabels[] = { "None", "Small", "Medium", "High" };

ConfigCustomButton *cfg = nullptr;
bool *show = nullptr;
bool *summaryShow = nullptr;
std::string *summaryText = nullptr;
int *summaryPosition = nullptr;
int *summaryMargin = nullptr;
cfg = &g_Config.CustomButton[id_];
// This screen is reachable from the main menu, so neither GamepadEmu nor the layout screen
// need have sanitized these yet - and everything below indexes the tables with them.
CustomKeyData::Sanitize(*cfg);
show = &touch.touchCustom[id_].show;
summaryShow = &g_Config.bCustomButtonSummary[id_];
summaryText = &g_Config.sCustomButtonSummaryText[id_];
summaryPosition = &g_Config.iCustomButtonSummaryPosition[id_];
summaryMargin = &g_Config.iCustomButtonSummaryMargin[id_];
// Only load once, since the views can be recreated (on rotation, for example) before the array is saved.
if (!arrayLoaded_) {
for (int i = 0; i < ARRAY_SIZE(g_customKeyList); i++) {
Expand Down Expand Up @@ -185,6 +195,15 @@ void CustomButtonMappingScreen::CreateDialogViews(UI::ViewGroup *parent) {
screenManager()->push(shape);
});

vertLayout->Add(new CheckBox(summaryShow, co->T("Show summary")));
vertLayout->Add(new PopupTextInputChoice(GetRequesterToken(), summaryText, co->T("Summary text"), co->T("Summary text"), 48, screenManager()));
PopupMultiChoice *summaryPos = vertLayout->Add(new PopupMultiChoice(summaryPosition, co->T("Summary position"), summaryPositionLabels, 0, ARRAY_SIZE(summaryPositionLabels), I18NCat::CONTROLS, screenManager()));
summaryPos->SetEnabledPtr(summaryShow);
PopupMultiChoice *summaryMarginChoice = vertLayout->Add(new PopupMultiChoice(summaryMargin, co->T("Summary margin"), summaryMarginLabels, 0, ARRAY_SIZE(summaryMarginLabels), I18NCat::CONTROLS, screenManager()));
summaryMarginChoice->SetEnabledFunc([summaryShow, summaryPosition]() {
return *summaryShow && *summaryPosition != 0;
});

vertLayout->Add(new ItemHeader(co->T("Button Binding")));
vertLayout->Add(new CheckBox(&(cfg->toggle), co->T("Toggle mode")));
vertLayout->Add(new CheckBox(&(cfg->repeat), co->T("Repeat mode")));
Expand Down
18 changes: 17 additions & 1 deletion UI/EmuScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,22 @@ void EmuScreen::ProcessVKey(VirtKey virtKey, bool down) {
}
}
break;
case VIRTKEY_SWAP_LAYOUT:
if (down) {
// Switch the active layout first, then release all inputs from the
// current view tree before it is recreated. RELEASE_ALL is not tied
// to the touch position, so a pointer still over a button won't keep
// the previous control latched during the layout transition.
g_Config.SwapTouchControlsLayouts();

TouchInput releaseTouch{};
releaseTouch.id = 0;
releaseTouch.flags = TouchInputFlags::RELEASE_ALL;
UIScreen::touch(releaseTouch);

System_PostUIMessage(UIMessage::RECREATE_VIEWS);
}
break;
case VIRTKEY_OPENCHAT:
if (down) {
if (g_Config.bEnableNetworkChat && !g_Config.bShowImDebugger) {
Expand Down Expand Up @@ -1249,7 +1265,7 @@ void EmuScreen::CreateViews() {

const DeviceOrientation deviceOrientation = GetDeviceOrientation();

TouchControlConfig &touch = g_Config.GetTouchControlsConfig(deviceOrientation);
TouchControlConfig &touch = g_Config.GetCurrentTouchControlsConfig(deviceOrientation);

const Bounds &bounds = GetLayoutBounds(*screenManager()->getUIContext());

Expand Down
34 changes: 32 additions & 2 deletions UI/GameSettingsScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -869,13 +869,43 @@ void GameSettingsScreen::CreateControlsSettings(UI::ViewGroup *controlsSettings)
});
gesture->SetEnabledPtr(&g_Config.bShowTouchControls);

static const char *touchControlStyles[] = { "Classic", "Thin borders", "Glowing borders" };
static const char *touchControlStyles[] = { "Classic", "Border" };
View *style = controlsSettings->Add(new PopupMultiChoice(&g_Config.iTouchButtonStyle, co->T("Button style"), touchControlStyles, 0, ARRAY_SIZE(touchControlStyles), I18NCat::CONTROLS, screenManager()));
style->SetEnabledPtr(&g_Config.bShowTouchControls);

static const char *touchAtlasScales[] = { "1x (Low)", "2x (Medium)", "3x (High)", "4x (Very High)" };
PopupMultiChoice *atlasScale = new PopupMultiChoice(&g_Config.iTouchButtonAtlasScale, co->T("Button icon quality"), touchAtlasScales, 1, ARRAY_SIZE(touchAtlasScales), I18NCat::CONTROLS, screenManager());
controlsSettings->Add(atlasScale);
atlasScale->SetEnabledPtr(&g_Config.bShowTouchControls);
atlasScale->OnChoice.Add([this](UI::EventParams &e) { screenManager()->getUIContext()->InvalidateAtlas(); });
CheckBox *disableTouchShadows = controlsSettings->Add(new CheckBox(&g_Config.bDisableTouchButtonShadows, co->T("Disable icon shadow")));
disableTouchShadows->SetEnabledPtr(&g_Config.bShowTouchControls);
disableTouchShadows->OnClick.Add([this](UI::EventParams &e) { screenManager()->getUIContext()->InvalidateAtlas(); });
CheckBox *disableTouchThemeColor = controlsSettings->Add(new CheckBox(&g_Config.bDisableTouchButtonThemeColor, co->T("Disable theme color on touch controls")));
disableTouchThemeColor->SetEnabledPtr(&g_Config.bShowTouchControls);

static const char *touchButtonPressedStyles[] = { "Glow", "Enlarge", "Shrink", "Ripple" };
View *pressedStyle = controlsSettings->Add(new PopupMultiChoice(&g_Config.iTouchButtonPressedStyle, co->T("Button pressed style"), touchButtonPressedStyles, 0, ARRAY_SIZE(touchButtonPressedStyles), I18NCat::CONTROLS, screenManager()));
pressedStyle->SetEnabledPtr(&g_Config.bShowTouchControls);

PopupSliderChoice *opacity = controlsSettings->Add(new PopupSliderChoice(&g_Config.iTouchButtonOpacity, 0, 100, 65, co->T("Button Opacity"), screenManager(), "%"));
opacity->SetEnabledPtr(&g_Config.bShowTouchControls);
opacity->SetFormat("%i%%");

PopupSliderChoice *surfaceAlpha = controlsSettings->Add(new PopupSliderChoice(&g_Config.iTouchButtonSurfaceAlpha, 0, 100, 25, co->T("Button fill opacity"), screenManager(), "%"));
surfaceAlpha->SetEnabledPtr(&g_Config.bShowTouchControls);
surfaceAlpha->SetFormat("%i%%");

PopupSliderChoice *analogHeadOpacity = controlsSettings->Add(new PopupSliderChoice(&g_Config.iTouchAnalogHeadOpacity, 0, 100, 65, co->T("Analog head opacity"), screenManager(), "%"));
analogHeadOpacity->SetEnabledPtr(&g_Config.bShowTouchControls);
analogHeadOpacity->SetFormat("%i%%");

PopupSliderChoice *enlargeScale = controlsSettings->Add(new PopupSliderChoice(&g_Config.iTouchButtonEnlargePercent, 100, 500, 150, co->T("Enlarge size"), screenManager(), "%"));
enlargeScale->SetFormat("%i%%");
enlargeScale->SetEnabledFunc([] { return g_Config.bShowTouchControls && g_Config.iTouchButtonPressedStyle == 1; });
PopupSliderChoice *shrinkScale = controlsSettings->Add(new PopupSliderChoice(&g_Config.iTouchButtonShrinkPercent, 1, 100, 67, co->T("Shrink size"), screenManager(), "%"));
shrinkScale->SetFormat("%i%%");
shrinkScale->SetEnabledFunc([] { return g_Config.bShowTouchControls && g_Config.iTouchButtonPressedStyle == 2; });
PopupSliderChoice *autoHide = controlsSettings->Add(new PopupSliderChoice(&g_Config.iTouchButtonHideSeconds, 0, 300, 20, co->T("Auto-hide buttons after delay"), screenManager(), di->T("seconds, 0:off")));
autoHide->SetEnabledPtr(&g_Config.bShowTouchControls);
autoHide->SetFormat(di->T("%d seconds"));
Expand All @@ -884,7 +914,7 @@ void GameSettingsScreen::CreateControlsSettings(UI::ViewGroup *controlsSettings)
CheckBox *touchGliding = controlsSettings->Add(new CheckBox(&g_Config.bTouchGliding, co->T("Keep first touched button pressed when dragging")));
touchGliding->SetEnabledPtr(&g_Config.bShowTouchControls);

TouchControlConfig &touch = g_Config.GetTouchControlsConfig(GetDeviceOrientation());
TouchControlConfig &touch = g_Config.GetCurrentTouchControlsConfig(GetDeviceOrientation());

// Hide stick background, useful when increasing the size
CheckBox *hideStickBackground = controlsSettings->Add(new CheckBox(&touch.bHideStickBackground, co->T("Hide touch analog stick background circle")));
Expand Down
Loading
Loading