diff options
| -rw-r--r-- | src/common/settings.cpp | 3 | ||||
| -rw-r--r-- | src/common/settings.h | 32 | ||||
| -rw-r--r-- | src/common/settings_common.h | 1 | ||||
| -rw-r--r-- | src/common/settings_enums.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/am/library_applet_creator.cpp | 51 | ||||
| -rw-r--r-- | src/frontend_common/config.cpp | 18 | ||||
| -rw-r--r-- | src/frontend_common/config.h | 2 | ||||
| -rw-r--r-- | src/yuzu/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_applets.cpp | 86 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_applets.h | 48 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_applets.ui | 65 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_dialog.cpp | 7 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_dialog.h | 2 | ||||
| -rw-r--r-- | src/yuzu/configuration/shared_translation.cpp | 22 | 
14 files changed, 334 insertions, 8 deletions
| diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 07709d4e5..80d388fe8 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -30,6 +30,7 @@ namespace Settings {  #define SETTING(TYPE, RANGED) template class Setting<TYPE, RANGED>  #define SWITCHABLE(TYPE, RANGED) template class SwitchableSetting<TYPE, RANGED> +SETTING(AppletMode, false);  SETTING(AudioEngine, false);  SETTING(bool, false);  SETTING(int, false); @@ -215,6 +216,8 @@ const char* TranslateCategory(Category category) {          return "Debugging";      case Category::GpuDriver:          return "GpuDriver"; +    case Category::LibraryApplet: +        return "LibraryApplet";      case Category::Miscellaneous:          return "Miscellaneous";      case Category::Network: diff --git a/src/common/settings.h b/src/common/settings.h index f1b1add56..aa054dc24 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -133,6 +133,38 @@ struct TouchFromButtonMap {  struct Values {      Linkage linkage{}; +    // Applet +    Setting<AppletMode> cabinet_applet_mode{linkage, AppletMode::LLE, "cabinet_applet_mode", +                                            Category::LibraryApplet}; +    Setting<AppletMode> controller_applet_mode{linkage, AppletMode::HLE, "controller_applet_mode", +                                               Category::LibraryApplet}; +    Setting<AppletMode> data_erase_applet_mode{linkage, AppletMode::HLE, "data_erase_applet_mode", +                                               Category::LibraryApplet}; +    Setting<AppletMode> error_applet_mode{linkage, AppletMode::HLE, "error_applet_mode", +                                          Category::LibraryApplet}; +    Setting<AppletMode> net_connect_applet_mode{linkage, AppletMode::HLE, "net_connect_applet_mode", +                                                Category::LibraryApplet}; +    Setting<AppletMode> player_select_applet_mode{ +        linkage, AppletMode::HLE, "player_select_applet_mode", Category::LibraryApplet}; +    Setting<AppletMode> swkbd_applet_mode{linkage, AppletMode::LLE, "swkbd_applet_mode", +                                          Category::LibraryApplet}; +    Setting<AppletMode> mii_edit_applet_mode{linkage, AppletMode::LLE, "mii_edit_applet_mode", +                                             Category::LibraryApplet}; +    Setting<AppletMode> web_applet_mode{linkage, AppletMode::HLE, "web_applet_mode", +                                        Category::LibraryApplet}; +    Setting<AppletMode> shop_applet_mode{linkage, AppletMode::HLE, "shop_applet_mode", +                                         Category::LibraryApplet}; +    Setting<AppletMode> photo_viewer_applet_mode{ +        linkage, AppletMode::LLE, "photo_viewer_applet_mode", Category::LibraryApplet}; +    Setting<AppletMode> offline_web_applet_mode{linkage, AppletMode::LLE, "offline_web_applet_mode", +                                                Category::LibraryApplet}; +    Setting<AppletMode> login_share_applet_mode{linkage, AppletMode::HLE, "login_share_applet_mode", +                                                Category::LibraryApplet}; +    Setting<AppletMode> wifi_web_auth_applet_mode{ +        linkage, AppletMode::HLE, "wifi_web_auth_applet_mode", Category::LibraryApplet}; +    Setting<AppletMode> my_page_applet_mode{linkage, AppletMode::LLE, "my_page_applet_mode", +                                            Category::LibraryApplet}; +      // Audio      SwitchableSetting<AudioEngine> sink_id{linkage, AudioEngine::Auto, "output_engine",                                             Category::Audio, Specialization::RuntimeList}; diff --git a/src/common/settings_common.h b/src/common/settings_common.h index 987489e8a..2df3f0809 100644 --- a/src/common/settings_common.h +++ b/src/common/settings_common.h @@ -44,6 +44,7 @@ enum class Category : u32 {      Services,      Paths,      Linux, +    LibraryApplet,      MaxEnum,  }; diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h index 617036588..f42367e67 100644 --- a/src/common/settings_enums.h +++ b/src/common/settings_enums.h @@ -151,6 +151,8 @@ ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch);  ENUM(ConsoleMode, Handheld, Docked); +ENUM(AppletMode, HLE, LLE); +  template <typename Type>  inline std::string CanonicalizeEnum(Type id) {      const auto group = EnumMetadata<Type>::Canonicalizations(); diff --git a/src/core/hle/service/am/library_applet_creator.cpp b/src/core/hle/service/am/library_applet_creator.cpp index ee646bea5..a883a021e 100644 --- a/src/core/hle/service/am/library_applet_creator.cpp +++ b/src/core/hle/service/am/library_applet_creator.cpp @@ -1,6 +1,7 @@  // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project  // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/settings.h"  #include "core/hle/kernel/k_transfer_memory.h"  #include "core/hle/service/am/applet_data_broker.h"  #include "core/hle/service/am/applet_manager.h" @@ -16,6 +17,34 @@ namespace Service::AM {  namespace { +bool ShouldCreateGuestApplet(AppletId applet_id) { +#define X(Name, name)                                                                              \ +    if (applet_id == AppletId::Name &&                                                             \ +        Settings::values.name##_applet_mode.GetValue() != Settings::AppletMode::LLE) {             \ +        return false;                                                                              \ +    } + +    X(Cabinet, cabinet) +    X(Controller, controller) +    X(DataErase, data_erase) +    X(Error, error) +    X(NetConnect, net_connect) +    X(ProfileSelect, player_select) +    X(SoftwareKeyboard, swkbd) +    X(MiiEdit, mii_edit) +    X(Web, web) +    X(Shop, shop) +    X(PhotoViewer, photo_viewer) +    X(OfflineWeb, offline_web) +    X(LoginShare, login_share) +    X(WebAuth, wifi_web_auth) +    X(MyPage, my_page) + +#undef X + +    return true; +} +  AppletProgramId AppletIdToProgramId(AppletId applet_id) {      switch (applet_id) {      case AppletId::OverlayDisplay: @@ -63,9 +92,10 @@ AppletProgramId AppletIdToProgramId(AppletId applet_id) {      }  } -[[maybe_unused]] std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet( -    Core::System& system, std::shared_ptr<Applet> caller_applet, AppletId applet_id, -    LibraryAppletMode mode) { +std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system, +                                                          std::shared_ptr<Applet> caller_applet, +                                                          AppletId applet_id, +                                                          LibraryAppletMode mode) {      const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));      if (program_id == 0) {          // Unknown applet @@ -117,9 +147,10 @@ AppletProgramId AppletIdToProgramId(AppletId applet_id) {      return std::make_shared<ILibraryAppletAccessor>(system, broker, applet);  } -[[maybe_unused]] std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet( -    Core::System& system, std::shared_ptr<Applet> caller_applet, AppletId applet_id, -    LibraryAppletMode mode) { +std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(Core::System& system, +                                                             std::shared_ptr<Applet> caller_applet, +                                                             AppletId applet_id, +                                                             LibraryAppletMode mode) {      const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));      auto process = std::make_unique<Process>(system); @@ -163,7 +194,13 @@ void ILibraryAppletCreator::CreateLibraryApplet(HLERequestContext& ctx) {      LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id,                applet_mode); -    auto library_applet = CreateFrontendApplet(system, applet, applet_id, applet_mode); +    std::shared_ptr<ILibraryAppletAccessor> library_applet; +    if (ShouldCreateGuestApplet(applet_id)) { +        library_applet = CreateGuestApplet(system, applet, applet_id, applet_mode); +    } +    if (!library_applet) { +        library_applet = CreateFrontendApplet(system, applet, applet_id, applet_mode); +    }      if (!library_applet) {          LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); diff --git a/src/frontend_common/config.cpp b/src/frontend_common/config.cpp index d34624d28..cbbb07ac7 100644 --- a/src/frontend_common/config.cpp +++ b/src/frontend_common/config.cpp @@ -401,6 +401,14 @@ void Config::ReadNetworkValues() {      EndGroup();  } +void Config::ReadLibraryAppletValues() { +    BeginGroup(Settings::TranslateCategory(Settings::Category::LibraryApplet)); + +    ReadCategory(Settings::Category::LibraryApplet); + +    EndGroup(); +} +  void Config::ReadValues() {      if (global) {          ReadDataStorageValues(); @@ -410,6 +418,7 @@ void Config::ReadValues() {          ReadServiceValues();          ReadWebServiceValues();          ReadMiscellaneousValues(); +        ReadLibraryAppletValues();      }      ReadControlValues();      ReadCoreValues(); @@ -511,6 +520,7 @@ void Config::SaveValues() {          SaveNetworkValues();          SaveWebServiceValues();          SaveMiscellaneousValues(); +        SaveLibraryAppletValues();      } else {          LOG_DEBUG(Config, "Saving only generic configuration values");      } @@ -691,6 +701,14 @@ void Config::SaveWebServiceValues() {      EndGroup();  } +void Config::SaveLibraryAppletValues() { +    BeginGroup(Settings::TranslateCategory(Settings::Category::LibraryApplet)); + +    WriteCategory(Settings::Category::LibraryApplet); + +    EndGroup(); +} +  bool Config::ReadBooleanSetting(const std::string& key, const std::optional<bool> default_value) {      std::string full_key = GetFullKey(key, false);      if (!default_value.has_value()) { diff --git a/src/frontend_common/config.h b/src/frontend_common/config.h index 4ecb97044..8b0599cc3 100644 --- a/src/frontend_common/config.h +++ b/src/frontend_common/config.h @@ -88,6 +88,7 @@ protected:      void ReadSystemValues();      void ReadWebServiceValues();      void ReadNetworkValues(); +    void ReadLibraryAppletValues();      // Read platform specific sections      virtual void ReadHidbusValues() = 0; @@ -121,6 +122,7 @@ protected:      void SaveScreenshotValues();      void SaveSystemValues();      void SaveWebServiceValues(); +    void SaveLibraryAppletValues();      // Save platform specific sections      virtual void SaveHidbusValues() = 0; diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 76f06da12..0259a8c29 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -41,6 +41,9 @@ add_executable(yuzu      configuration/configuration_shared.cpp      configuration/configuration_shared.h      configuration/configure.ui +    configuration/configure_applets.cpp +    configuration/configure_applets.h +    configuration/configure_applets.ui      configuration/configure_audio.cpp      configuration/configure_audio.h      configuration/configure_audio.ui diff --git a/src/yuzu/configuration/configure_applets.cpp b/src/yuzu/configuration/configure_applets.cpp new file mode 100644 index 000000000..513ecb548 --- /dev/null +++ b/src/yuzu/configuration/configure_applets.cpp @@ -0,0 +1,86 @@ +// SPDX-FileCopyrightText: 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/settings.h" +#include "core/core.h" +#include "ui_configure_applets.h" +#include "yuzu/configuration/configuration_shared.h" +#include "yuzu/configuration/configure_applets.h" +#include "yuzu/configuration/shared_widget.h" + +ConfigureApplets::ConfigureApplets(Core::System& system_, +                                   std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group_, +                                   const ConfigurationShared::Builder& builder, QWidget* parent) +    : Tab(group_, parent), ui{std::make_unique<Ui::ConfigureApplets>()}, system{system_} { +    ui->setupUi(this); + +    Setup(builder); + +    SetConfiguration(); +} + +ConfigureApplets::~ConfigureApplets() = default; + +void ConfigureApplets::changeEvent(QEvent* event) { +    if (event->type() == QEvent::LanguageChange) { +        RetranslateUI(); +    } + +    QWidget::changeEvent(event); +} + +void ConfigureApplets::RetranslateUI() { +    ui->retranslateUi(this); +} + +void ConfigureApplets::Setup(const ConfigurationShared::Builder& builder) { +    auto& library_applets_layout = *ui->group_library_applet_modes->layout(); +    std::map<u32, QWidget*> applets_hold{}; + +    std::vector<Settings::BasicSetting*> settings; +    auto push = [&settings](auto& list) { +        for (auto setting : list) { +            settings.push_back(setting); +        } +    }; + +    push(Settings::values.linkage.by_category[Settings::Category::LibraryApplet]); + +    for (auto setting : settings) { +        ConfigurationShared::Widget* widget = builder.BuildWidget(setting, apply_funcs); + +        if (widget == nullptr) { +            continue; +        } +        if (!widget->Valid()) { +            widget->deleteLater(); +            continue; +        } + +        // Untested applets +        if (setting->Id() == Settings::values.data_erase_applet_mode.Id() || +            setting->Id() == Settings::values.error_applet_mode.Id() || +            setting->Id() == Settings::values.net_connect_applet_mode.Id() || +            setting->Id() == Settings::values.web_applet_mode.Id() || +            setting->Id() == Settings::values.shop_applet_mode.Id() || +            setting->Id() == Settings::values.login_share_applet_mode.Id() || +            setting->Id() == Settings::values.wifi_web_auth_applet_mode.Id() || +            setting->Id() == Settings::values.my_page_applet_mode.Id()) { +            widget->setHidden(true); +        } + +        applets_hold.emplace(setting->Id(), widget); +    } +    for (const auto& [label, widget] : applets_hold) { +        library_applets_layout.addWidget(widget); +    } +} + +void ConfigureApplets::SetConfiguration() {} + +void ConfigureApplets::ApplyConfiguration() { +    const bool powered_on = system.IsPoweredOn(); +    for (const auto& func : apply_funcs) { +        func(powered_on); +    } +} diff --git a/src/yuzu/configuration/configure_applets.h b/src/yuzu/configuration/configure_applets.h new file mode 100644 index 000000000..54f494d2f --- /dev/null +++ b/src/yuzu/configuration/configure_applets.h @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <QWidget> +#include "yuzu/configuration/configuration_shared.h" + +class QCheckBox; +class QLineEdit; +class QComboBox; +class QDateTimeEdit; +namespace Core { +class System; +} + +namespace Ui { +class ConfigureApplets; +} + +namespace ConfigurationShared { +class Builder; +} + +class ConfigureApplets : public ConfigurationShared::Tab { +public: +    explicit ConfigureApplets(Core::System& system_, +                              std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group, +                              const ConfigurationShared::Builder& builder, +                              QWidget* parent = nullptr); +    ~ConfigureApplets() override; + +    void ApplyConfiguration() override; +    void SetConfiguration() override; + +private: +    void changeEvent(QEvent* event) override; +    void RetranslateUI(); + +    void Setup(const ConfigurationShared::Builder& builder); + +    std::vector<std::function<void(bool)>> apply_funcs{}; + +    std::unique_ptr<Ui::ConfigureApplets> ui; +    bool enabled = false; + +    Core::System& system; +}; diff --git a/src/yuzu/configuration/configure_applets.ui b/src/yuzu/configuration/configure_applets.ui new file mode 100644 index 000000000..6f2ca66bd --- /dev/null +++ b/src/yuzu/configuration/configure_applets.ui @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ConfigureApplets</class> + <widget class="QWidget" name="ConfigureApplets"> +  <property name="geometry"> +   <rect> +    <x>0</x> +    <y>0</y> +    <width>605</width> +    <height>300</height> +   </rect> +  </property> +  <property name="windowTitle"> +   <string>Form</string> +  </property> +  <property name="accessibleName"> +   <string>Applets</string> +  </property> +  <layout class="QVBoxLayout" name="verticalLayout_1"> +   <item> +    <layout class="QVBoxLayout" name="verticalLayout"> +     <item> +      <widget class="QGroupBox" name="group_library_applet_modes"> +       <property name="title"> +        <string>Applet mode preference</string> +       </property> +       <layout class="QVBoxLayout"> +        <item> +         <widget class="QWidget" name="applets_widget" native="true"> +          <layout class="QVBoxLayout" name="verticalLayout_3"> +           <property name="leftMargin"> +            <number>0</number> +           </property> +           <property name="topMargin"> +            <number>0</number> +           </property> +           <property name="rightMargin"> +            <number>0</number> +           </property> +          </layout> +         </widget> +        </item> +       </layout> +      </widget> +     </item> +    </layout> +   </item> +   <item> +    <spacer name="verticalSpacer"> +     <property name="orientation"> +      <enum>Qt::Vertical</enum> +     </property> +     <property name="sizeHint" stdset="0"> +      <size> +       <width>20</width> +       <height>40</height> +      </size> +     </property> +    </spacer> +   </item> +  </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index aab54a1cc..37f23388e 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -8,6 +8,7 @@  #include "core/core.h"  #include "ui_configure.h"  #include "vk_device_info.h" +#include "yuzu/configuration/configure_applets.h"  #include "yuzu/configuration/configure_audio.h"  #include "yuzu/configuration/configure_cpu.h"  #include "yuzu/configuration/configure_debug_tab.h" @@ -34,6 +35,7 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,      : QDialog(parent), ui{std::make_unique<Ui::ConfigureDialog>()},        registry(registry_), system{system_}, builder{std::make_unique<ConfigurationShared::Builder>(                                                  this, !system_.IsPoweredOn())}, +      applets_tab{std::make_unique<ConfigureApplets>(system_, nullptr, *builder, this)},        audio_tab{std::make_unique<ConfigureAudio>(system_, nullptr, *builder, this)},        cpu_tab{std::make_unique<ConfigureCpu>(system_, nullptr, *builder, this)},        debug_tab_tab{std::make_unique<ConfigureDebugTab>(system_, this)}, @@ -58,6 +60,7 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,      ui->setupUi(this); +    ui->tabWidget->addTab(applets_tab.get(), tr("Applets"));      ui->tabWidget->addTab(audio_tab.get(), tr("Audio"));      ui->tabWidget->addTab(cpu_tab.get(), tr("CPU"));      ui->tabWidget->addTab(debug_tab_tab.get(), tr("Debug")); @@ -124,6 +127,7 @@ void ConfigureDialog::ApplyConfiguration() {      debug_tab_tab->ApplyConfiguration();      web_tab->ApplyConfiguration();      network_tab->ApplyConfiguration(); +    applets_tab->ApplyConfiguration();      system.ApplySettings();      Settings::LogSettings();  } @@ -161,7 +165,8 @@ void ConfigureDialog::PopulateSelectionList() {          {{tr("General"),            {general_tab.get(), hotkeys_tab.get(), ui_tab.get(), web_tab.get(), debug_tab_tab.get()}},           {tr("System"), -          {system_tab.get(), profile_tab.get(), network_tab.get(), filesystem_tab.get()}}, +          {system_tab.get(), profile_tab.get(), network_tab.get(), filesystem_tab.get(), +           applets_tab.get()}},           {tr("CPU"), {cpu_tab.get()}},           {tr("Graphics"), {graphics_tab.get(), graphics_advanced_tab.get()}},           {tr("Audio"), {audio_tab.get()}}, diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h index b28ce288c..d0a24a07b 100644 --- a/src/yuzu/configuration/configure_dialog.h +++ b/src/yuzu/configuration/configure_dialog.h @@ -15,6 +15,7 @@ namespace Core {  class System;  } +class ConfigureApplets;  class ConfigureAudio;  class ConfigureCpu;  class ConfigureDebugTab; @@ -75,6 +76,7 @@ private:      std::unique_ptr<ConfigurationShared::Builder> builder;      std::vector<ConfigurationShared::Tab*> tab_group; +    std::unique_ptr<ConfigureApplets> applets_tab;      std::unique_ptr<ConfigureAudio> audio_tab;      std::unique_ptr<ConfigureCpu> cpu_tab;      std::unique_ptr<ConfigureDebugTab> debug_tab_tab; diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp index ed9c7d859..ce65b2bf1 100644 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/yuzu/configuration/shared_translation.cpp @@ -26,6 +26,23 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {      // A setting can be ignored by giving it a blank name +    // Applets +    INSERT(Settings, cabinet_applet_mode, tr("Amiibo editor"), QStringLiteral()); +    INSERT(Settings, controller_applet_mode, tr("Controller configuration"), QStringLiteral()); +    INSERT(Settings, data_erase_applet_mode, tr("Data erase"), QStringLiteral()); +    INSERT(Settings, error_applet_mode, tr("Error"), QStringLiteral()); +    INSERT(Settings, net_connect_applet_mode, tr("Net connect"), QStringLiteral()); +    INSERT(Settings, player_select_applet_mode, tr("Player select"), QStringLiteral()); +    INSERT(Settings, swkbd_applet_mode, tr("Software keyboard"), QStringLiteral()); +    INSERT(Settings, mii_edit_applet_mode, tr("Mii Edit"), QStringLiteral()); +    INSERT(Settings, web_applet_mode, tr("Online web"), QStringLiteral()); +    INSERT(Settings, shop_applet_mode, tr("Shop"), QStringLiteral()); +    INSERT(Settings, photo_viewer_applet_mode, tr("Photo viewer"), QStringLiteral()); +    INSERT(Settings, offline_web_applet_mode, tr("Offline web"), QStringLiteral()); +    INSERT(Settings, login_share_applet_mode, tr("Login share"), QStringLiteral()); +    INSERT(Settings, wifi_web_auth_applet_mode, tr("Wifi web auth"), QStringLiteral()); +    INSERT(Settings, my_page_applet_mode, tr("My page"), QStringLiteral()); +      // Audio      INSERT(Settings, sink_id, tr("Output Engine:"), QStringLiteral());      INSERT(Settings, audio_output_device_id, tr("Output Device:"), QStringLiteral()); @@ -203,6 +220,11 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {  #define PAIR(ENUM, VALUE, TRANSLATION) {static_cast<u32>(Settings::ENUM::VALUE), (TRANSLATION)}      // Intentionally skipping VSyncMode to let the UI fill that one out +    translations->insert({Settings::EnumMetadata<Settings::AppletMode>::Index(), +                          { +                              PAIR(AppletMode, HLE, tr("Custom frontend")), +                              PAIR(AppletMode, LLE, tr("Real applet")), +                          }});      translations->insert({Settings::EnumMetadata<Settings::AstcDecodeMode>::Index(),                            { | 
