2024-03-03 03:43:04 +00:00
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
2022-12-04 11:03:45 +00:00
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
2021-01-30 11:37:49 +00:00
# define IMGUI_DEFINE_MATH_OPERATORS
# include "fullscreen_ui.h"
2023-08-13 06:28:28 +00:00
# include "achievements.h"
# include "bios.h"
# include "cheats.h"
# include "controller.h"
# include "core/memory_card_image.h"
# include "cpu_core.h"
# include "game_list.h"
# include "gpu.h"
# include "host.h"
# include "resources.h"
# include "settings.h"
# include "system.h"
# include "scmversion/scmversion.h"
2024-04-09 10:04:45 +00:00
# include "util/cd_image.h"
2023-08-13 03:42:02 +00:00
# include "util/gpu_device.h"
2023-08-13 06:28:28 +00:00
# include "util/imgui_fullscreen.h"
# include "util/imgui_manager.h"
# include "util/ini_settings_interface.h"
# include "util/input_manager.h"
2023-08-27 12:48:40 +00:00
# include "util/postprocessing.h"
2023-08-13 06:28:28 +00:00
2021-01-30 11:37:49 +00:00
# include "common/byte_stream.h"
2023-08-27 12:48:40 +00:00
# include "common/error.h"
2021-01-30 11:37:49 +00:00
# include "common/file_system.h"
# include "common/log.h"
2022-07-08 11:57:06 +00:00
# include "common/path.h"
2023-09-20 13:49:14 +00:00
# include "common/small_string.h"
2021-01-30 11:37:49 +00:00
# include "common/string_util.h"
2022-09-17 05:51:05 +00:00
# include "common/threading.h"
2023-08-13 06:28:28 +00:00
# include "IconsFontAwesome5.h"
2024-02-05 13:34:34 +00:00
# include "IconsPromptFont.h"
2022-07-08 11:11:16 +00:00
# include "fmt/chrono.h"
# include "fmt/format.h"
2021-01-30 11:37:49 +00:00
# include "imgui.h"
# include "imgui_internal.h"
# include "imgui_stdlib.h"
2023-08-13 06:28:28 +00:00
2022-07-11 13:03:29 +00:00
# include <atomic>
2021-01-30 11:37:49 +00:00
# include <bitset>
2022-08-25 15:26:55 +00:00
# include <unordered_map>
2023-01-15 04:00:51 +00:00
# include <utility>
# include <vector>
2023-08-13 06:28:28 +00:00
2021-01-30 11:37:49 +00:00
Log_SetChannel ( FullscreenUI ) ;
2023-08-20 02:38:55 +00:00
# define TR_CONTEXT "FullscreenUI"
2023-09-20 13:49:14 +00:00
namespace {
2023-08-20 02:38:55 +00:00
template < size_t L >
2023-09-20 13:49:14 +00:00
class IconStackString : public SmallStackString < L >
2023-08-20 02:38:55 +00:00
{
public :
ALWAYS_INLINE IconStackString ( const char * icon , const char * str )
{
2023-12-13 11:06:15 +00:00
SmallStackString < L > : : format ( " {} {} " , icon , Host : : TranslateToStringView ( TR_CONTEXT , str ) ) ;
2023-09-20 13:49:14 +00:00
}
ALWAYS_INLINE IconStackString ( const char * icon , const char * str , const char * suffix )
{
2023-12-13 11:06:15 +00:00
SmallStackString < L > : : format ( " {} {}##{} " , icon , Host : : TranslateToStringView ( TR_CONTEXT , str ) , suffix ) ;
2023-08-20 02:38:55 +00:00
}
} ;
2023-09-20 13:49:14 +00:00
} // namespace
2023-08-20 02:38:55 +00:00
2023-09-20 13:49:14 +00:00
# define FSUI_ICONSTR(icon, str) IconStackString<128>(icon, str).c_str()
2023-08-20 02:38:55 +00:00
# define FSUI_STR(str) Host::TranslateToString(TR_CONTEXT, str)
# define FSUI_CSTR(str) Host::TranslateToCString(TR_CONTEXT, str)
# define FSUI_VSTR(str) Host::TranslateToStringView(TR_CONTEXT, str)
# define FSUI_FSTR(str) fmt::runtime(Host::TranslateToStringView(TR_CONTEXT, str))
# define FSUI_NSTR(str) str
2021-01-30 11:37:49 +00:00
using ImGuiFullscreen : : g_large_font ;
2021-02-21 16:38:16 +00:00
using ImGuiFullscreen : : g_layout_padding_left ;
using ImGuiFullscreen : : g_layout_padding_top ;
2021-01-30 11:37:49 +00:00
using ImGuiFullscreen : : g_medium_font ;
2024-04-09 10:04:45 +00:00
using ImGuiFullscreen : : LAYOUT_FOOTER_HEIGHT ;
2021-01-30 11:37:49 +00:00
using ImGuiFullscreen : : LAYOUT_LARGE_FONT_SIZE ;
using ImGuiFullscreen : : LAYOUT_MEDIUM_FONT_SIZE ;
2021-01-31 07:40:50 +00:00
using ImGuiFullscreen : : LAYOUT_MENU_BUTTON_HEIGHT ;
using ImGuiFullscreen : : LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ;
2021-02-01 15:40:37 +00:00
using ImGuiFullscreen : : LAYOUT_MENU_BUTTON_X_PADDING ;
using ImGuiFullscreen : : LAYOUT_MENU_BUTTON_Y_PADDING ;
2021-01-30 11:37:49 +00:00
using ImGuiFullscreen : : LAYOUT_SCREEN_HEIGHT ;
using ImGuiFullscreen : : LAYOUT_SCREEN_WIDTH ;
2022-07-11 13:03:29 +00:00
using ImGuiFullscreen : : UIBackgroundColor ;
using ImGuiFullscreen : : UIBackgroundHighlightColor ;
using ImGuiFullscreen : : UIBackgroundLineColor ;
using ImGuiFullscreen : : UIBackgroundTextColor ;
using ImGuiFullscreen : : UIDisabledColor ;
using ImGuiFullscreen : : UIPrimaryColor ;
using ImGuiFullscreen : : UIPrimaryDarkColor ;
using ImGuiFullscreen : : UIPrimaryLightColor ;
using ImGuiFullscreen : : UIPrimaryLineColor ;
using ImGuiFullscreen : : UIPrimaryTextColor ;
using ImGuiFullscreen : : UISecondaryColor ;
2023-09-19 14:09:31 +00:00
using ImGuiFullscreen : : UISecondaryStrongColor ;
2022-07-11 13:03:29 +00:00
using ImGuiFullscreen : : UISecondaryTextColor ;
2023-09-20 07:10:41 +00:00
using ImGuiFullscreen : : UISecondaryWeakColor ;
2022-07-11 13:03:29 +00:00
using ImGuiFullscreen : : UITextHighlightColor ;
2021-01-30 11:37:49 +00:00
using ImGuiFullscreen : : ActiveButton ;
2022-07-11 13:03:29 +00:00
using ImGuiFullscreen : : AddNotification ;
2021-01-30 11:37:49 +00:00
using ImGuiFullscreen : : BeginFullscreenColumns ;
using ImGuiFullscreen : : BeginFullscreenColumnWindow ;
using ImGuiFullscreen : : BeginFullscreenWindow ;
2024-04-09 10:04:45 +00:00
using ImGuiFullscreen : : BeginHorizontalMenu ;
2021-01-30 11:37:49 +00:00
using ImGuiFullscreen : : BeginMenuButtons ;
2021-06-30 09:12:56 +00:00
using ImGuiFullscreen : : BeginNavBar ;
2022-07-11 13:03:29 +00:00
using ImGuiFullscreen : : CenterImage ;
2021-01-30 11:37:49 +00:00
using ImGuiFullscreen : : CloseChoiceDialog ;
using ImGuiFullscreen : : CloseFileSelector ;
2022-10-23 04:09:54 +00:00
using ImGuiFullscreen : : DrawShadowedText ;
2021-01-30 11:37:49 +00:00
using ImGuiFullscreen : : EndFullscreenColumns ;
using ImGuiFullscreen : : EndFullscreenColumnWindow ;
using ImGuiFullscreen : : EndFullscreenWindow ;
2024-04-09 10:04:45 +00:00
using ImGuiFullscreen : : EndHorizontalMenu ;
2021-01-30 11:37:49 +00:00
using ImGuiFullscreen : : EndMenuButtons ;
2021-06-30 09:12:56 +00:00
using ImGuiFullscreen : : EndNavBar ;
2021-01-30 11:37:49 +00:00
using ImGuiFullscreen : : EnumChoiceButton ;
2021-02-24 16:08:01 +00:00
using ImGuiFullscreen : : FloatingButton ;
2024-04-09 10:04:45 +00:00
using ImGuiFullscreen : : ForceKeyNavEnabled ;
2022-03-26 13:51:37 +00:00
using ImGuiFullscreen : : GetCachedTexture ;
2022-07-11 13:03:29 +00:00
using ImGuiFullscreen : : GetCachedTextureAsync ;
using ImGuiFullscreen : : GetPlaceholderTexture ;
2024-04-09 10:04:45 +00:00
using ImGuiFullscreen : : HorizontalMenuItem ;
using ImGuiFullscreen : : IsFocusResetQueued ;
using ImGuiFullscreen : : IsGamepadInputSource ;
2021-01-30 11:37:49 +00:00
using ImGuiFullscreen : : LayoutScale ;
2022-07-11 13:03:29 +00:00
using ImGuiFullscreen : : LoadTexture ;
2021-01-30 11:37:49 +00:00
using ImGuiFullscreen : : MenuButton ;
using ImGuiFullscreen : : MenuButtonFrame ;
2022-09-17 05:51:05 +00:00
using ImGuiFullscreen : : MenuButtonWithoutSummary ;
2021-01-30 11:37:49 +00:00
using ImGuiFullscreen : : MenuButtonWithValue ;
using ImGuiFullscreen : : MenuHeading ;
2021-03-02 16:25:58 +00:00
using ImGuiFullscreen : : MenuHeadingButton ;
2021-01-30 11:37:49 +00:00
using ImGuiFullscreen : : MenuImageButton ;
2022-09-17 05:51:05 +00:00
using ImGuiFullscreen : : ModAlpha ;
using ImGuiFullscreen : : MulAlpha ;
2021-06-30 09:12:56 +00:00
using ImGuiFullscreen : : NavButton ;
2023-09-07 10:13:48 +00:00
using ImGuiFullscreen : : NavTab ;
2021-06-30 09:12:56 +00:00
using ImGuiFullscreen : : NavTitle ;
2021-01-30 11:37:49 +00:00
using ImGuiFullscreen : : OpenChoiceDialog ;
2022-10-13 14:14:21 +00:00
using ImGuiFullscreen : : OpenConfirmMessageDialog ;
2021-01-30 11:37:49 +00:00
using ImGuiFullscreen : : OpenFileSelector ;
2022-08-27 04:42:16 +00:00
using ImGuiFullscreen : : OpenInputStringDialog ;
2022-07-11 13:03:29 +00:00
using ImGuiFullscreen : : PopPrimaryColor ;
using ImGuiFullscreen : : PushPrimaryColor ;
using ImGuiFullscreen : : QueueResetFocus ;
2021-01-30 11:37:49 +00:00
using ImGuiFullscreen : : RangeButton ;
2022-07-11 13:03:29 +00:00
using ImGuiFullscreen : : ResetFocusHere ;
2021-06-30 09:12:56 +00:00
using ImGuiFullscreen : : RightAlignNavButtons ;
2024-04-09 10:04:45 +00:00
using ImGuiFullscreen : : SetFullscreenFooterText ;
2022-07-11 13:03:29 +00:00
using ImGuiFullscreen : : ShowToast ;
using ImGuiFullscreen : : ThreeWayToggleButton ;
2021-01-30 11:37:49 +00:00
using ImGuiFullscreen : : ToggleButton ;
2022-07-11 13:03:29 +00:00
using ImGuiFullscreen : : WantsToCloseMenu ;
2021-01-30 11:37:49 +00:00
2022-08-10 03:05:28 +00:00
# ifndef __ANDROID__
2021-01-30 11:37:49 +00:00
namespace FullscreenUI {
2022-07-11 13:03:29 +00:00
enum class MainWindowType
{
None ,
Landing ,
2024-04-09 10:04:45 +00:00
StartGame ,
Exit ,
2022-07-11 13:03:29 +00:00
GameList ,
2024-04-09 10:04:45 +00:00
GameListSettings ,
2022-07-11 13:03:29 +00:00
Settings ,
PauseMenu ,
Achievements ,
Leaderboards ,
} ;
enum class PauseSubMenu
{
None ,
Exit ,
Achievements ,
} ;
enum class SettingsPage
{
Summary ,
Interface ,
Console ,
Emulation ,
BIOS ,
Controller ,
Hotkey ,
MemoryCards ,
Display ,
2022-10-13 14:14:21 +00:00
PostProcessing ,
2022-07-11 13:03:29 +00:00
Audio ,
Achievements ,
Advanced ,
Count
} ;
2024-04-09 10:04:45 +00:00
enum class GameListView
2022-09-17 05:51:05 +00:00
{
Grid ,
List ,
Count
} ;
2023-08-27 12:48:40 +00:00
struct PostProcessingStageInfo
{
std : : string name ;
std : : vector < PostProcessing : : ShaderOption > options ;
} ;
2021-01-30 11:37:49 +00:00
//////////////////////////////////////////////////////////////////////////
// Main
//////////////////////////////////////////////////////////////////////////
2023-09-18 12:29:47 +00:00
static void PauseForMenuOpen ( bool set_pause_menu_open ) ;
2024-04-09 10:04:45 +00:00
static bool AreAnyDialogsOpen ( ) ;
2022-07-11 13:03:29 +00:00
static void ClosePauseMenu ( ) ;
static void OpenPauseSubMenu ( PauseSubMenu submenu ) ;
2024-04-09 10:04:45 +00:00
static void DrawLandingTemplate ( ImVec2 * menu_pos , ImVec2 * menu_size ) ;
2021-01-30 11:37:49 +00:00
static void DrawLandingWindow ( ) ;
2024-04-09 10:04:45 +00:00
static void DrawStartGameWindow ( ) ;
static void DrawExitWindow ( ) ;
2023-09-18 12:29:47 +00:00
static void DrawPauseMenu ( ) ;
2022-08-25 15:26:55 +00:00
static void ExitFullscreenAndOpenURL ( const std : : string_view & url ) ;
static void CopyTextToClipboard ( std : : string title , const std : : string_view & text ) ;
2021-01-30 11:37:49 +00:00
static void DrawAboutWindow ( ) ;
static void OpenAboutWindow ( ) ;
2023-12-14 06:07:57 +00:00
static void FixStateIfPaused ( ) ;
2024-04-09 10:04:45 +00:00
static void GetStandardSelectionFooterText ( SmallStringBase & dest , bool back_instead_of_cancel ) ;
2021-03-03 09:14:01 +00:00
2022-07-11 13:03:29 +00:00
static MainWindowType s_current_main_window = MainWindowType : : None ;
static PauseSubMenu s_current_pause_submenu = PauseSubMenu : : None ;
static std : : string s_current_game_subtitle ;
static bool s_initialized = false ;
static bool s_tried_to_initialize = false ;
static bool s_pause_menu_was_open = false ;
2021-01-30 11:37:49 +00:00
static bool s_was_paused_on_quick_menu_open = false ;
static bool s_about_window_open = false ;
//////////////////////////////////////////////////////////////////////////
// Resources
//////////////////////////////////////////////////////////////////////////
static bool LoadResources ( ) ;
static void DestroyResources ( ) ;
2022-10-03 06:44:34 +00:00
static std : : shared_ptr < GPUTexture > s_app_icon_texture ;
static std : : array < std : : shared_ptr < GPUTexture > , static_cast < u32 > ( GameDatabase : : CompatibilityRating : : Count ) >
2021-01-30 11:37:49 +00:00
s_game_compatibility_textures ;
2022-10-03 06:44:34 +00:00
static std : : shared_ptr < GPUTexture > s_fallback_disc_texture ;
static std : : shared_ptr < GPUTexture > s_fallback_exe_texture ;
static std : : shared_ptr < GPUTexture > s_fallback_psf_texture ;
static std : : shared_ptr < GPUTexture > s_fallback_playlist_texture ;
2021-01-30 11:37:49 +00:00
//////////////////////////////////////////////////////////////////////////
2022-07-11 13:03:29 +00:00
// Landing
2021-01-30 11:37:49 +00:00
//////////////////////////////////////////////////////////////////////////
2022-07-11 13:03:29 +00:00
static void SwitchToLanding ( ) ;
static ImGuiFullscreen : : FileSelectorFilters GetDiscImageFilters ( ) ;
static void DoStartPath ( std : : string path , std : : string state = std : : string ( ) ,
std : : optional < bool > fast_boot = std : : nullopt ) ;
static void DoResume ( ) ;
static void DoStartFile ( ) ;
static void DoStartBIOS ( ) ;
2024-04-09 10:04:45 +00:00
static void DoStartDisc ( std : : string path ) ;
static void DoStartDisc ( ) ;
2022-07-11 13:03:29 +00:00
static void DoToggleFastForward ( ) ;
static void DoShutdown ( bool save_state ) ;
static void DoReset ( ) ;
static void DoChangeDiscFromFile ( ) ;
static void DoChangeDisc ( ) ;
static void DoRequestExit ( ) ;
2024-04-09 10:04:45 +00:00
static void DoDesktopMode ( ) ;
2022-07-11 13:03:29 +00:00
static void DoToggleFullscreen ( ) ;
2022-07-30 02:58:03 +00:00
static void DoCheatsMenu ( ) ;
static void DoToggleAnalogMode ( ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
//////////////////////////////////////////////////////////////////////////
// Settings
//////////////////////////////////////////////////////////////////////////
2021-01-30 11:37:49 +00:00
static constexpr double INPUT_BINDING_TIMEOUT_SECONDS = 5.0 ;
2022-07-11 13:03:29 +00:00
static void SwitchToSettings ( ) ;
static void SwitchToGameSettings ( ) ;
static void SwitchToGameSettings ( const GameList : : Entry * entry ) ;
static void SwitchToGameSettingsForPath ( const std : : string & path ) ;
static void SwitchToGameSettingsForSerial ( const std : : string_view & serial ) ;
2021-01-30 11:37:49 +00:00
static void DrawSettingsWindow ( ) ;
2022-07-11 13:03:29 +00:00
static void DrawSummarySettingsPage ( ) ;
static void DrawInterfaceSettingsPage ( ) ;
static void DrawBIOSSettingsPage ( ) ;
static void DrawConsoleSettingsPage ( ) ;
static void DrawEmulationSettingsPage ( ) ;
static void DrawDisplaySettingsPage ( ) ;
2022-10-13 14:14:21 +00:00
static void DrawPostProcessingSettingsPage ( ) ;
2022-07-11 13:03:29 +00:00
static void DrawAudioSettingsPage ( ) ;
static void DrawMemoryCardSettingsPage ( ) ;
static void DrawControllerSettingsPage ( ) ;
static void DrawHotkeySettingsPage ( ) ;
static void DrawAchievementsSettingsPage ( ) ;
static void DrawAdvancedSettingsPage ( ) ;
2022-08-25 15:26:55 +00:00
static bool IsEditingGameSettings ( SettingsInterface * bsi ) ;
2022-07-11 13:03:29 +00:00
static SettingsInterface * GetEditingSettingsInterface ( ) ;
2022-08-25 15:26:55 +00:00
static SettingsInterface * GetEditingSettingsInterface ( bool game_settings ) ;
static void SetSettingsChanged ( SettingsInterface * bsi ) ;
static bool GetEffectiveBoolSetting ( SettingsInterface * bsi , const char * section , const char * key , bool default_value ) ;
static s32 GetEffectiveIntSetting ( SettingsInterface * bsi , const char * section , const char * key , s32 default_value ) ;
static u32 GetEffectiveUIntSetting ( SettingsInterface * bsi , const char * section , const char * key , u32 default_value ) ;
static float GetEffectiveFloatSetting ( SettingsInterface * bsi , const char * section , const char * key ,
float default_value ) ;
2024-04-07 10:43:13 +00:00
static TinyString GetEffectiveTinyStringSetting ( SettingsInterface * bsi , const char * section , const char * key ,
const char * default_value ) ;
2022-07-11 13:03:29 +00:00
static void DoCopyGameSettings ( ) ;
static void DoClearGameSettings ( ) ;
2022-08-25 15:26:55 +00:00
static void CopyGlobalControllerSettingsToGame ( ) ;
static void ResetControllerSettings ( ) ;
2022-08-27 04:42:16 +00:00
static void DoLoadInputProfile ( ) ;
static void DoSaveInputProfile ( ) ;
2024-04-07 10:43:13 +00:00
static void DoSaveNewInputProfile ( ) ;
2022-08-27 04:42:16 +00:00
static void DoSaveInputProfile ( const std : : string & name ) ;
2022-07-11 13:03:29 +00:00
2022-08-25 15:26:55 +00:00
static bool DrawToggleSetting ( SettingsInterface * bsi , const char * title , const char * summary , const char * section ,
const char * key , bool default_value , bool enabled = true , bool allow_tristate = true ,
2022-07-11 13:03:29 +00:00
float height = ImGuiFullscreen : : LAYOUT_MENU_BUTTON_HEIGHT , ImFont * font = g_large_font ,
ImFont * summary_font = g_medium_font ) ;
2022-08-25 15:26:55 +00:00
static void DrawIntListSetting ( SettingsInterface * bsi , const char * title , const char * summary , const char * section ,
const char * key , int default_value , const char * const * options , size_t option_count ,
2023-09-03 03:20:38 +00:00
bool translate_options , int option_offset = 0 , bool enabled = true ,
2022-07-11 13:03:29 +00:00
float height = ImGuiFullscreen : : LAYOUT_MENU_BUTTON_HEIGHT , ImFont * font = g_large_font ,
2023-09-16 09:06:59 +00:00
ImFont * summary_font = g_medium_font , const char * tr_context = TR_CONTEXT ) ;
2022-08-25 15:26:55 +00:00
static void DrawIntRangeSetting ( SettingsInterface * bsi , const char * title , const char * summary , const char * section ,
const char * key , int default_value , int min_value , int max_value ,
const char * format = " %d " , bool enabled = true ,
float height = ImGuiFullscreen : : LAYOUT_MENU_BUTTON_HEIGHT , ImFont * font = g_large_font ,
ImFont * summary_font = g_medium_font ) ;
2022-10-23 04:09:54 +00:00
static void DrawIntSpinBoxSetting ( SettingsInterface * bsi , const char * title , const char * summary , const char * section ,
const char * key , int default_value , int min_value , int max_value , int step_value ,
const char * format = " %d " , bool enabled = true ,
float height = ImGuiFullscreen : : LAYOUT_MENU_BUTTON_HEIGHT ,
ImFont * font = g_large_font , ImFont * summary_font = g_medium_font ) ;
2022-08-25 15:26:55 +00:00
static void DrawFloatRangeSetting ( SettingsInterface * bsi , const char * title , const char * summary , const char * section ,
const char * key , float default_value , float min_value , float max_value ,
const char * format = " %f " , float multiplier = 1.0f , bool enabled = true ,
float height = ImGuiFullscreen : : LAYOUT_MENU_BUTTON_HEIGHT ,
2022-07-11 13:03:29 +00:00
ImFont * font = g_large_font , ImFont * summary_font = g_medium_font ) ;
2022-10-31 08:08:26 +00:00
static void DrawFloatSpinBoxSetting ( SettingsInterface * bsi , const char * title , const char * summary , const char * section ,
const char * key , float default_value , float min_value , float max_value ,
float step_value , float multiplier , const char * format = " %f " , bool enabled = true ,
float height = ImGuiFullscreen : : LAYOUT_MENU_BUTTON_HEIGHT ,
ImFont * font = g_large_font , ImFont * summary_font = g_medium_font ) ;
2022-12-20 11:26:19 +00:00
#if 0
2022-08-25 15:26:55 +00:00
static void DrawIntRectSetting ( SettingsInterface * bsi , const char * title , const char * summary , const char * section ,
const char * left_key , int default_left , const char * top_key , int default_top ,
const char * right_key , int default_right , const char * bottom_key , int default_bottom ,
int min_value , int max_value , const char * format = " %d " , bool enabled = true ,
2022-07-11 13:03:29 +00:00
float height = ImGuiFullscreen : : LAYOUT_MENU_BUTTON_HEIGHT , ImFont * font = g_large_font ,
ImFont * summary_font = g_medium_font ) ;
2022-08-25 15:26:55 +00:00
static void DrawStringListSetting ( SettingsInterface * bsi , const char * title , const char * summary , const char * section ,
const char * key , const char * default_value , const char * const * options ,
2022-07-11 13:03:29 +00:00
const char * const * option_values , size_t option_count , bool enabled = true ,
float height = ImGuiFullscreen : : LAYOUT_MENU_BUTTON_HEIGHT ,
ImFont * font = g_large_font , ImFont * summary_font = g_medium_font ) ;
2022-12-20 11:26:19 +00:00
# endif
2022-07-11 13:03:29 +00:00
template < typename DataType , typename SizeType >
2022-08-25 15:26:55 +00:00
static void DrawEnumSetting ( SettingsInterface * bsi , const char * title , const char * summary , const char * section ,
const char * key , DataType default_value ,
std : : optional < DataType > ( * from_string_function ) ( const char * str ) ,
2022-07-11 13:03:29 +00:00
const char * ( * to_string_function ) ( DataType value ) ,
const char * ( * to_display_string_function ) ( DataType value ) , SizeType option_count ,
bool enabled = true , float height = ImGuiFullscreen : : LAYOUT_MENU_BUTTON_HEIGHT ,
ImFont * font = g_large_font , ImFont * summary_font = g_medium_font ) ;
2022-08-25 15:26:55 +00:00
static void DrawFloatListSetting ( SettingsInterface * bsi , const char * title , const char * summary , const char * section ,
const char * key , float default_value , const char * const * options ,
2023-09-03 03:20:38 +00:00
const float * option_values , size_t option_count , bool translate_options ,
bool enabled = true , float height = ImGuiFullscreen : : LAYOUT_MENU_BUTTON_HEIGHT ,
ImFont * font = g_large_font , ImFont * summary_font = g_medium_font ) ;
2022-08-25 15:26:55 +00:00
static void DrawFolderSetting ( SettingsInterface * bsi , const char * title , const char * section , const char * key ,
const std : : string & runtime_var , float height = ImGuiFullscreen : : LAYOUT_MENU_BUTTON_HEIGHT ,
ImFont * font = g_large_font , ImFont * summary_font = g_medium_font ) ;
2022-07-11 13:03:29 +00:00
static void PopulateGraphicsAdapterList ( ) ;
static void PopulateGameListDirectoryCache ( SettingsInterface * si ) ;
2023-08-27 12:48:40 +00:00
static void PopulatePostProcessingChain ( SettingsInterface * si ) ;
2023-01-15 04:00:51 +00:00
static void BeginInputBinding ( SettingsInterface * bsi , InputBindingInfo : : Type type , const std : : string_view & section ,
const std : : string_view & key , const std : : string_view & display_name ) ;
2021-01-30 11:37:49 +00:00
static void DrawInputBindingWindow ( ) ;
2023-01-15 04:00:51 +00:00
static void DrawInputBindingButton ( SettingsInterface * bsi , InputBindingInfo : : Type type , const char * section ,
2023-11-26 10:30:10 +00:00
const char * name , const char * display_name , const char * icon_name ,
bool show_type = true ) ;
2022-07-11 13:03:29 +00:00
static void ClearInputBindingVariables ( ) ;
static void StartAutomaticBinding ( u32 port ) ;
static SettingsPage s_settings_page = SettingsPage : : Interface ;
static std : : unique_ptr < INISettingsInterface > s_game_settings_interface ;
static std : : unique_ptr < GameList : : Entry > s_game_settings_entry ;
static std : : vector < std : : pair < std : : string , bool > > s_game_list_directories_cache ;
static std : : vector < std : : string > s_graphics_adapter_list_cache ;
static std : : vector < std : : string > s_fullscreen_mode_list_cache ;
2023-08-27 12:48:40 +00:00
static std : : vector < PostProcessingStageInfo > s_postprocessing_stages ;
2022-07-11 13:03:29 +00:00
static std : : vector < const HotkeyInfo * > s_hotkey_list_cache ;
static std : : atomic_bool s_settings_changed { false } ;
2022-08-25 15:26:55 +00:00
static std : : atomic_bool s_game_settings_changed { false } ;
2023-01-15 04:00:51 +00:00
static InputBindingInfo : : Type s_input_binding_type = InputBindingInfo : : Type : : Unknown ;
2022-07-11 13:03:29 +00:00
static std : : string s_input_binding_section ;
static std : : string s_input_binding_key ;
static std : : string s_input_binding_display_name ;
static std : : vector < InputBindingKey > s_input_binding_new_bindings ;
2023-01-15 04:00:51 +00:00
static std : : vector < std : : pair < InputBindingKey , std : : pair < float , float > > > s_input_binding_value_ranges ;
2021-01-30 11:37:49 +00:00
static Common : : Timer s_input_binding_timer ;
//////////////////////////////////////////////////////////////////////////
// Save State List
//////////////////////////////////////////////////////////////////////////
struct SaveStateListEntry
{
std : : string title ;
std : : string summary ;
std : : string path ;
2022-10-03 06:44:34 +00:00
std : : unique_ptr < GPUTexture > preview_texture ;
2022-09-17 05:51:05 +00:00
time_t timestamp ;
2021-01-30 11:37:49 +00:00
s32 slot ;
bool global ;
} ;
2024-04-09 10:04:45 +00:00
static void InitializePlaceholderSaveStateListEntry ( SaveStateListEntry * li , const std : : string & serial , s32 slot ,
bool global ) ;
static bool InitializeSaveStateListEntryFromSerial ( SaveStateListEntry * li , const std : : string & serial , s32 slot ,
bool global ) ;
static bool InitializeSaveStateListEntryFromPath ( SaveStateListEntry * li , std : : string path , s32 slot , bool global ) ;
2022-07-11 13:03:29 +00:00
static void PopulateSaveStateScreenshot ( SaveStateListEntry * li , const ExtendedSaveStateInfo * ssi ) ;
static void ClearSaveStateEntryList ( ) ;
static u32 PopulateSaveStateListEntries ( const std : : string & title , const std : : string & serial ) ;
static bool OpenLoadStateSelectorForGame ( const std : : string & game_path ) ;
static bool OpenSaveStateSelector ( bool is_loading ) ;
2021-01-30 11:37:49 +00:00
static void CloseSaveStateSelector ( ) ;
2022-10-23 04:09:54 +00:00
static void DrawSaveStateSelector ( bool is_loading ) ;
2022-09-17 05:51:05 +00:00
static bool OpenLoadStateSelectorForGameResume ( const GameList : : Entry * entry ) ;
static void DrawResumeStateSelector ( ) ;
2022-07-11 13:03:29 +00:00
static void DoLoadState ( std : : string path ) ;
static void DoSaveState ( s32 slot , bool global ) ;
2021-01-30 11:37:49 +00:00
static std : : vector < SaveStateListEntry > s_save_state_selector_slots ;
2022-07-11 13:03:29 +00:00
static std : : string s_save_state_selector_game_path ;
2022-10-23 04:09:54 +00:00
static s32 s_save_state_selector_submenu_index = - 1 ;
2021-01-30 11:37:49 +00:00
static bool s_save_state_selector_open = false ;
static bool s_save_state_selector_loading = true ;
2022-09-17 05:51:05 +00:00
static bool s_save_state_selector_resuming = false ;
2021-01-30 11:37:49 +00:00
//////////////////////////////////////////////////////////////////////////
// Game List
//////////////////////////////////////////////////////////////////////////
static void DrawGameListWindow ( ) ;
2022-09-17 05:51:05 +00:00
static void DrawGameList ( const ImVec2 & heading_size ) ;
static void DrawGameGrid ( const ImVec2 & heading_size ) ;
static void HandleGameListActivate ( const GameList : : Entry * entry ) ;
static void HandleGameListOptions ( const GameList : : Entry * entry ) ;
2024-04-09 10:04:45 +00:00
static void DrawGameListSettingsWindow ( ) ;
2021-01-30 11:37:49 +00:00
static void SwitchToGameList ( ) ;
2022-07-11 13:03:29 +00:00
static void PopulateGameListEntryList ( ) ;
2022-10-03 06:44:34 +00:00
static GPUTexture * GetTextureForGameListEntryType ( GameList : : EntryType type ) ;
static GPUTexture * GetGameListCover ( const GameList : : Entry * entry ) ;
static GPUTexture * GetCoverForCurrentGame ( ) ;
2021-01-30 11:37:49 +00:00
// Lazily populated cover images.
2021-02-27 06:25:42 +00:00
static std : : unordered_map < std : : string , std : : string > s_cover_image_map ;
2022-07-11 13:03:29 +00:00
static std : : vector < const GameList : : Entry * > s_game_list_sorted_entries ;
2024-04-09 10:04:45 +00:00
static GameListView s_game_list_view = GameListView : : Grid ;
2022-07-11 13:03:29 +00:00
} // namespace FullscreenUI
2022-08-25 15:26:55 +00:00
//////////////////////////////////////////////////////////////////////////
// Utility
//////////////////////////////////////////////////////////////////////////
2023-09-20 13:49:14 +00:00
void FullscreenUI : : TimeToPrintableString ( SmallStringBase * str , time_t t )
2022-08-25 15:26:55 +00:00
{
struct tm lt = { } ;
# ifdef _MSC_VER
localtime_s ( & lt , & t ) ;
# else
localtime_r ( & t , & lt ) ;
# endif
char buf [ 256 ] ;
std : : strftime ( buf , sizeof ( buf ) , " %c " , & lt ) ;
2023-09-20 13:49:14 +00:00
str - > assign ( buf ) ;
2022-08-25 15:26:55 +00:00
}
2024-04-09 10:04:45 +00:00
void FullscreenUI : : GetStandardSelectionFooterText ( SmallStringBase & dest , bool back_instead_of_cancel )
{
if ( IsGamepadInputSource ( ) )
{
ImGuiFullscreen : : CreateFooterTextString (
dest ,
std : : array { std : : make_pair ( ICON_PF_XBOX_DPAD_UP_DOWN , FSUI_VSTR ( " Change Selection " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_A , FSUI_VSTR ( " Select " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_B , back_instead_of_cancel ? FSUI_VSTR ( " Back " ) : FSUI_VSTR ( " Cancel " ) ) } ) ;
}
else
{
ImGuiFullscreen : : CreateFooterTextString (
dest , std : : array { std : : make_pair ( ICON_PF_ARROW_UP ICON_PF_ARROW_DOWN , FSUI_VSTR ( " Change Selection " ) ) ,
std : : make_pair ( ICON_PF_ENTER , FSUI_VSTR ( " Select " ) ) ,
std : : make_pair ( ICON_PF_ESC , back_instead_of_cancel ? FSUI_VSTR ( " Back " ) : FSUI_VSTR ( " Cancel " ) ) } ) ;
}
}
void FullscreenUI : : SetStandardSelectionFooterText ( bool back_instead_of_cancel )
{
SmallString text ;
GetStandardSelectionFooterText ( text , back_instead_of_cancel ) ;
ImGuiFullscreen : : SetFullscreenFooterText ( text ) ;
}
void ImGuiFullscreen : : GetChoiceDialogHelpText ( SmallStringBase & dest )
{
FullscreenUI : : GetStandardSelectionFooterText ( dest , false ) ;
}
void ImGuiFullscreen : : GetFileSelectorHelpText ( SmallStringBase & dest )
{
if ( IsGamepadInputSource ( ) )
{
ImGuiFullscreen : : CreateFooterTextString (
dest , std : : array { std : : make_pair ( ICON_PF_XBOX_DPAD_UP_DOWN , FSUI_VSTR ( " Change Selection " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_Y , FSUI_VSTR ( " Parent Directory " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_A , FSUI_VSTR ( " Select " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_B , FSUI_VSTR ( " Cancel " ) ) } ) ;
}
else
{
ImGuiFullscreen : : CreateFooterTextString (
dest ,
std : : array { std : : make_pair ( ICON_PF_ARROW_UP ICON_PF_ARROW_DOWN , FSUI_VSTR ( " Change Selection " ) ) ,
std : : make_pair ( ICON_PF_BACKSPACE , FSUI_VSTR ( " Parent Directory " ) ) ,
std : : make_pair ( ICON_PF_ENTER , FSUI_VSTR ( " Select " ) ) , std : : make_pair ( ICON_PF_ESC , FSUI_VSTR ( " Cancel " ) ) } ) ;
}
}
void ImGuiFullscreen : : GetInputDialogHelpText ( SmallStringBase & dest )
{
if ( IsGamepadInputSource ( ) )
{
CreateFooterTextString ( dest , std : : array { std : : make_pair ( ICON_PF_KEYBOARD , FSUI_VSTR ( " Enter Value " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_A , FSUI_VSTR ( " Select " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_B , FSUI_VSTR ( " Cancel " ) ) } ) ;
}
else
{
CreateFooterTextString ( dest , std : : array { std : : make_pair ( ICON_PF_KEYBOARD , FSUI_VSTR ( " Enter Value " ) ) ,
std : : make_pair ( ICON_PF_ENTER , FSUI_VSTR ( " Select " ) ) ,
std : : make_pair ( ICON_PF_ESC , FSUI_VSTR ( " Cancel " ) ) } ) ;
}
}
2021-01-30 11:37:49 +00:00
//////////////////////////////////////////////////////////////////////////
// Main
//////////////////////////////////////////////////////////////////////////
2022-07-11 13:03:29 +00:00
bool FullscreenUI : : Initialize ( )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
if ( s_initialized )
return true ;
if ( s_tried_to_initialize )
return false ;
2022-09-17 05:51:05 +00:00
ImGuiFullscreen : : SetTheme ( Host : : GetBaseBoolSettingValue ( " Main " , " UseLightFullscreenUITheme " , false ) ) ;
2022-07-11 13:03:29 +00:00
ImGuiFullscreen : : UpdateLayoutScale ( ) ;
2022-08-10 03:05:28 +00:00
if ( ! ImGuiManager : : AddFullscreenFontsIfMissing ( ) | | ! ImGuiFullscreen : : Initialize ( " images/placeholder.png " ) | |
2022-07-11 13:03:29 +00:00
! LoadResources ( ) )
2022-03-26 13:51:37 +00:00
{
2022-07-11 13:03:29 +00:00
DestroyResources ( ) ;
2022-03-26 13:51:37 +00:00
ImGuiFullscreen : : Shutdown ( ) ;
2022-07-11 13:03:29 +00:00
s_tried_to_initialize = true ;
2021-01-30 11:37:49 +00:00
return false ;
2022-03-26 13:51:37 +00:00
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
s_initialized = true ;
s_current_main_window = MainWindowType : : None ;
s_current_pause_submenu = PauseSubMenu : : None ;
s_pause_menu_was_open = false ;
s_was_paused_on_quick_menu_open = false ;
s_about_window_open = false ;
s_hotkey_list_cache = InputManager : : GetHotkeyList ( ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
if ( ! System : : IsValid ( ) )
SwitchToLanding ( ) ;
2021-01-30 11:37:49 +00:00
2023-12-14 06:07:57 +00:00
if ( ! System : : IsRunning ( ) )
Host : : OnIdleStateChanged ( ) ;
2024-04-09 10:04:45 +00:00
ForceKeyNavEnabled ( ) ;
2021-01-30 11:37:49 +00:00
return true ;
}
2022-07-11 13:03:29 +00:00
bool FullscreenUI : : IsInitialized ( )
2021-05-14 03:26:06 +00:00
{
2022-07-11 13:03:29 +00:00
return s_initialized ;
2021-05-14 03:26:06 +00:00
}
2022-07-11 13:03:29 +00:00
bool FullscreenUI : : HasActiveWindow ( )
2021-01-30 11:37:49 +00:00
{
2024-04-09 10:04:45 +00:00
return s_initialized & & ( s_current_main_window ! = MainWindowType : : None | | AreAnyDialogsOpen ( ) ) ;
}
bool FullscreenUI : : AreAnyDialogsOpen ( )
{
return ( s_save_state_selector_open | | s_about_window_open | |
s_input_binding_type ! = InputBindingInfo : : Type : : Unknown | | ImGuiFullscreen : : IsChoiceDialogOpen ( ) | |
ImGuiFullscreen : : IsFileSelectorOpen ( ) ) ;
2021-01-30 11:37:49 +00:00
}
2022-09-21 12:58:18 +00:00
void FullscreenUI : : CheckForConfigChanges ( const Settings & old_settings )
{
if ( ! IsInitialized ( ) )
return ;
// If achievements got disabled, we might have the menu open...
// That means we're going to be reading achievement state.
if ( old_settings . achievements_enabled & & ! g_settings . achievements_enabled )
2022-10-08 10:59:18 +00:00
{
if ( s_current_main_window = = MainWindowType : : Achievements | | s_current_main_window = = MainWindowType : : Leaderboards )
2023-09-18 12:29:47 +00:00
ReturnToPreviousWindow ( ) ;
2022-10-08 10:59:18 +00:00
}
2022-09-21 12:58:18 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : OnSystemStarted ( )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
if ( ! IsInitialized ( ) )
return ;
2021-01-30 11:37:49 +00:00
s_current_main_window = MainWindowType : : None ;
2022-07-11 13:03:29 +00:00
QueueResetFocus ( ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : OnSystemPaused ( )
2021-01-30 11:37:49 +00:00
{
2022-08-10 03:05:28 +00:00
// noop
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : OnSystemResumed ( )
2021-06-21 02:15:31 +00:00
{
2022-08-10 03:05:28 +00:00
// get rid of pause menu if we unpaused another way
if ( s_current_main_window = = MainWindowType : : PauseMenu )
ClosePauseMenu ( ) ;
2021-06-21 02:15:31 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : OnSystemDestroyed ( )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
if ( ! IsInitialized ( ) )
2021-01-30 11:37:49 +00:00
return ;
2022-07-11 13:03:29 +00:00
s_pause_menu_was_open = false ;
2023-09-18 12:29:47 +00:00
s_was_paused_on_quick_menu_open = false ;
s_current_pause_submenu = PauseSubMenu : : None ;
2022-07-11 13:03:29 +00:00
SwitchToLanding ( ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : OnRunningGameChanged ( )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
if ( ! IsInitialized ( ) )
2021-01-30 11:37:49 +00:00
return ;
2023-05-15 13:38:37 +00:00
const std : : string & path = System : : GetDiscPath ( ) ;
const std : : string & serial = System : : GetGameSerial ( ) ;
2022-07-11 13:03:29 +00:00
if ( ! serial . empty ( ) )
s_current_game_subtitle = fmt : : format ( " {0} - {1} " , serial , Path : : GetFileName ( path ) ) ;
else
s_current_game_subtitle = { } ;
2021-01-30 11:37:49 +00:00
}
2023-09-18 12:29:47 +00:00
void FullscreenUI : : PauseForMenuOpen ( bool set_pause_menu_open )
2022-07-11 13:03:29 +00:00
{
s_was_paused_on_quick_menu_open = ( System : : GetState ( ) = = System : : State : : Paused ) ;
2023-11-06 11:48:09 +00:00
if ( ! s_was_paused_on_quick_menu_open )
2022-12-04 04:05:57 +00:00
Host : : RunOnCPUThread ( [ ] ( ) { System : : PauseSystem ( true ) ; } ) ;
2022-07-11 13:03:29 +00:00
2023-09-18 12:29:47 +00:00
s_pause_menu_was_open | = set_pause_menu_open ;
2022-07-11 13:03:29 +00:00
}
2021-06-21 02:10:49 +00:00
2022-07-11 13:03:29 +00:00
void FullscreenUI : : OpenPauseMenu ( )
2021-06-20 03:33:30 +00:00
{
2022-07-11 13:03:29 +00:00
if ( ! System : : IsValid ( ) )
return ;
2021-06-20 03:33:30 +00:00
2022-07-11 13:03:29 +00:00
if ( ! Initialize ( ) | | s_current_main_window ! = MainWindowType : : None )
return ;
2021-06-21 02:15:31 +00:00
2023-09-18 12:29:47 +00:00
PauseForMenuOpen ( true ) ;
2022-07-11 13:03:29 +00:00
s_current_main_window = MainWindowType : : PauseMenu ;
s_current_pause_submenu = PauseSubMenu : : None ;
QueueResetFocus ( ) ;
2024-04-09 10:04:45 +00:00
ForceKeyNavEnabled ( ) ;
2023-12-14 06:07:57 +00:00
FixStateIfPaused ( ) ;
}
void FullscreenUI : : FixStateIfPaused ( )
{
if ( ! System : : IsValid ( ) | | System : : IsRunning ( ) )
return ;
// When we're paused, we won't have trickled the key up event for escape yet. Do it now.
ImGui : : UpdateInputEvents ( false ) ;
Host : : OnIdleStateChanged ( ) ;
Host : : RunOnCPUThread ( [ ] ( ) {
if ( System : : IsValid ( ) )
{
// Why twice? To clear the "wants keyboard input" flag.
System : : InvalidateDisplay ( ) ;
System : : InvalidateDisplay ( ) ;
}
} ) ;
2021-06-20 03:33:30 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : ClosePauseMenu ( )
2021-06-20 03:33:30 +00:00
{
2022-07-11 13:03:29 +00:00
if ( ! IsInitialized ( ) | | ! System : : IsValid ( ) )
return ;
2021-06-20 03:33:30 +00:00
2022-07-11 13:03:29 +00:00
if ( System : : GetState ( ) = = System : : State : : Paused & & ! s_was_paused_on_quick_menu_open )
Host : : RunOnCPUThread ( [ ] ( ) { System : : PauseSystem ( false ) ; } ) ;
2021-06-21 02:15:31 +00:00
2022-07-11 13:03:29 +00:00
s_current_main_window = MainWindowType : : None ;
s_current_pause_submenu = PauseSubMenu : : None ;
s_pause_menu_was_open = false ;
QueueResetFocus ( ) ;
2023-12-14 06:07:57 +00:00
FixStateIfPaused ( ) ;
2021-06-20 03:33:30 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : OpenPauseSubMenu ( PauseSubMenu submenu )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
s_current_main_window = MainWindowType : : PauseMenu ;
s_current_pause_submenu = submenu ;
QueueResetFocus ( ) ;
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
void FullscreenUI : : Shutdown ( )
{
2023-09-07 10:13:48 +00:00
Achievements : : ClearUIState ( ) ;
2021-01-30 11:37:49 +00:00
CloseSaveStateSelector ( ) ;
s_cover_image_map . clear ( ) ;
2022-07-11 13:03:29 +00:00
s_game_list_sorted_entries = { } ;
s_game_list_directories_cache = { } ;
2023-08-27 12:48:40 +00:00
s_postprocessing_stages = { } ;
2022-07-11 13:03:29 +00:00
s_fullscreen_mode_list_cache = { } ;
s_graphics_adapter_list_cache = { } ;
s_hotkey_list_cache = { } ;
s_current_game_subtitle = { } ;
2021-01-30 11:37:49 +00:00
DestroyResources ( ) ;
2022-03-26 13:51:37 +00:00
ImGuiFullscreen : : Shutdown ( ) ;
2022-07-11 13:03:29 +00:00
s_initialized = false ;
s_tried_to_initialize = false ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : Render ( )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
if ( ! s_initialized )
return ;
2021-03-03 09:14:01 +00:00
2022-07-11 13:03:29 +00:00
ImGuiFullscreen : : UploadAsyncTextures ( ) ;
2021-01-30 11:37:49 +00:00
ImGuiFullscreen : : BeginLayout ( ) ;
2022-09-21 12:02:54 +00:00
// Primed achievements must come first, because we don't want the pause screen to be behind them.
2023-09-07 10:13:48 +00:00
if ( s_current_main_window = = MainWindowType : : None )
Achievements : : DrawGameOverlays ( ) ;
2022-09-21 12:02:54 +00:00
2021-01-30 11:37:49 +00:00
switch ( s_current_main_window )
{
case MainWindowType : : Landing :
DrawLandingWindow ( ) ;
break ;
2024-04-09 10:04:45 +00:00
case MainWindowType : : StartGame :
DrawStartGameWindow ( ) ;
break ;
case MainWindowType : : Exit :
DrawExitWindow ( ) ;
break ;
2021-01-30 11:37:49 +00:00
case MainWindowType : : GameList :
DrawGameListWindow ( ) ;
break ;
2024-04-09 10:04:45 +00:00
case MainWindowType : : GameListSettings :
DrawGameListSettingsWindow ( ) ;
break ;
2021-01-30 11:37:49 +00:00
case MainWindowType : : Settings :
DrawSettingsWindow ( ) ;
break ;
2022-07-11 13:03:29 +00:00
case MainWindowType : : PauseMenu :
2023-09-18 12:29:47 +00:00
DrawPauseMenu ( ) ;
2021-01-30 11:37:49 +00:00
break ;
2021-02-26 14:44:53 +00:00
case MainWindowType : : Achievements :
2023-09-07 10:13:48 +00:00
Achievements : : DrawAchievementsWindow ( ) ;
2021-02-26 14:44:53 +00:00
break ;
2021-06-18 21:40:11 +00:00
case MainWindowType : : Leaderboards :
2023-09-07 10:13:48 +00:00
Achievements : : DrawLeaderboardsWindow ( ) ;
2021-06-18 21:40:11 +00:00
break ;
2021-01-30 11:37:49 +00:00
default :
break ;
}
if ( s_save_state_selector_open )
2022-09-17 05:51:05 +00:00
{
if ( s_save_state_selector_resuming )
DrawResumeStateSelector ( ) ;
else
2022-10-23 04:09:54 +00:00
DrawSaveStateSelector ( s_save_state_selector_loading ) ;
2022-09-17 05:51:05 +00:00
}
2021-01-30 11:37:49 +00:00
if ( s_about_window_open )
DrawAboutWindow ( ) ;
2023-01-15 04:00:51 +00:00
if ( s_input_binding_type ! = InputBindingInfo : : Type : : Unknown )
2021-01-30 11:37:49 +00:00
DrawInputBindingWindow ( ) ;
2021-02-23 14:20:52 +00:00
ImGuiFullscreen : : EndLayout ( ) ;
2021-01-30 11:37:49 +00:00
2022-08-25 15:26:55 +00:00
if ( s_settings_changed . load ( std : : memory_order_relaxed ) )
2022-07-11 13:03:29 +00:00
{
2022-08-25 15:26:55 +00:00
Host : : CommitBaseSettingChanges ( ) ;
Host : : RunOnCPUThread ( [ ] ( ) { System : : ApplySettings ( false ) ; } ) ;
s_settings_changed . store ( false , std : : memory_order_release ) ;
}
if ( s_game_settings_changed . load ( std : : memory_order_relaxed ) )
{
if ( s_game_settings_interface )
{
s_game_settings_interface - > Save ( ) ;
if ( System : : IsValid ( ) )
Host : : RunOnCPUThread ( [ ] ( ) { System : : ReloadGameSettings ( false ) ; } ) ;
}
s_game_settings_changed . store ( false , std : : memory_order_release ) ;
2022-07-11 13:03:29 +00:00
}
2022-07-23 09:38:46 +00:00
ImGuiFullscreen : : ResetCloseMenuIfNeeded ( ) ;
2021-01-30 11:37:49 +00:00
}
2022-09-09 10:32:21 +00:00
void FullscreenUI : : InvalidateCoverCache ( )
{
if ( ! IsInitialized ( ) )
return ;
Host : : RunOnCPUThread ( [ ] ( ) { s_cover_image_map . clear ( ) ; } ) ;
}
2023-09-18 12:29:47 +00:00
void FullscreenUI : : ReturnToPreviousWindow ( )
2021-01-30 11:37:49 +00:00
{
2023-09-18 12:29:47 +00:00
if ( System : : IsValid ( ) & & s_pause_menu_was_open )
{
s_current_main_window = MainWindowType : : PauseMenu ;
QueueResetFocus ( ) ;
}
else
{
ReturnToMainWindow ( ) ;
}
}
2021-02-24 08:56:43 +00:00
2023-09-18 12:29:47 +00:00
void FullscreenUI : : ReturnToMainWindow ( )
{
ClosePauseMenu ( ) ;
2021-02-24 08:56:43 +00:00
s_current_main_window = System : : IsValid ( ) ? MainWindowType : : None : MainWindowType : : Landing ;
2023-12-14 06:07:57 +00:00
FixStateIfPaused ( ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
bool FullscreenUI : : LoadResources ( )
2021-01-30 11:37:49 +00:00
{
2022-08-10 03:05:28 +00:00
s_app_icon_texture = LoadTexture ( " images/duck.png " ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
s_fallback_disc_texture = LoadTexture ( " fullscreenui/media-cdrom.png " ) ;
s_fallback_exe_texture = LoadTexture ( " fullscreenui/applications-system.png " ) ;
2022-09-17 05:51:05 +00:00
s_fallback_psf_texture = LoadTexture ( " fullscreenui/multimedia-player.png " ) ;
2022-07-11 13:03:29 +00:00
s_fallback_playlist_texture = LoadTexture ( " fullscreenui/address-book-new.png " ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
for ( u32 i = 0 ; i < static_cast < u32 > ( GameDatabase : : CompatibilityRating : : Count ) ; i + + )
2023-12-13 11:06:15 +00:00
s_game_compatibility_textures [ i ] = LoadTexture ( TinyString : : from_format ( " fullscreenui/star-{}.png " , i ) . c_str ( ) ) ;
2021-01-30 11:37:49 +00:00
return true ;
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DestroyResources ( )
2021-01-30 11:37:49 +00:00
{
s_app_icon_texture . reset ( ) ;
2021-01-31 14:50:59 +00:00
s_fallback_playlist_texture . reset ( ) ;
s_fallback_psf_texture . reset ( ) ;
s_fallback_exe_texture . reset ( ) ;
s_fallback_disc_texture . reset ( ) ;
2021-01-30 11:37:49 +00:00
for ( auto & tex : s_game_compatibility_textures )
tex . reset ( ) ;
}
2022-07-11 13:03:29 +00:00
//////////////////////////////////////////////////////////////////////////
// Utility
//////////////////////////////////////////////////////////////////////////
2021-02-21 06:55:28 +00:00
2022-07-11 13:03:29 +00:00
ImGuiFullscreen : : FileSelectorFilters FullscreenUI : : GetDiscImageFilters ( )
2022-03-26 13:51:37 +00:00
{
2022-09-02 04:15:04 +00:00
return { " *.bin " , " *.cue " , " *.iso " , " *.img " , " *.chd " , " *.ecm " , " *.mds " , " *.psexe " ,
" *.ps-exe " , " *.exe " , " *.psf " , " *.minipsf " , " *.m3u " , " *.pbp " , " *.PBP " } ;
2022-03-26 13:51:37 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DoStartPath ( std : : string path , std : : string state , std : : optional < bool > fast_boot )
2021-02-21 06:55:28 +00:00
{
2022-07-11 13:03:29 +00:00
if ( System : : IsValid ( ) )
return ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
SystemBootParameters params ;
params . filename = std : : move ( path ) ;
params . save_state = std : : move ( state ) ;
params . override_fast_boot = std : : move ( fast_boot ) ;
Host : : RunOnCPUThread ( [ params = std : : move ( params ) ] ( ) {
if ( System : : IsValid ( ) )
return ;
2021-01-30 11:37:49 +00:00
2024-04-11 03:42:10 +00:00
Error error ;
if ( ! System : : BootSystem ( std : : move ( params ) , & error ) )
{
Host : : ReportErrorAsync ( TRANSLATE_SV ( " System " , " Error " ) ,
fmt : : format ( TRANSLATE_FS ( " System " , " Failed to boot system: {} " ) , error . GetDescription ( ) ) ) ;
}
2022-07-11 13:03:29 +00:00
} ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DoResume ( )
2021-01-30 11:37:49 +00:00
{
2024-04-09 10:04:45 +00:00
std : : string path = System : : GetMostRecentResumeSaveStatePath ( ) ;
2022-07-11 13:03:29 +00:00
if ( path . empty ( ) )
2021-07-03 14:27:23 +00:00
{
2023-08-20 02:38:55 +00:00
ShowToast ( { } , FSUI_CSTR ( " No resume save state found. " ) ) ;
2022-07-11 13:03:29 +00:00
return ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
2024-04-09 10:04:45 +00:00
SaveStateListEntry slentry ;
if ( ! InitializeSaveStateListEntryFromPath ( & slentry , std : : move ( path ) , - 1 , false ) )
return ;
CloseSaveStateSelector ( ) ;
s_save_state_selector_slots . push_back ( std : : move ( slentry ) ) ;
s_save_state_selector_game_path = { } ;
s_save_state_selector_loading = true ;
s_save_state_selector_open = true ;
s_save_state_selector_resuming = true ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DoStartFile ( )
2021-01-30 11:37:49 +00:00
{
auto callback = [ ] ( const std : : string & path ) {
if ( ! path . empty ( ) )
2022-07-11 13:03:29 +00:00
DoStartPath ( path ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
QueueResetFocus ( ) ;
2021-01-30 11:37:49 +00:00
CloseFileSelector ( ) ;
} ;
2023-08-20 02:38:55 +00:00
OpenFileSelector ( FSUI_ICONSTR ( ICON_FA_COMPACT_DISC , " Select Disc Image " ) , false , std : : move ( callback ) ,
GetDiscImageFilters ( ) ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DoStartBIOS ( )
2021-01-30 11:37:49 +00:00
{
2024-04-11 03:42:10 +00:00
DoStartDisc ( std : : string ( ) ) ;
2021-01-30 11:37:49 +00:00
}
2024-04-09 10:04:45 +00:00
void FullscreenUI : : DoStartDisc ( std : : string path )
{
Host : : RunOnCPUThread ( [ path = std : : move ( path ) ] ( ) mutable {
if ( System : : IsValid ( ) )
return ;
2024-04-11 03:42:10 +00:00
Error error ;
2024-04-09 10:04:45 +00:00
SystemBootParameters params ;
params . filename = std : : move ( path ) ;
2024-04-11 03:42:10 +00:00
if ( ! System : : BootSystem ( std : : move ( params ) , & error ) )
{
Host : : ReportErrorAsync ( TRANSLATE_SV ( " System " , " Error " ) ,
fmt : : format ( TRANSLATE_FS ( " System " , " Failed to boot system: {} " ) , error . GetDescription ( ) ) ) ;
}
2024-04-09 10:04:45 +00:00
} ) ;
}
void FullscreenUI : : DoStartDisc ( )
{
std : : vector < std : : pair < std : : string , std : : string > > devices = CDImage : : GetDeviceList ( ) ;
if ( devices . empty ( ) )
{
ShowToast ( std : : string ( ) ,
FSUI_STR ( " Could not find any CD/DVD-ROM devices. Please ensure you have a drive connected and sufficient "
" permissions to access it. " ) ) ;
return ;
}
// if there's only one, select it automatically
if ( devices . size ( ) = = 1 )
{
DoStartDisc ( std : : move ( devices . front ( ) . first ) ) ;
return ;
}
ImGuiFullscreen : : ChoiceDialogOptions options ;
std : : vector < std : : string > paths ;
options . reserve ( devices . size ( ) ) ;
paths . reserve ( paths . size ( ) ) ;
for ( auto & [ path , name ] : devices )
{
options . emplace_back ( std : : move ( name ) , false ) ;
paths . push_back ( std : : move ( path ) ) ;
}
OpenChoiceDialog ( FSUI_ICONSTR ( ICON_FA_COMPACT_DISC , " Select Disc Drive " ) , false , std : : move ( options ) ,
[ paths = std : : move ( paths ) ] ( s32 index , const std : : string & , bool ) mutable {
if ( index < 0 )
return ;
DoStartDisc ( std : : move ( paths [ index ] ) ) ;
CloseChoiceDialog ( ) ;
QueueResetFocus ( ) ;
} ) ;
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DoShutdown ( bool save_state )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
Host : : RunOnCPUThread ( [ save_state ] ( ) { Host : : RequestSystemShutdown ( false , save_state ) ; } ) ;
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DoReset ( )
{
Host : : RunOnCPUThread ( System : : ResetSystem ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DoToggleFastForward ( )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
Host : : RunOnCPUThread ( [ ] ( ) {
2021-01-30 11:37:49 +00:00
if ( ! System : : IsValid ( ) )
return ;
2022-07-11 13:03:29 +00:00
System : : SetFastForwardEnabled ( ! System : : IsFastForwardEnabled ( ) ) ;
2021-01-30 11:37:49 +00:00
} ) ;
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DoChangeDiscFromFile ( )
{
auto callback = [ ] ( const std : : string & path ) {
if ( ! path . empty ( ) )
{
if ( ! GameList : : IsScannableFilename ( path ) )
{
2023-08-20 02:38:55 +00:00
ShowToast ( { } ,
fmt : : format ( FSUI_FSTR ( " {} is not a valid disc image. " ) , FileSystem : : GetDisplayNameFromPath ( path ) ) ) ;
2022-07-11 13:03:29 +00:00
}
else
{
Host : : RunOnCPUThread ( [ path ] ( ) { System : : InsertMedia ( path . c_str ( ) ) ; } ) ;
}
}
QueueResetFocus ( ) ;
CloseFileSelector ( ) ;
2023-09-18 12:29:47 +00:00
ReturnToPreviousWindow ( ) ;
2022-07-11 13:03:29 +00:00
} ;
2023-08-20 02:38:55 +00:00
OpenFileSelector ( FSUI_ICONSTR ( ICON_FA_COMPACT_DISC , " Select Disc Image " ) , false , std : : move ( callback ) ,
GetDiscImageFilters ( ) , std : : string ( Path : : GetDirectory ( System : : GetDiscPath ( ) ) ) ) ;
2022-07-11 13:03:29 +00:00
}
void FullscreenUI : : DoChangeDisc ( )
{
2023-08-23 08:12:10 +00:00
ImGuiFullscreen : : ChoiceDialogOptions options ;
if ( System : : HasMediaSubImages ( ) )
2022-07-11 13:03:29 +00:00
{
2023-08-23 08:12:10 +00:00
const u32 current_index = System : : GetMediaSubImageIndex ( ) ;
const u32 count = System : : GetMediaSubImageCount ( ) ;
options . reserve ( count + 1 ) ;
options . emplace_back ( FSUI_STR ( " From File... " ) , false ) ;
for ( u32 i = 0 ; i < count ; i + + )
options . emplace_back ( System : : GetMediaSubImageTitle ( i ) , i = = current_index ) ;
auto callback = [ ] ( s32 index , const std : : string & title , bool checked ) {
if ( index = = 0 )
{
CloseChoiceDialog ( ) ;
DoChangeDiscFromFile ( ) ;
return ;
}
else if ( index > 0 )
{
System : : SwitchMediaSubImage ( static_cast < u32 > ( index - 1 ) ) ;
}
QueueResetFocus ( ) ;
CloseChoiceDialog ( ) ;
2023-09-18 12:29:47 +00:00
ReturnToPreviousWindow ( ) ;
2023-08-23 08:12:10 +00:00
} ;
OpenChoiceDialog ( FSUI_ICONSTR ( ICON_FA_COMPACT_DISC , " Select Disc Image " ) , true , std : : move ( options ) ,
std : : move ( callback ) ) ;
2022-07-11 13:03:29 +00:00
return ;
}
2023-08-23 08:12:10 +00:00
if ( const GameDatabase : : Entry * entry = System : : GetGameDatabaseEntry ( ) ; entry & & ! entry - > disc_set_serials . empty ( ) )
{
const auto lock = GameList : : GetLock ( ) ;
const auto matches = GameList : : GetMatchingEntriesForSerial ( entry - > disc_set_serials ) ;
if ( matches . size ( ) > 1 )
{
options . reserve ( matches . size ( ) + 1 ) ;
options . emplace_back ( FSUI_STR ( " From File... " ) , false ) ;
2022-07-11 13:03:29 +00:00
2023-08-23 08:12:10 +00:00
std : : vector < std : : string > paths ;
paths . reserve ( matches . size ( ) ) ;
const std : : string & current_path = System : : GetDiscPath ( ) ;
for ( auto & [ title , glentry ] : matches )
{
options . emplace_back ( std : : move ( title ) , current_path = = glentry - > path ) ;
paths . push_back ( glentry - > path ) ;
}
auto callback = [ paths = std : : move ( paths ) ] ( s32 index , const std : : string & title , bool checked ) {
if ( index = = 0 )
{
CloseChoiceDialog ( ) ;
DoChangeDiscFromFile ( ) ;
return ;
}
else if ( index > 0 )
{
System : : InsertMedia ( paths [ index - 1 ] . c_str ( ) ) ;
}
QueueResetFocus ( ) ;
CloseChoiceDialog ( ) ;
ReturnToMainWindow ( ) ;
} ;
OpenChoiceDialog ( FSUI_ICONSTR ( ICON_FA_COMPACT_DISC , " Select Disc Image " ) , true , std : : move ( options ) ,
std : : move ( callback ) ) ;
2022-07-11 13:03:29 +00:00
2021-01-30 11:37:49 +00:00
return ;
2022-07-11 13:03:29 +00:00
}
2023-08-23 08:12:10 +00:00
}
2022-07-11 13:03:29 +00:00
2023-08-23 08:12:10 +00:00
DoChangeDiscFromFile ( ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-30 02:58:03 +00:00
void FullscreenUI : : DoCheatsMenu ( )
2021-01-30 11:37:49 +00:00
{
CheatList * cl = System : : GetCheatList ( ) ;
if ( ! cl )
{
2022-07-30 02:58:03 +00:00
if ( ! System : : LoadCheatListFromDatabase ( ) | | ( ( cl = System : : GetCheatList ( ) ) = = nullptr ) )
2021-01-30 11:37:49 +00:00
{
2023-08-20 02:38:55 +00:00
Host : : AddKeyedOSDMessage ( " load_cheat_list " ,
fmt : : format ( FSUI_FSTR ( " No cheats found for {}. " ) , System : : GetGameTitle ( ) ) , 10.0f ) ;
2023-09-18 12:29:47 +00:00
ReturnToPreviousWindow ( ) ;
2021-01-30 11:37:49 +00:00
return ;
}
}
ImGuiFullscreen : : ChoiceDialogOptions options ;
options . reserve ( cl - > GetCodeCount ( ) ) ;
for ( u32 i = 0 ; i < cl - > GetCodeCount ( ) ; i + + )
{
const CheatCode & cc = cl - > GetCode ( i ) ;
options . emplace_back ( cc . description . c_str ( ) , cc . enabled ) ;
}
auto callback = [ ] ( s32 index , const std : : string & title , bool checked ) {
if ( index < 0 )
2021-02-24 08:56:43 +00:00
{
2023-09-18 12:29:47 +00:00
ReturnToPreviousWindow ( ) ;
2021-01-30 11:37:49 +00:00
return ;
2021-02-24 08:56:43 +00:00
}
2021-01-30 11:37:49 +00:00
CheatList * cl = System : : GetCheatList ( ) ;
if ( ! cl )
return ;
const CheatCode & cc = cl - > GetCode ( static_cast < u32 > ( index ) ) ;
if ( cc . activation = = CheatCode : : Activation : : Manual )
cl - > ApplyCode ( static_cast < u32 > ( index ) ) ;
else
2024-03-03 03:43:04 +00:00
System : : SetCheatCodeState ( static_cast < u32 > ( index ) , checked ) ;
2021-01-30 11:37:49 +00:00
} ;
2023-08-20 02:38:55 +00:00
OpenChoiceDialog ( FSUI_ICONSTR ( ICON_FA_FROWN , " Cheat List " ) , true , std : : move ( options ) , std : : move ( callback ) ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-30 02:58:03 +00:00
void FullscreenUI : : DoToggleAnalogMode ( )
2021-01-30 11:37:49 +00:00
{
// hacky way to toggle analog mode
for ( u32 i = 0 ; i < NUM_CONTROLLER_AND_CARD_PORTS ; i + + )
{
Controller * ctrl = System : : GetController ( i ) ;
if ( ! ctrl )
continue ;
2022-07-11 13:03:29 +00:00
const Controller : : ControllerInfo * cinfo = Controller : : GetControllerInfo ( ctrl - > GetType ( ) ) ;
if ( ! cinfo )
2021-01-30 11:37:49 +00:00
continue ;
2023-09-20 07:10:41 +00:00
for ( const Controller : : ControllerBindingInfo & bi : cinfo - > bindings )
2022-07-11 13:03:29 +00:00
{
if ( std : : strcmp ( bi . name , " Analog " ) = = 0 )
{
ctrl - > SetBindState ( bi . bind_index , 1.0f ) ;
ctrl - > SetBindState ( bi . bind_index , 0.0f ) ;
break ;
}
}
2021-01-30 11:37:49 +00:00
}
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DoRequestExit ( )
2021-01-30 11:37:49 +00:00
{
2024-04-09 10:04:45 +00:00
Host : : RunOnCPUThread ( [ ] ( ) { Host : : RequestExitApplication ( true ) ; } ) ;
}
void FullscreenUI : : DoDesktopMode ( )
{
Host : : RunOnCPUThread ( [ ] ( ) { Host : : RequestExitBigPicture ( ) ; } ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DoToggleFullscreen ( )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
Host : : RunOnCPUThread ( [ ] ( ) { Host : : SetFullscreen ( ! Host : : IsFullscreen ( ) ) ; } ) ;
2021-01-30 11:37:49 +00:00
}
//////////////////////////////////////////////////////////////////////////
// Landing Window
//////////////////////////////////////////////////////////////////////////
2022-07-11 13:03:29 +00:00
void FullscreenUI : : SwitchToLanding ( )
{
s_current_main_window = MainWindowType : : Landing ;
QueueResetFocus ( ) ;
}
2024-04-09 10:04:45 +00:00
void FullscreenUI : : DrawLandingTemplate ( ImVec2 * menu_pos , ImVec2 * menu_size )
2021-01-30 11:37:49 +00:00
{
2024-04-09 10:04:45 +00:00
const ImGuiIO & io = ImGui : : GetIO ( ) ;
const ImVec2 heading_size = ImVec2 (
io . DisplaySize . x , LayoutScale ( LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY + LAYOUT_MENU_BUTTON_Y_PADDING * 2.0f + 2.0f ) ) ;
* menu_pos = ImVec2 ( 0.0f , heading_size . y ) ;
* menu_size = ImVec2 ( io . DisplaySize . x , io . DisplaySize . y - heading_size . y - LayoutScale ( LAYOUT_FOOTER_HEIGHT ) ) ;
2021-01-30 11:37:49 +00:00
2024-04-09 10:04:45 +00:00
if ( BeginFullscreenWindow ( ImVec2 ( 0.0f , 0.0f ) , heading_size , " landing_heading " , UIPrimaryColor ) )
2021-01-30 11:37:49 +00:00
{
2024-04-09 10:04:45 +00:00
ImFont * const heading_font = g_large_font ;
ImDrawList * const dl = ImGui : : GetWindowDrawList ( ) ;
SmallString heading_str ;
ImGui : : PushFont ( heading_font ) ;
ImGui : : PushStyleColor ( ImGuiCol_Text , UIPrimaryTextColor ) ;
// draw branding
{
const ImVec2 logo_pos = LayoutScale ( LAYOUT_MENU_BUTTON_X_PADDING , LAYOUT_MENU_BUTTON_Y_PADDING ) ;
const ImVec2 logo_size = LayoutScale ( LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY , LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ) ;
2024-04-09 14:04:51 +00:00
dl - > AddImage ( s_app_icon_texture . get ( ) , logo_pos , logo_pos + logo_size ) ;
2024-04-09 10:04:45 +00:00
dl - > AddText ( heading_font , heading_font - > FontSize ,
ImVec2 ( logo_pos . x + logo_size . x + LayoutScale ( LAYOUT_MENU_BUTTON_X_PADDING ) , logo_pos . y ) ,
ImGui : : GetColorU32 ( ImGuiCol_Text ) , " DuckStation " ) ;
}
// draw time
ImVec2 time_pos ;
{
heading_str . format ( FSUI_FSTR ( " {:%H:%M} " ) , fmt : : localtime ( std : : time ( nullptr ) ) ) ;
const ImVec2 time_size = heading_font - > CalcTextSizeA ( heading_font - > FontSize , FLT_MAX , 0.0f , " 00:00 " ) ;
time_pos = ImVec2 ( heading_size . x - LayoutScale ( LAYOUT_MENU_BUTTON_X_PADDING ) - time_size . x ,
LayoutScale ( LAYOUT_MENU_BUTTON_Y_PADDING ) ) ;
ImGui : : RenderTextClipped ( time_pos , time_pos + time_size , heading_str . c_str ( ) , heading_str . end_ptr ( ) , & time_size ) ;
}
// draw achievements info
if ( Achievements : : IsActive ( ) )
{
const auto lock = Achievements : : GetLock ( ) ;
const char * username = Achievements : : GetLoggedInUserName ( ) ;
if ( username )
{
const ImVec2 name_size = heading_font - > CalcTextSizeA ( heading_font - > FontSize , FLT_MAX , 0.0f , username ) ;
const ImVec2 name_pos =
ImVec2 ( time_pos . x - name_size . x - LayoutScale ( LAYOUT_MENU_BUTTON_X_PADDING ) , time_pos . y ) ;
ImGui : : RenderTextClipped ( name_pos , name_pos + name_size , username , nullptr , & name_size ) ;
// TODO: should we cache this? heap allocations bad...
std : : string badge_path = Achievements : : GetLoggedInUserBadgePath ( ) ;
if ( ! badge_path . empty ( ) ) [[likely]]
{
const ImVec2 badge_size =
LayoutScale ( LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY , LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ) ;
const ImVec2 badge_pos =
ImVec2 ( name_pos . x - badge_size . x - LayoutScale ( LAYOUT_MENU_BUTTON_X_PADDING ) , time_pos . y ) ;
dl - > AddImage ( reinterpret_cast < ImTextureID > ( GetCachedTextureAsync ( badge_path ) ) , badge_pos ,
badge_pos + badge_size ) ;
}
}
}
ImGui : : PopStyleColor ( ) ;
ImGui : : PopFont ( ) ;
2021-01-30 11:37:49 +00:00
}
2024-04-09 10:04:45 +00:00
EndFullscreenWindow ( ) ;
}
void FullscreenUI : : DrawLandingWindow ( )
{
ImVec2 menu_pos , menu_size ;
DrawLandingTemplate ( & menu_pos , & menu_size ) ;
2021-01-30 11:37:49 +00:00
2024-04-09 10:04:45 +00:00
ImGui : : PushStyleColor ( ImGuiCol_Text , UIBackgroundTextColor ) ;
if ( BeginHorizontalMenu ( " landing_window " , menu_pos , menu_size , 4 ) )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
ResetFocusHere ( ) ;
2024-04-09 10:04:45 +00:00
if ( HorizontalMenuItem ( GetCachedTexture ( " fullscreenui/address-book-new.png " ) , FSUI_CSTR ( " Game List " ) ,
FSUI_CSTR ( " Launch a game from images scanned from your game directories. " ) ) )
2022-09-17 05:51:05 +00:00
{
SwitchToGameList ( ) ;
}
2024-04-09 10:04:45 +00:00
if ( HorizontalMenuItem (
GetCachedTexture ( " fullscreenui/media-cdrom.png " ) , FSUI_CSTR ( " Start Game " ) ,
FSUI_CSTR ( " Launch a game from a file, disc, or starts the console without any disc inserted. " ) ) )
2021-01-30 11:37:49 +00:00
{
2024-04-09 10:04:45 +00:00
s_current_main_window = MainWindowType : : StartGame ;
QueueResetFocus ( ) ;
2021-01-30 11:37:49 +00:00
}
2024-04-09 10:04:45 +00:00
if ( HorizontalMenuItem ( GetCachedTexture ( " fullscreenui/applications-system.png " ) , FSUI_CSTR ( " Settings " ) ,
FSUI_CSTR ( " Changes settings for the application. " ) ) )
2021-01-30 11:37:49 +00:00
{
2024-04-09 10:04:45 +00:00
SwitchToSettings ( ) ;
2021-01-30 11:37:49 +00:00
}
2024-04-09 10:04:45 +00:00
if ( HorizontalMenuItem ( GetCachedTexture ( " fullscreenui/exit.png " ) , FSUI_CSTR ( " Exit " ) ,
FSUI_CSTR ( " Return to desktop mode, or exit the application. " ) ) | |
( ! AreAnyDialogsOpen ( ) & & WantsToCloseMenu ( ) ) )
2022-07-11 13:03:29 +00:00
{
2024-04-09 10:04:45 +00:00
s_current_main_window = MainWindowType : : Exit ;
QueueResetFocus ( ) ;
2022-07-11 13:03:29 +00:00
}
2024-04-09 10:04:45 +00:00
}
EndHorizontalMenu ( ) ;
2021-01-30 11:37:49 +00:00
2024-04-09 10:04:45 +00:00
ImGui : : PopStyleColor ( ) ;
if ( ! AreAnyDialogsOpen ( ) )
{
if ( ImGui : : IsKeyPressed ( ImGuiKey_GamepadStart , false ) | | ImGui : : IsKeyPressed ( ImGuiKey_F1 , false ) )
OpenAboutWindow ( ) ;
else if ( ImGui : : IsKeyPressed ( ImGuiKey_NavGamepadMenu , false ) | | ImGui : : IsKeyPressed ( ImGuiKey_F3 , false ) )
DoResume ( ) ;
else if ( ImGui : : IsKeyPressed ( ImGuiKey_NavGamepadInput , false ) | | ImGui : : IsKeyPressed ( ImGuiKey_F11 , false ) )
DoToggleFullscreen ( ) ;
}
if ( IsGamepadInputSource ( ) )
{
SetFullscreenFooterText ( std : : array { std : : make_pair ( ICON_PF_BURGER_MENU , FSUI_VSTR ( " About " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_Y , FSUI_VSTR ( " Resume Last Session " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_X , FSUI_VSTR ( " Toggle Fullscreen " ) ) ,
std : : make_pair ( ICON_PF_XBOX_DPAD_LEFT_RIGHT , FSUI_VSTR ( " Navigate " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_A , FSUI_VSTR ( " Select " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_B , FSUI_VSTR ( " Exit " ) ) } ) ;
}
else
{
SetFullscreenFooterText ( std : : array {
std : : make_pair ( ICON_PF_F1 , FSUI_VSTR ( " About " ) ) , std : : make_pair ( ICON_PF_F3 , FSUI_VSTR ( " Resume Last Session " ) ) ,
std : : make_pair ( ICON_PF_F11 , FSUI_VSTR ( " Toggle Fullscreen " ) ) ,
std : : make_pair ( ICON_PF_ARROW_LEFT ICON_PF_ARROW_RIGHT , FSUI_VSTR ( " Navigate " ) ) ,
std : : make_pair ( ICON_PF_ENTER , FSUI_VSTR ( " Select " ) ) , std : : make_pair ( ICON_PF_ESC , FSUI_VSTR ( " Exit " ) ) } ) ;
}
}
void FullscreenUI : : DrawStartGameWindow ( )
{
ImVec2 menu_pos , menu_size ;
DrawLandingTemplate ( & menu_pos , & menu_size ) ;
ImGui : : PushStyleColor ( ImGuiCol_Text , UIBackgroundTextColor ) ;
if ( BeginHorizontalMenu ( " start_game_window " , menu_pos , menu_size , 4 ) )
{
ResetFocusHere ( ) ;
if ( HorizontalMenuItem ( GetCachedTexture ( " fullscreenui/start-file.png " ) , FSUI_CSTR ( " Start File " ) ,
FSUI_CSTR ( " Launch a game by selecting a file/disc image. " ) ) )
2021-01-30 11:37:49 +00:00
{
2024-04-09 10:04:45 +00:00
DoStartFile ( ) ;
2021-01-30 11:37:49 +00:00
}
2024-04-09 10:04:45 +00:00
if ( HorizontalMenuItem ( GetCachedTexture ( " fullscreenui/drive-cdrom.png " ) , FSUI_CSTR ( " Start Disc " ) ,
FSUI_CSTR ( " Start a game from a disc in your PC's DVD drive. " ) ) )
{
DoStartDisc ( ) ;
}
2021-01-30 11:37:49 +00:00
2024-04-09 10:04:45 +00:00
if ( HorizontalMenuItem ( GetCachedTexture ( " fullscreenui/start-bios.png " ) , FSUI_CSTR ( " Start BIOS " ) ,
FSUI_CSTR ( " Start the console without any disc inserted. " ) ) )
2022-07-11 13:03:29 +00:00
{
2024-04-09 10:04:45 +00:00
DoStartBIOS ( ) ;
2022-07-11 13:03:29 +00:00
}
2021-01-30 11:37:49 +00:00
2024-04-09 10:04:45 +00:00
// https://www.iconpacks.net/free-icon/arrow-back-3783.html
if ( HorizontalMenuItem ( GetCachedTexture ( " fullscreenui/back-icon.png " ) , FSUI_CSTR ( " Back " ) ,
FSUI_CSTR ( " Return to the previous menu. " ) ) | |
( ! AreAnyDialogsOpen ( ) & & WantsToCloseMenu ( ) ) )
2021-01-30 11:37:49 +00:00
{
2024-04-09 10:04:45 +00:00
s_current_main_window = MainWindowType : : Landing ;
QueueResetFocus ( ) ;
}
}
EndHorizontalMenu ( ) ;
2021-01-30 11:37:49 +00:00
2024-04-09 10:04:45 +00:00
ImGui : : PopStyleColor ( ) ;
2021-01-30 11:37:49 +00:00
2024-04-09 10:04:45 +00:00
if ( ! AreAnyDialogsOpen ( ) )
{
if ( ImGui : : IsKeyPressed ( ImGuiKey_NavGamepadMenu , false ) | | ImGui : : IsKeyPressed ( ImGuiKey_F1 , false ) )
OpenSaveStateSelector ( true ) ;
}
2022-09-17 05:51:05 +00:00
2024-04-09 10:04:45 +00:00
if ( IsGamepadInputSource ( ) )
{
SetFullscreenFooterText ( std : : array { std : : make_pair ( ICON_PF_XBOX_DPAD_LEFT_RIGHT , FSUI_VSTR ( " Navigate " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_Y , FSUI_VSTR ( " Load Global State " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_A , FSUI_VSTR ( " Select " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_B , FSUI_VSTR ( " Back " ) ) } ) ;
}
else
{
SetFullscreenFooterText ( std : : array { std : : make_pair ( ICON_PF_ARROW_LEFT ICON_PF_ARROW_RIGHT , FSUI_VSTR ( " Navigate " ) ) ,
std : : make_pair ( ICON_PF_F1 , FSUI_VSTR ( " Load Global State " ) ) ,
std : : make_pair ( ICON_PF_ENTER , FSUI_VSTR ( " Select " ) ) ,
std : : make_pair ( ICON_PF_ESC , FSUI_VSTR ( " Back " ) ) } ) ;
}
}
void FullscreenUI : : DrawExitWindow ( )
{
ImVec2 menu_pos , menu_size ;
DrawLandingTemplate ( & menu_pos , & menu_size ) ;
ImGui : : PushStyleColor ( ImGuiCol_Text , UIBackgroundTextColor ) ;
if ( BeginHorizontalMenu ( " exit_window " , menu_pos , menu_size , 3 ) )
{
ResetFocusHere ( ) ;
// https://www.iconpacks.net/free-icon/arrow-back-3783.html
if ( HorizontalMenuItem ( GetCachedTexture ( " fullscreenui/back-icon.png " ) , FSUI_CSTR ( " Back " ) ,
FSUI_CSTR ( " Return to the previous menu. " ) ) | |
WantsToCloseMenu ( ) )
{
s_current_main_window = MainWindowType : : Landing ;
QueueResetFocus ( ) ;
2021-01-30 11:37:49 +00:00
}
2024-04-09 10:04:45 +00:00
if ( HorizontalMenuItem ( GetCachedTexture ( " fullscreenui/exit.png " ) , FSUI_CSTR ( " Exit DuckStation " ) ,
FSUI_CSTR ( " Completely exits the application, returning you to your desktop. " ) ) )
{
DoRequestExit ( ) ;
}
2022-07-23 03:59:59 +00:00
2024-04-09 10:04:45 +00:00
if ( HorizontalMenuItem ( GetCachedTexture ( " fullscreenui/desktop-mode.png " ) , FSUI_CSTR ( " Desktop Mode " ) ,
FSUI_CSTR ( " Exits Big Picture mode, returning to the desktop interface. " ) ) )
{
DoDesktopMode ( ) ;
}
2021-01-30 11:37:49 +00:00
}
2024-04-09 10:04:45 +00:00
EndHorizontalMenu ( ) ;
2021-01-30 11:37:49 +00:00
2024-04-09 10:04:45 +00:00
ImGui : : PopStyleColor ( ) ;
2021-01-30 11:37:49 +00:00
2024-04-09 10:04:45 +00:00
SetStandardSelectionFooterText ( true ) ;
2021-01-30 11:37:49 +00:00
}
2022-08-25 15:26:55 +00:00
bool FullscreenUI : : IsEditingGameSettings ( SettingsInterface * bsi )
2021-01-30 11:37:49 +00:00
{
2022-08-25 15:26:55 +00:00
return ( bsi = = s_game_settings_interface . get ( ) ) ;
2022-07-11 13:03:29 +00:00
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
SettingsInterface * FullscreenUI : : GetEditingSettingsInterface ( )
{
return s_game_settings_interface ? s_game_settings_interface . get ( ) : Host : : Internal : : GetBaseSettingsLayer ( ) ;
}
2021-01-30 11:37:49 +00:00
2022-08-25 15:26:55 +00:00
SettingsInterface * FullscreenUI : : GetEditingSettingsInterface ( bool game_settings )
{
return ( game_settings & & s_game_settings_interface ) ? s_game_settings_interface . get ( ) :
Host : : Internal : : GetBaseSettingsLayer ( ) ;
}
void FullscreenUI : : SetSettingsChanged ( SettingsInterface * bsi )
{
if ( bsi & & bsi = = s_game_settings_interface . get ( ) )
s_game_settings_changed . store ( true , std : : memory_order_release ) ;
else
s_settings_changed . store ( true , std : : memory_order_release ) ;
}
bool FullscreenUI : : GetEffectiveBoolSetting ( SettingsInterface * bsi , const char * section , const char * key ,
bool default_value )
{
if ( IsEditingGameSettings ( bsi ) )
{
std : : optional < bool > value = bsi - > GetOptionalBoolValue ( section , key , std : : nullopt ) ;
if ( value . has_value ( ) )
return value . value ( ) ;
}
return Host : : Internal : : GetBaseSettingsLayer ( ) - > GetBoolValue ( section , key , default_value ) ;
}
s32 FullscreenUI : : GetEffectiveIntSetting ( SettingsInterface * bsi , const char * section , const char * key ,
s32 default_value )
{
if ( IsEditingGameSettings ( bsi ) )
{
std : : optional < s32 > value = bsi - > GetOptionalIntValue ( section , key , std : : nullopt ) ;
if ( value . has_value ( ) )
return value . value ( ) ;
}
return Host : : Internal : : GetBaseSettingsLayer ( ) - > GetIntValue ( section , key , default_value ) ;
}
u32 FullscreenUI : : GetEffectiveUIntSetting ( SettingsInterface * bsi , const char * section , const char * key ,
u32 default_value )
{
if ( IsEditingGameSettings ( bsi ) )
{
std : : optional < u32 > value = bsi - > GetOptionalUIntValue ( section , key , std : : nullopt ) ;
if ( value . has_value ( ) )
return value . value ( ) ;
}
return Host : : Internal : : GetBaseSettingsLayer ( ) - > GetUIntValue ( section , key , default_value ) ;
}
float FullscreenUI : : GetEffectiveFloatSetting ( SettingsInterface * bsi , const char * section , const char * key ,
float default_value )
{
if ( IsEditingGameSettings ( bsi ) )
{
std : : optional < float > value = bsi - > GetOptionalFloatValue ( section , key , std : : nullopt ) ;
if ( value . has_value ( ) )
return value . value ( ) ;
}
return Host : : Internal : : GetBaseSettingsLayer ( ) - > GetFloatValue ( section , key , default_value ) ;
}
2024-04-07 10:43:13 +00:00
TinyString FullscreenUI : : GetEffectiveTinyStringSetting ( SettingsInterface * bsi , const char * section , const char * key ,
const char * default_value )
2022-07-11 13:03:29 +00:00
{
2024-04-07 10:43:13 +00:00
TinyString ret ;
std : : optional < TinyString > value ;
2022-08-25 15:26:55 +00:00
if ( IsEditingGameSettings ( bsi ) )
2024-04-07 10:43:13 +00:00
value = bsi - > GetOptionalTinyStringValue ( section , key , std : : nullopt ) ;
2022-08-25 15:26:55 +00:00
if ( value . has_value ( ) )
ret = std : : move ( value . value ( ) ) ;
else
2024-04-07 10:43:13 +00:00
ret = Host : : Internal : : GetBaseSettingsLayer ( ) - > GetTinyStringValue ( section , key , default_value ) ;
2022-08-25 15:26:55 +00:00
return ret ;
2021-01-30 11:37:49 +00:00
}
2023-01-15 04:00:51 +00:00
void FullscreenUI : : DrawInputBindingButton ( SettingsInterface * bsi , InputBindingInfo : : Type type , const char * section ,
2023-11-26 10:30:10 +00:00
const char * name , const char * display_name , const char * icon_name ,
bool show_type )
2021-01-30 11:37:49 +00:00
{
2023-10-12 09:29:09 +00:00
if ( type = = InputBindingInfo : : Type : : Pointer )
return ;
2022-08-25 15:26:55 +00:00
TinyString title ;
2023-12-13 11:06:15 +00:00
title . format ( " {}/{} " , section , name ) ;
2021-01-30 11:37:49 +00:00
2024-04-07 10:43:13 +00:00
SmallString value = bsi - > GetSmallStringValue ( section , name ) ;
const bool oneline = value . count ( ' & ' ) < = 1 ;
2023-11-26 10:47:38 +00:00
2021-01-30 11:37:49 +00:00
ImRect bb ;
bool visible , hovered , clicked ;
2023-11-26 10:47:38 +00:00
clicked = MenuButtonFrame ( title , true ,
oneline ? ImGuiFullscreen : : LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY :
ImGuiFullscreen : : LAYOUT_MENU_BUTTON_HEIGHT ,
& visible , & hovered , & bb . Min , & bb . Max ) ;
2021-01-30 11:37:49 +00:00
if ( ! visible )
return ;
2023-11-26 11:34:00 +00:00
if ( oneline )
InputManager : : PrettifyInputBinding ( value ) ;
2021-05-15 17:25:28 +00:00
if ( show_type )
2021-01-30 11:37:49 +00:00
{
2023-11-26 10:30:10 +00:00
if ( icon_name )
2021-05-15 17:25:28 +00:00
{
2023-12-13 11:06:15 +00:00
title . format ( " {} {} " , icon_name , display_name ) ;
2023-11-26 10:30:10 +00:00
}
else
{
switch ( type )
{
case InputBindingInfo : : Type : : Button :
2023-12-13 11:06:15 +00:00
title . format ( ICON_FA_DOT_CIRCLE " {} " , display_name ) ;
2023-11-26 10:30:10 +00:00
break ;
case InputBindingInfo : : Type : : Axis :
case InputBindingInfo : : Type : : HalfAxis :
2023-12-13 11:06:15 +00:00
title . format ( ICON_FA_BULLSEYE " {} " , display_name ) ;
2023-11-26 10:30:10 +00:00
break ;
case InputBindingInfo : : Type : : Motor :
2023-12-13 11:06:15 +00:00
title . format ( ICON_FA_BELL " {} " , display_name ) ;
2023-11-26 10:30:10 +00:00
break ;
case InputBindingInfo : : Type : : Macro :
2023-12-13 11:06:15 +00:00
title . format ( ICON_FA_PIZZA_SLICE " {} " , display_name ) ;
2023-11-26 10:30:10 +00:00
break ;
default :
title = display_name ;
break ;
}
2021-05-15 17:25:28 +00:00
}
2021-01-30 11:37:49 +00:00
}
2021-05-15 17:25:28 +00:00
2023-11-26 10:47:38 +00:00
const float midpoint = bb . Min . y + g_large_font - > FontSize + LayoutScale ( 4.0f ) ;
2021-01-30 11:37:49 +00:00
2023-11-26 10:47:38 +00:00
if ( oneline )
{
ImGui : : PushFont ( g_large_font ) ;
const ImVec2 value_size ( ImGui : : CalcTextSize ( value . empty ( ) ? FSUI_CSTR ( " - " ) : value . c_str ( ) , nullptr ) ) ;
const float text_end = bb . Max . x - value_size . x ;
const ImRect title_bb ( bb . Min , ImVec2 ( text_end , midpoint ) ) ;
ImGui : : RenderTextClipped ( title_bb . Min , title_bb . Max , show_type ? title . c_str ( ) : display_name , nullptr , nullptr ,
ImVec2 ( 0.0f , 0.0f ) , & title_bb ) ;
2023-11-26 11:34:00 +00:00
ImGui : : RenderTextClipped ( bb . Min , bb . Max , value . empty ( ) ? FSUI_CSTR ( " - " ) : value . c_str ( ) , nullptr , & value_size ,
ImVec2 ( 1.0f , 0.5f ) , & bb ) ;
2023-11-26 10:47:38 +00:00
ImGui : : PopFont ( ) ;
}
else
{
const ImRect title_bb ( bb . Min , ImVec2 ( bb . Max . x , midpoint ) ) ;
const ImRect summary_bb ( ImVec2 ( bb . Min . x , midpoint ) , bb . Max ) ;
ImGui : : PushFont ( g_large_font ) ;
ImGui : : RenderTextClipped ( title_bb . Min , title_bb . Max , show_type ? title . c_str ( ) : display_name , nullptr , nullptr ,
ImVec2 ( 0.0f , 0.0f ) , & title_bb ) ;
ImGui : : PopFont ( ) ;
ImGui : : PushFont ( g_medium_font ) ;
ImGui : : RenderTextClipped ( summary_bb . Min , summary_bb . Max , value . empty ( ) ? FSUI_CSTR ( " No Binding " ) : value . c_str ( ) ,
nullptr , nullptr , ImVec2 ( 0.0f , 0.0f ) , & summary_bb ) ;
ImGui : : PopFont ( ) ;
}
2021-01-30 11:37:49 +00:00
if ( clicked )
2022-07-11 13:03:29 +00:00
{
2022-08-25 15:26:55 +00:00
BeginInputBinding ( bsi , type , section , name , display_name ) ;
2022-07-11 13:03:29 +00:00
}
2024-04-07 10:43:13 +00:00
else if ( ImGui : : IsItemClicked ( ImGuiMouseButton_Right ) | | ImGui : : IsKeyPressed ( ImGuiKey_NavGamepadMenu , false ) )
2022-07-11 13:03:29 +00:00
{
2022-08-25 15:26:55 +00:00
bsi - > DeleteValue ( section , name ) ;
SetSettingsChanged ( bsi ) ;
2022-07-11 13:03:29 +00:00
}
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : ClearInputBindingVariables ( )
2021-03-07 15:39:13 +00:00
{
2023-01-15 04:00:51 +00:00
s_input_binding_type = InputBindingInfo : : Type : : Unknown ;
2022-07-11 13:03:29 +00:00
s_input_binding_section = { } ;
s_input_binding_key = { } ;
s_input_binding_display_name = { } ;
s_input_binding_new_bindings = { } ;
2023-01-15 04:00:51 +00:00
s_input_binding_value_ranges = { } ;
2021-03-07 15:39:13 +00:00
}
2023-01-15 04:00:51 +00:00
void FullscreenUI : : BeginInputBinding ( SettingsInterface * bsi , InputBindingInfo : : Type type ,
2022-08-25 15:26:55 +00:00
const std : : string_view & section , const std : : string_view & key ,
const std : : string_view & display_name )
2021-02-24 16:05:33 +00:00
{
2023-01-15 04:00:51 +00:00
if ( s_input_binding_type ! = InputBindingInfo : : Type : : Unknown )
2021-03-07 15:39:13 +00:00
{
2022-07-11 13:03:29 +00:00
InputManager : : RemoveHook ( ) ;
ClearInputBindingVariables ( ) ;
2021-03-07 15:39:13 +00:00
}
2021-02-24 16:05:33 +00:00
2021-01-30 11:37:49 +00:00
s_input_binding_type = type ;
s_input_binding_section = section ;
s_input_binding_key = key ;
s_input_binding_display_name = display_name ;
2022-07-11 13:03:29 +00:00
s_input_binding_new_bindings = { } ;
2023-01-15 04:00:51 +00:00
s_input_binding_value_ranges = { } ;
2021-01-30 11:37:49 +00:00
s_input_binding_timer . Reset ( ) ;
2023-01-15 04:00:51 +00:00
const bool game_settings = IsEditingGameSettings ( bsi ) ;
InputManager : : SetHook ( [ game_settings ] ( InputBindingKey key , float value ) - > InputInterceptHook : : CallbackResult {
if ( s_input_binding_type = = InputBindingInfo : : Type : : Unknown )
return InputInterceptHook : : CallbackResult : : StopProcessingEvent ;
2022-07-11 13:03:29 +00:00
// holding the settings lock here will protect the input binding list
auto lock = Host : : GetSettingsLock ( ) ;
2021-07-03 05:11:45 +00:00
2023-01-15 04:00:51 +00:00
float initial_value = value ;
float min_value = value ;
auto it = std : : find_if ( s_input_binding_value_ranges . begin ( ) , s_input_binding_value_ranges . end ( ) ,
[ key ] ( const auto & it ) { return it . first . bits = = key . bits ; } ) ;
if ( it ! = s_input_binding_value_ranges . end ( ) )
{
initial_value = it - > second . first ;
min_value = it - > second . second = std : : min ( it - > second . second , value ) ;
}
else
{
s_input_binding_value_ranges . emplace_back ( key , std : : make_pair ( initial_value , min_value ) ) ;
}
2022-07-11 13:03:29 +00:00
const float abs_value = std : : abs ( value ) ;
2023-01-15 04:00:51 +00:00
const bool reverse_threshold = ( key . source_subtype = = InputSubclass : : ControllerAxis & & initial_value > 0.5f ) ;
2021-01-30 11:37:49 +00:00
2023-01-15 04:00:51 +00:00
for ( InputBindingKey & other_key : s_input_binding_new_bindings )
2022-07-11 13:03:29 +00:00
{
2023-01-15 04:00:51 +00:00
// if this key is in our new binding list, it's a "release", and we're done
2022-07-11 13:03:29 +00:00
if ( other_key . MaskDirection ( ) = = key . MaskDirection ( ) )
{
2023-01-15 04:00:51 +00:00
// for pedals, we wait for it to go back to near its starting point to commit the binding
if ( ( reverse_threshold ? ( ( initial_value - value ) < = 0.25f ) : ( abs_value < 0.5f ) ) )
2021-01-30 11:37:49 +00:00
{
2023-01-15 04:00:51 +00:00
// did we go the full range?
if ( reverse_threshold & & initial_value > 0.5f & & min_value < = - 0.5f )
other_key . modifier = InputModifier : : FullAxis ;
2022-08-25 15:26:55 +00:00
SettingsInterface * bsi = GetEditingSettingsInterface ( game_settings ) ;
2022-07-11 13:03:29 +00:00
const std : : string new_binding ( InputManager : : ConvertInputBindingKeysToString (
2023-01-15 04:00:51 +00:00
s_input_binding_type , s_input_binding_new_bindings . data ( ) , s_input_binding_new_bindings . size ( ) ) ) ;
2022-08-25 15:26:55 +00:00
bsi - > SetStringValue ( s_input_binding_section . c_str ( ) , s_input_binding_key . c_str ( ) , new_binding . c_str ( ) ) ;
SetSettingsChanged ( bsi ) ;
2022-07-11 13:03:29 +00:00
ClearInputBindingVariables ( ) ;
return InputInterceptHook : : CallbackResult : : RemoveHookAndStopProcessingEvent ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
// otherwise, keep waiting
return InputInterceptHook : : CallbackResult : : StopProcessingEvent ;
2021-03-07 15:39:13 +00:00
}
2022-07-11 13:03:29 +00:00
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
// new binding, add it to the list, but wait for a decent distance first, and then wait for release
2023-01-15 04:00:51 +00:00
if ( ( reverse_threshold ? ( abs_value < 0.5f ) : ( abs_value > = 0.5f ) ) )
2022-07-11 13:03:29 +00:00
{
InputBindingKey key_to_add = key ;
2023-01-15 04:00:51 +00:00
key_to_add . modifier = ( value < 0.0f & & ! reverse_threshold ) ? InputModifier : : Negate : InputModifier : : None ;
key_to_add . invert = reverse_threshold ;
2022-07-11 13:03:29 +00:00
s_input_binding_new_bindings . push_back ( key_to_add ) ;
}
2021-03-07 15:39:13 +00:00
2022-07-11 13:03:29 +00:00
return InputInterceptHook : : CallbackResult : : StopProcessingEvent ;
} ) ;
2021-03-07 15:39:13 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DrawInputBindingWindow ( )
2021-01-30 11:37:49 +00:00
{
2023-01-15 04:00:51 +00:00
DebugAssert ( s_input_binding_type ! = InputBindingInfo : : Type : : Unknown ) ;
2021-01-30 11:37:49 +00:00
const double time_remaining = INPUT_BINDING_TIMEOUT_SECONDS - s_input_binding_timer . GetTimeSeconds ( ) ;
if ( time_remaining < = 0.0 )
{
2022-07-11 13:03:29 +00:00
InputManager : : RemoveHook ( ) ;
ClearInputBindingVariables ( ) ;
2021-01-30 11:37:49 +00:00
return ;
}
2023-08-20 02:38:55 +00:00
const char * title = FSUI_ICONSTR ( ICON_FA_GAMEPAD , " Set Input Binding " ) ;
2021-01-30 11:37:49 +00:00
ImGui : : SetNextWindowSize ( LayoutScale ( 500.0f , 0.0f ) ) ;
ImGui : : SetNextWindowPos ( ImGui : : GetIO ( ) . DisplaySize * 0.5f , ImGuiCond_Always , ImVec2 ( 0.5f , 0.5f ) ) ;
ImGui : : OpenPopup ( title ) ;
ImGui : : PushFont ( g_large_font ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowRounding , LayoutScale ( 10.0f ) ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , LayoutScale ( ImGuiFullscreen : : LAYOUT_MENU_BUTTON_X_PADDING ,
ImGuiFullscreen : : LAYOUT_MENU_BUTTON_Y_PADDING ) ) ;
2022-10-31 08:08:26 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_FrameBorderSize , 0.0f ) ;
2022-07-11 13:03:29 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowPadding , LayoutScale ( 20.0f , 20.0f ) ) ;
2021-01-30 11:37:49 +00:00
if ( ImGui : : BeginPopupModal ( title , nullptr ,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoInputs ) )
{
2023-12-13 11:06:15 +00:00
ImGui : : TextWrapped ( " %s " , SmallString : : from_format ( FSUI_FSTR ( " Setting {} binding {}. " ) , s_input_binding_section ,
2023-12-14 06:07:57 +00:00
s_input_binding_display_name )
2023-09-20 13:49:14 +00:00
. c_str ( ) ) ;
2023-08-20 02:38:55 +00:00
ImGui : : TextUnformatted ( FSUI_CSTR ( " Push a controller button or axis now. " ) ) ;
2021-01-30 11:37:49 +00:00
ImGui : : NewLine ( ) ;
2023-12-13 11:06:15 +00:00
ImGui : : TextUnformatted ( SmallString : : from_format ( FSUI_FSTR ( " Timing out in {:.0f} seconds... " ) , time_remaining ) ) ;
2021-01-30 11:37:49 +00:00
ImGui : : EndPopup ( ) ;
}
2022-10-31 08:08:26 +00:00
ImGui : : PopStyleVar ( 4 ) ;
2021-01-30 11:37:49 +00:00
ImGui : : PopFont ( ) ;
}
2022-08-25 15:26:55 +00:00
bool FullscreenUI : : DrawToggleSetting ( SettingsInterface * bsi , const char * title , const char * summary ,
const char * section , const char * key , bool default_value , bool enabled ,
bool allow_tristate , float height , ImFont * font , ImFont * summary_font )
2021-01-30 11:37:49 +00:00
{
2022-08-25 15:26:55 +00:00
if ( ! allow_tristate | | ! IsEditingGameSettings ( bsi ) )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
bool value = bsi - > GetBoolValue ( section , key , default_value ) ;
if ( ! ToggleButton ( title , summary , & value , enabled , height , font , summary_font ) )
2021-01-30 11:37:49 +00:00
return false ;
2022-07-11 13:03:29 +00:00
bsi - > SetBoolValue ( section , key , value ) ;
}
else
{
std : : optional < bool > value ( false ) ;
if ( ! bsi - > GetBoolValue ( section , key , & value . value ( ) ) )
value . reset ( ) ;
if ( ! ThreeWayToggleButton ( title , summary , & value , enabled , height , font , summary_font ) )
2021-01-30 11:37:49 +00:00
return false ;
2022-07-11 13:03:29 +00:00
if ( value . has_value ( ) )
bsi - > SetBoolValue ( section , key , value . value ( ) ) ;
else
bsi - > DeleteValue ( section , key ) ;
}
2021-01-30 11:37:49 +00:00
2022-08-25 15:26:55 +00:00
SetSettingsChanged ( bsi ) ;
2022-07-11 13:03:29 +00:00
return true ;
}
2021-01-30 11:37:49 +00:00
2022-08-25 15:26:55 +00:00
void FullscreenUI : : DrawIntListSetting ( SettingsInterface * bsi , const char * title , const char * summary ,
const char * section , const char * key , int default_value ,
2023-09-03 03:20:38 +00:00
const char * const * options , size_t option_count , bool translate_options ,
2023-09-16 09:06:59 +00:00
int option_offset , bool enabled , float height , ImFont * font , ImFont * summary_font ,
const char * tr_context )
2022-07-11 13:03:29 +00:00
{
2022-08-25 15:26:55 +00:00
const bool game_settings = IsEditingGameSettings ( bsi ) ;
2022-09-17 05:51:05 +00:00
if ( options & & option_count = = 0 )
{
while ( options [ option_count ] ! = nullptr )
option_count + + ;
}
2022-07-11 13:03:29 +00:00
const std : : optional < int > value =
bsi - > GetOptionalIntValue ( section , key , game_settings ? std : : nullopt : std : : optional < int > ( default_value ) ) ;
const int index = value . has_value ( ) ? ( value . value ( ) - option_offset ) : std : : numeric_limits < int > : : min ( ) ;
2023-08-20 02:38:55 +00:00
const char * value_text =
( value . has_value ( ) ) ?
2023-09-03 03:20:38 +00:00
( ( index < 0 | | static_cast < size_t > ( index ) > = option_count ) ?
FSUI_CSTR ( " Unknown " ) :
2023-09-16 09:06:59 +00:00
( translate_options ? Host : : TranslateToCString ( tr_context , options [ index ] ) : options [ index ] ) ) :
2023-08-20 02:38:55 +00:00
FSUI_CSTR ( " Use Global Setting " ) ;
2022-07-11 13:03:29 +00:00
if ( MenuButtonWithValue ( title , summary , value_text , enabled , height , font , summary_font ) )
{
ImGuiFullscreen : : ChoiceDialogOptions cd_options ;
cd_options . reserve ( option_count + 1 ) ;
if ( game_settings )
2023-08-20 02:38:55 +00:00
cd_options . emplace_back ( FSUI_STR ( " Use Global Setting " ) , ! value . has_value ( ) ) ;
2022-07-11 13:03:29 +00:00
for ( size_t i = 0 ; i < option_count ; i + + )
2023-09-03 03:20:38 +00:00
{
2023-09-16 09:06:59 +00:00
cd_options . emplace_back ( translate_options ? Host : : TranslateToString ( tr_context , options [ i ] ) :
2023-09-03 03:20:38 +00:00
std : : string ( options [ i ] ) ,
( i = = static_cast < size_t > ( index ) ) ) ;
}
2022-07-11 13:03:29 +00:00
OpenChoiceDialog ( title , false , std : : move ( cd_options ) ,
2022-08-25 15:26:55 +00:00
[ game_settings , section , key , option_offset ] ( s32 index , const std : : string & title , bool checked ) {
2022-07-11 13:03:29 +00:00
if ( index > = 0 )
{
auto lock = Host : : GetSettingsLock ( ) ;
2022-08-25 15:26:55 +00:00
SettingsInterface * bsi = GetEditingSettingsInterface ( game_settings ) ;
if ( game_settings )
2022-07-11 13:03:29 +00:00
{
if ( index = = 0 )
bsi - > DeleteValue ( section , key ) ;
else
bsi - > SetIntValue ( section , key , index - 1 + option_offset ) ;
}
else
{
bsi - > SetIntValue ( section , key , index + option_offset ) ;
}
2022-08-25 15:26:55 +00:00
SetSettingsChanged ( bsi ) ;
2022-07-11 13:03:29 +00:00
}
CloseChoiceDialog ( ) ;
} ) ;
2021-01-30 11:37:49 +00:00
}
}
2022-08-25 15:26:55 +00:00
void FullscreenUI : : DrawIntRangeSetting ( SettingsInterface * bsi , const char * title , const char * summary ,
const char * section , const char * key , int default_value , int min_value ,
int max_value , const char * format , bool enabled , float height , ImFont * font ,
ImFont * summary_font )
2021-01-30 11:37:49 +00:00
{
2022-08-25 15:26:55 +00:00
const bool game_settings = IsEditingGameSettings ( bsi ) ;
2022-07-11 13:03:29 +00:00
const std : : optional < int > value =
bsi - > GetOptionalIntValue ( section , key , game_settings ? std : : nullopt : std : : optional < int > ( default_value ) ) ;
2024-04-13 04:41:10 +00:00
const SmallString value_text =
value . has_value ( ) ? SmallString : : from_sprintf ( format , value . value ( ) ) : SmallString ( FSUI_VSTR ( " Use Global Setting " ) ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
if ( MenuButtonWithValue ( title , summary , value_text . c_str ( ) , enabled , height , font , summary_font ) )
ImGui : : OpenPopup ( title ) ;
2021-04-22 05:52:11 +00:00
2022-09-17 05:51:05 +00:00
ImGui : : SetNextWindowSize ( LayoutScale ( 500.0f , 190.0f ) ) ;
ImGui : : SetNextWindowPos ( ImGui : : GetIO ( ) . DisplaySize * 0.5f , ImGuiCond_Always , ImVec2 ( 0.5f , 0.5f ) ) ;
2021-03-03 09:14:01 +00:00
2022-07-11 13:03:29 +00:00
ImGui : : PushFont ( g_large_font ) ;
2021-03-03 09:14:01 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowRounding , LayoutScale ( 10.0f ) ) ;
2022-07-11 13:03:29 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , LayoutScale ( ImGuiFullscreen : : LAYOUT_MENU_BUTTON_X_PADDING ,
ImGuiFullscreen : : LAYOUT_MENU_BUTTON_Y_PADDING ) ) ;
2022-10-31 08:08:26 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_FrameBorderSize , 0.0f ) ;
2021-07-04 05:59:52 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowPadding , LayoutScale ( 20.0f , 20.0f ) ) ;
2021-03-03 09:14:01 +00:00
2022-09-17 05:51:05 +00:00
bool is_open = true ;
if ( ImGui : : BeginPopupModal ( title , & is_open ,
2022-07-11 13:03:29 +00:00
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove ) )
2021-03-03 09:14:01 +00:00
{
2022-09-17 05:51:05 +00:00
BeginMenuButtons ( ) ;
const float end = ImGui : : GetCurrentWindow ( ) - > WorkRect . GetWidth ( ) ;
ImGui : : SetNextItemWidth ( end ) ;
2022-07-11 13:03:29 +00:00
s32 dlg_value = static_cast < s32 > ( value . value_or ( default_value ) ) ;
if ( ImGui : : SliderInt ( " ##value " , & dlg_value , min_value , max_value , format , ImGuiSliderFlags_NoInput ) )
{
2022-08-25 15:26:55 +00:00
if ( IsEditingGameSettings ( bsi ) & & dlg_value = = default_value )
2022-07-11 13:03:29 +00:00
bsi - > DeleteValue ( section , key ) ;
else
bsi - > SetIntValue ( section , key , dlg_value ) ;
2021-03-03 09:14:01 +00:00
2022-08-25 15:26:55 +00:00
SetSettingsChanged ( bsi ) ;
2022-07-11 13:03:29 +00:00
}
2021-03-03 09:14:01 +00:00
2022-09-17 05:51:05 +00:00
ImGui : : SetCursorPosY ( ImGui : : GetCursorPosY ( ) + LayoutScale ( 10.0f ) ) ;
2023-08-20 02:38:55 +00:00
if ( MenuButtonWithoutSummary ( FSUI_CSTR ( " OK " ) , true , LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY , g_large_font ,
ImVec2 ( 0.5f , 0.0f ) ) )
2022-09-17 05:51:05 +00:00
{
2022-07-11 13:03:29 +00:00
ImGui : : CloseCurrentPopup ( ) ;
2022-09-17 05:51:05 +00:00
}
2022-07-11 13:03:29 +00:00
EndMenuButtons ( ) ;
2021-03-03 09:14:01 +00:00
2022-07-11 13:03:29 +00:00
ImGui : : EndPopup ( ) ;
}
2021-03-03 09:14:01 +00:00
2022-10-31 08:08:26 +00:00
ImGui : : PopStyleVar ( 4 ) ;
2022-07-11 13:03:29 +00:00
ImGui : : PopFont ( ) ;
}
2021-03-03 09:14:01 +00:00
2022-08-25 15:26:55 +00:00
void FullscreenUI : : DrawFloatRangeSetting ( SettingsInterface * bsi , const char * title , const char * summary ,
const char * section , const char * key , float default_value , float min_value ,
float max_value , const char * format , float multiplier , bool enabled ,
float height , ImFont * font , ImFont * summary_font )
2022-07-11 13:03:29 +00:00
{
2022-08-25 15:26:55 +00:00
const bool game_settings = IsEditingGameSettings ( bsi ) ;
2022-07-11 13:03:29 +00:00
const std : : optional < float > value =
bsi - > GetOptionalFloatValue ( section , key , game_settings ? std : : nullopt : std : : optional < float > ( default_value ) ) ;
2024-04-13 04:41:10 +00:00
const SmallString value_text = value . has_value ( ) ? SmallString : : from_sprintf ( format , value . value ( ) * multiplier ) :
SmallString ( FSUI_VSTR ( " Use Global Setting " ) ) ;
2021-03-03 09:14:01 +00:00
2022-07-11 13:03:29 +00:00
if ( MenuButtonWithValue ( title , summary , value_text . c_str ( ) , enabled , height , font , summary_font ) )
ImGui : : OpenPopup ( title ) ;
2021-03-03 09:14:01 +00:00
2022-09-17 05:51:05 +00:00
ImGui : : SetNextWindowSize ( LayoutScale ( 500.0f , 190.0f ) ) ;
ImGui : : SetNextWindowPos ( ImGui : : GetIO ( ) . DisplaySize * 0.5f , ImGuiCond_Always , ImVec2 ( 0.5f , 0.5f ) ) ;
2021-03-03 09:14:01 +00:00
2022-07-11 13:03:29 +00:00
ImGui : : PushFont ( g_large_font ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowRounding , LayoutScale ( 10.0f ) ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , LayoutScale ( ImGuiFullscreen : : LAYOUT_MENU_BUTTON_X_PADDING ,
ImGuiFullscreen : : LAYOUT_MENU_BUTTON_Y_PADDING ) ) ;
2022-10-31 08:08:26 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_FrameBorderSize , 0.0f ) ;
2022-07-11 13:03:29 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowPadding , LayoutScale ( 20.0f , 20.0f ) ) ;
2021-03-03 09:14:01 +00:00
2022-09-17 05:51:05 +00:00
bool is_open = true ;
if ( ImGui : : BeginPopupModal ( title , & is_open ,
2022-07-11 13:03:29 +00:00
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove ) )
{
2022-09-17 05:51:05 +00:00
BeginMenuButtons ( ) ;
const float end = ImGui : : GetCurrentWindow ( ) - > WorkRect . GetWidth ( ) ;
ImGui : : SetNextItemWidth ( end ) ;
2022-08-25 15:26:55 +00:00
float dlg_value = value . value_or ( default_value ) * multiplier ;
2022-10-31 08:08:26 +00:00
if ( ImGui : : SliderFloat ( " ##value " , & dlg_value , min_value * multiplier , max_value * multiplier , format ,
ImGuiSliderFlags_NoInput ) )
2021-03-03 09:14:01 +00:00
{
2022-08-25 15:26:55 +00:00
dlg_value / = multiplier ;
if ( IsEditingGameSettings ( bsi ) & & dlg_value = = default_value )
2022-07-11 13:03:29 +00:00
bsi - > DeleteValue ( section , key ) ;
else
bsi - > SetFloatValue ( section , key , dlg_value ) ;
2022-08-25 15:26:55 +00:00
SetSettingsChanged ( bsi ) ;
2021-03-03 09:14:01 +00:00
}
2022-09-17 05:51:05 +00:00
ImGui : : SetCursorPosY ( ImGui : : GetCursorPosY ( ) + LayoutScale ( 10.0f ) ) ;
2023-08-20 02:38:55 +00:00
if ( MenuButtonWithoutSummary ( FSUI_CSTR ( " OK " ) , true , LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY , g_large_font ,
ImVec2 ( 0.5f , 0.0f ) ) )
2022-09-17 05:51:05 +00:00
{
2021-03-03 09:14:01 +00:00
ImGui : : CloseCurrentPopup ( ) ;
2022-09-17 05:51:05 +00:00
}
2021-03-03 09:14:01 +00:00
EndMenuButtons ( ) ;
ImGui : : EndPopup ( ) ;
}
2022-10-31 08:08:26 +00:00
ImGui : : PopStyleVar ( 4 ) ;
ImGui : : PopFont ( ) ;
}
void FullscreenUI : : DrawFloatSpinBoxSetting ( SettingsInterface * bsi , const char * title , const char * summary ,
const char * section , const char * key , float default_value , float min_value ,
float max_value , float step_value , float multiplier , const char * format ,
bool enabled , float height , ImFont * font , ImFont * summary_font )
{
const bool game_settings = IsEditingGameSettings ( bsi ) ;
const std : : optional < float > value =
bsi - > GetOptionalFloatValue ( section , key , game_settings ? std : : nullopt : std : : optional < float > ( default_value ) ) ;
2024-04-13 04:41:10 +00:00
const SmallString value_text = value . has_value ( ) ? SmallString : : from_sprintf ( format , value . value ( ) * multiplier ) :
SmallString ( FSUI_VSTR ( " Use Global Setting " ) ) ;
2022-10-31 08:08:26 +00:00
static bool manual_input = false ;
if ( MenuButtonWithValue ( title , summary , value_text . c_str ( ) , enabled , height , font , summary_font ) )
{
ImGui : : OpenPopup ( title ) ;
manual_input = false ;
}
ImGui : : SetNextWindowSize ( LayoutScale ( 500.0f , 190.0f ) ) ;
ImGui : : SetNextWindowPos ( ImGui : : GetIO ( ) . DisplaySize * 0.5f , ImGuiCond_Always , ImVec2 ( 0.5f , 0.5f ) ) ;
ImGui : : PushFont ( g_large_font ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowRounding , LayoutScale ( 10.0f ) ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , LayoutScale ( ImGuiFullscreen : : LAYOUT_MENU_BUTTON_X_PADDING ,
ImGuiFullscreen : : LAYOUT_MENU_BUTTON_Y_PADDING ) ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_FrameBorderSize , 0.0f ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowPadding , LayoutScale ( 20.0f , 20.0f ) ) ;
bool is_open = true ;
if ( ImGui : : BeginPopupModal ( title , & is_open ,
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove ) )
{
BeginMenuButtons ( ) ;
float dlg_value = value . value_or ( default_value ) * multiplier ;
bool dlg_value_changed = false ;
char str_value [ 32 ] ;
std : : snprintf ( str_value , std : : size ( str_value ) , format , dlg_value ) ;
if ( manual_input )
{
const float end = ImGui : : GetCurrentWindow ( ) - > WorkRect . GetWidth ( ) ;
ImGui : : SetNextItemWidth ( end ) ;
// round trip to drop any suffixes (e.g. percent)
if ( auto tmp_value = StringUtil : : FromChars < float > ( str_value ) ; tmp_value . has_value ( ) )
{
std : : snprintf ( str_value , std : : size ( str_value ) ,
( ( tmp_value . value ( ) - std : : floor ( tmp_value . value ( ) ) ) < 0.01f ) ? " %.0f " : " %f " , tmp_value . value ( ) ) ;
}
if ( ImGui : : InputText ( " ##value " , str_value , std : : size ( str_value ) , ImGuiInputTextFlags_CharsDecimal ) )
{
dlg_value = StringUtil : : FromChars < float > ( str_value ) . value_or ( dlg_value ) ;
dlg_value_changed = true ;
}
ImGui : : SetCursorPosY ( ImGui : : GetCursorPosY ( ) + LayoutScale ( 10.0f ) ) ;
}
else
{
const ImVec2 & padding ( ImGui : : GetStyle ( ) . FramePadding ) ;
ImVec2 button_pos ( ImGui : : GetCursorPos ( ) ) ;
// Align value text in middle.
ImGui : : SetCursorPosY (
button_pos . y +
( ( LayoutScale ( LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ) + padding . y * 2.0f ) - g_large_font - > FontSize ) * 0.5f ) ;
ImGui : : TextUnformatted ( str_value ) ;
float step = 0 ;
if ( FloatingButton ( ICON_FA_CHEVRON_UP , padding . x , button_pos . y , - 1.0f , - 1.0f , 1.0f , 0.0f , true , g_large_font ,
& button_pos , true ) )
{
step = step_value ;
}
if ( FloatingButton ( ICON_FA_CHEVRON_DOWN , button_pos . x - padding . x , button_pos . y , - 1.0f , - 1.0f , - 1.0f , 0.0f , true ,
g_large_font , & button_pos , true ) )
{
step = - step_value ;
}
if ( FloatingButton ( ICON_FA_KEYBOARD , button_pos . x - padding . x , button_pos . y , - 1.0f , - 1.0f , - 1.0f , 0.0f , true ,
g_large_font , & button_pos ) )
{
manual_input = true ;
}
if ( FloatingButton ( ICON_FA_TRASH , button_pos . x - padding . x , button_pos . y , - 1.0f , - 1.0f , - 1.0f , 0.0f , true ,
g_large_font , & button_pos ) )
{
dlg_value = default_value * multiplier ;
dlg_value_changed = true ;
}
if ( step ! = 0 )
{
dlg_value + = step * multiplier ;
dlg_value_changed = true ;
}
ImGui : : SetCursorPosY ( button_pos . y + ( padding . y * 2.0f ) +
LayoutScale ( LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY + 10.0f ) ) ;
}
if ( dlg_value_changed )
{
dlg_value = std : : clamp ( dlg_value / multiplier , min_value , max_value ) ;
if ( IsEditingGameSettings ( bsi ) & & dlg_value = = default_value )
bsi - > DeleteValue ( section , key ) ;
else
bsi - > SetFloatValue ( section , key , dlg_value ) ;
SetSettingsChanged ( bsi ) ;
}
2023-08-20 02:38:55 +00:00
if ( MenuButtonWithoutSummary ( FSUI_CSTR ( " OK " ) , true , LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY , g_large_font ,
ImVec2 ( 0.5f , 0.0f ) ) )
2022-10-31 08:08:26 +00:00
{
ImGui : : CloseCurrentPopup ( ) ;
}
EndMenuButtons ( ) ;
ImGui : : EndPopup ( ) ;
}
ImGui : : PopStyleVar ( 4 ) ;
2021-03-03 09:14:01 +00:00
ImGui : : PopFont ( ) ;
}
2022-12-20 11:26:19 +00:00
#if 0
2022-08-25 15:26:55 +00:00
void FullscreenUI : : DrawIntRectSetting ( SettingsInterface * bsi , const char * title , const char * summary ,
const char * section , const char * left_key , int default_left , const char * top_key ,
int default_top , const char * right_key , int default_right , const char * bottom_key ,
int default_bottom , int min_value , int max_value , const char * format ,
bool enabled , float height , ImFont * font , ImFont * summary_font )
2021-03-03 09:14:01 +00:00
{
2022-08-25 15:26:55 +00:00
const bool game_settings = IsEditingGameSettings ( bsi ) ;
2022-07-11 13:03:29 +00:00
const std : : optional < int > left_value =
bsi - > GetOptionalIntValue ( section , left_key , game_settings ? std : : nullopt : std : : optional < int > ( default_left ) ) ;
const std : : optional < int > top_value =
bsi - > GetOptionalIntValue ( section , top_key , game_settings ? std : : nullopt : std : : optional < int > ( default_top ) ) ;
const std : : optional < int > right_value =
bsi - > GetOptionalIntValue ( section , right_key , game_settings ? std : : nullopt : std : : optional < int > ( default_right ) ) ;
const std : : optional < int > bottom_value =
bsi - > GetOptionalIntValue ( section , bottom_key , game_settings ? std : : nullopt : std : : optional < int > ( default_bottom ) ) ;
2024-04-13 04:41:10 +00:00
const SmallString value_text = SmallString : : from_format (
2022-07-11 13:03:29 +00:00
" {}/{}/{}/{} " ,
2024-04-13 04:41:10 +00:00
left_value . has_value ( ) ? TinyString : : from_sprintf ( format , left_value . value ( ) ) : TinyString ( FSUI_VSTR ( " Default " ) ) ,
top_value . has_value ( ) ? TinyString : : from_sprintf ( format , top_value . value ( ) ) : TinyString ( FSUI_VSTR ( " Default " ) ) ,
right_value . has_value ( ) ? TinyString : : from_sprintf ( format , right_value . value ( ) ) : TinyString ( FSUI_VSTR ( " Default " ) ) ,
bottom_value . has_value ( ) ? TinyString : : from_sprintf ( format , bottom_value . value ( ) ) : TinyString ( FSUI_VSTR ( " Default " ) ) ) ;
2022-07-11 13:03:29 +00:00
if ( MenuButtonWithValue ( title , summary , value_text . c_str ( ) , enabled , height , font , summary_font ) )
ImGui : : OpenPopup ( title ) ;
2022-09-17 05:51:05 +00:00
ImGui : : SetNextWindowSize ( LayoutScale ( 500.0f , 370.0f ) ) ;
ImGui : : SetNextWindowPos ( ImGui : : GetIO ( ) . DisplaySize * 0.5f , ImGuiCond_Always , ImVec2 ( 0.5f , 0.5f ) ) ;
2021-03-03 09:14:01 +00:00
2022-07-11 13:03:29 +00:00
ImGui : : PushFont ( g_large_font ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowRounding , LayoutScale ( 10.0f ) ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , LayoutScale ( ImGuiFullscreen : : LAYOUT_MENU_BUTTON_X_PADDING ,
ImGuiFullscreen : : LAYOUT_MENU_BUTTON_Y_PADDING ) ) ;
2022-10-31 08:08:26 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_FrameBorderSize , 0.0f ) ;
2022-07-11 13:03:29 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowPadding , LayoutScale ( 20.0f , 20.0f ) ) ;
2021-03-03 09:14:01 +00:00
2022-09-17 05:51:05 +00:00
bool is_open = true ;
if ( ImGui : : BeginPopupModal ( title , & is_open ,
2022-07-11 13:03:29 +00:00
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove ) )
2021-03-03 09:14:01 +00:00
{
2022-07-11 13:03:29 +00:00
s32 dlg_left_value = static_cast < s32 > ( left_value . value_or ( default_left ) ) ;
s32 dlg_top_value = static_cast < s32 > ( top_value . value_or ( default_top ) ) ;
s32 dlg_right_value = static_cast < s32 > ( right_value . value_or ( default_right ) ) ;
s32 dlg_bottom_value = static_cast < s32 > ( bottom_value . value_or ( default_bottom ) ) ;
2022-09-17 05:51:05 +00:00
BeginMenuButtons ( ) ;
const float midpoint = LayoutScale ( 150.0f ) ;
const float end = ( ImGui : : GetCurrentWindow ( ) - > WorkRect . GetWidth ( ) - midpoint ) + ImGui : : GetStyle ( ) . WindowPadding . x ;
2022-08-25 15:26:55 +00:00
ImGui : : TextUnformatted ( " Left: " ) ;
2022-09-17 05:51:05 +00:00
ImGui : : SameLine ( midpoint ) ;
ImGui : : SetNextItemWidth ( end ) ;
2022-07-11 13:03:29 +00:00
const bool left_modified =
2022-08-25 15:26:55 +00:00
ImGui : : SliderInt ( " ##left " , & dlg_left_value , min_value , max_value , format , ImGuiSliderFlags_NoInput ) ;
2022-09-17 05:51:05 +00:00
ImGui : : SetCursorPosY ( ImGui : : GetCursorPosY ( ) + LayoutScale ( 10.0f ) ) ;
2022-08-25 15:26:55 +00:00
ImGui : : TextUnformatted ( " Top: " ) ;
2022-09-17 05:51:05 +00:00
ImGui : : SameLine ( midpoint ) ;
ImGui : : SetNextItemWidth ( end ) ;
2022-07-11 13:03:29 +00:00
const bool top_modified =
2022-08-25 15:26:55 +00:00
ImGui : : SliderInt ( " ##top " , & dlg_top_value , min_value , max_value , format , ImGuiSliderFlags_NoInput ) ;
2022-09-17 05:51:05 +00:00
ImGui : : SetCursorPosY ( ImGui : : GetCursorPosY ( ) + LayoutScale ( 10.0f ) ) ;
2022-08-25 15:26:55 +00:00
ImGui : : TextUnformatted ( " Right: " ) ;
2022-09-17 05:51:05 +00:00
ImGui : : SameLine ( midpoint ) ;
ImGui : : SetNextItemWidth ( end ) ;
2022-07-11 13:03:29 +00:00
const bool right_modified =
2022-08-25 15:26:55 +00:00
ImGui : : SliderInt ( " ##right " , & dlg_right_value , min_value , max_value , format , ImGuiSliderFlags_NoInput ) ;
2022-09-17 05:51:05 +00:00
ImGui : : SetCursorPosY ( ImGui : : GetCursorPosY ( ) + LayoutScale ( 10.0f ) ) ;
2022-08-25 15:26:55 +00:00
ImGui : : TextUnformatted ( " Bottom: " ) ;
2022-09-17 05:51:05 +00:00
ImGui : : SameLine ( midpoint ) ;
ImGui : : SetNextItemWidth ( end ) ;
2022-07-11 13:03:29 +00:00
const bool bottom_modified =
2022-08-25 15:26:55 +00:00
ImGui : : SliderInt ( " ##bottom " , & dlg_bottom_value , min_value , max_value , format , ImGuiSliderFlags_NoInput ) ;
2022-09-17 05:51:05 +00:00
ImGui : : SetCursorPosY ( ImGui : : GetCursorPosY ( ) + LayoutScale ( 10.0f ) ) ;
2022-07-11 13:03:29 +00:00
if ( left_modified )
{
2022-08-25 15:26:55 +00:00
if ( IsEditingGameSettings ( bsi ) & & dlg_left_value = = default_left )
2022-07-11 13:03:29 +00:00
bsi - > DeleteValue ( section , left_key ) ;
else
bsi - > SetIntValue ( section , left_key , dlg_left_value ) ;
}
if ( top_modified )
{
2022-08-25 15:26:55 +00:00
if ( IsEditingGameSettings ( bsi ) & & dlg_top_value = = default_top )
2022-07-11 13:03:29 +00:00
bsi - > DeleteValue ( section , top_key ) ;
else
bsi - > SetIntValue ( section , top_key , dlg_top_value ) ;
}
if ( right_modified )
{
2022-08-25 15:26:55 +00:00
if ( IsEditingGameSettings ( bsi ) & & dlg_right_value = = default_right )
2022-07-11 13:03:29 +00:00
bsi - > DeleteValue ( section , right_key ) ;
else
bsi - > SetIntValue ( section , right_key , dlg_right_value ) ;
}
if ( bottom_modified )
{
2022-08-25 15:26:55 +00:00
if ( IsEditingGameSettings ( bsi ) & & dlg_bottom_value = = default_bottom )
2022-07-11 13:03:29 +00:00
bsi - > DeleteValue ( section , bottom_key ) ;
else
bsi - > SetIntValue ( section , bottom_key , dlg_bottom_value ) ;
}
2021-03-03 09:14:01 +00:00
2022-07-11 13:03:29 +00:00
if ( left_modified | | top_modified | | right_modified | | bottom_modified )
2022-08-25 15:26:55 +00:00
SetSettingsChanged ( bsi ) ;
2021-03-03 09:14:01 +00:00
2022-09-17 05:51:05 +00:00
if ( MenuButtonWithoutSummary ( " OK " , true , LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY , g_large_font , ImVec2 ( 0.5f , 0.0f ) ) )
{
2022-07-11 13:03:29 +00:00
ImGui : : CloseCurrentPopup ( ) ;
2022-09-17 05:51:05 +00:00
}
2022-07-11 13:03:29 +00:00
EndMenuButtons ( ) ;
2021-03-03 09:14:01 +00:00
2022-07-11 13:03:29 +00:00
ImGui : : EndPopup ( ) ;
}
2021-03-03 09:14:01 +00:00
2022-10-31 08:08:26 +00:00
ImGui : : PopStyleVar ( 4 ) ;
2022-07-11 13:03:29 +00:00
ImGui : : PopFont ( ) ;
}
2022-12-20 11:26:19 +00:00
# endif
2021-04-22 05:52:11 +00:00
2022-10-23 04:09:54 +00:00
void FullscreenUI : : DrawIntSpinBoxSetting ( SettingsInterface * bsi , const char * title , const char * summary ,
const char * section , const char * key , int default_value , int min_value ,
int max_value , int step_value , const char * format , bool enabled , float height ,
ImFont * font , ImFont * summary_font )
{
const bool game_settings = IsEditingGameSettings ( bsi ) ;
const std : : optional < int > value =
bsi - > GetOptionalIntValue ( section , key , game_settings ? std : : nullopt : std : : optional < int > ( default_value ) ) ;
TinyString value_text ;
if ( value . has_value ( ) )
2023-12-13 11:06:15 +00:00
value_text . sprintf ( format , value . value ( ) ) ;
2022-10-23 04:09:54 +00:00
else
2023-08-20 02:38:55 +00:00
value_text = FSUI_VSTR ( " Use Global Setting " ) ;
2022-10-23 04:09:54 +00:00
static bool manual_input = false ;
if ( MenuButtonWithValue ( title , summary , value_text , enabled , height , font , summary_font ) )
{
ImGui : : OpenPopup ( title ) ;
manual_input = false ;
}
ImGui : : SetNextWindowSize ( LayoutScale ( 500.0f , 190.0f ) ) ;
ImGui : : SetNextWindowPos ( ImGui : : GetIO ( ) . DisplaySize * 0.5f , ImGuiCond_Always , ImVec2 ( 0.5f , 0.5f ) ) ;
ImGui : : PushFont ( g_large_font ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowRounding , LayoutScale ( 10.0f ) ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , LayoutScale ( ImGuiFullscreen : : LAYOUT_MENU_BUTTON_X_PADDING ,
ImGuiFullscreen : : LAYOUT_MENU_BUTTON_Y_PADDING ) ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_FrameBorderSize , 0.0f ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowPadding , LayoutScale ( 20.0f , 20.0f ) ) ;
bool is_open = true ;
if ( ImGui : : BeginPopupModal ( title , & is_open ,
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove ) )
{
BeginMenuButtons ( ) ;
s32 dlg_value = static_cast < s32 > ( value . value_or ( default_value ) ) ;
bool dlg_value_changed = false ;
char str_value [ 32 ] ;
std : : snprintf ( str_value , std : : size ( str_value ) , format , dlg_value ) ;
if ( manual_input )
{
const float end = ImGui : : GetCurrentWindow ( ) - > WorkRect . GetWidth ( ) ;
ImGui : : SetNextItemWidth ( end ) ;
std : : snprintf ( str_value , std : : size ( str_value ) , " %d " , dlg_value ) ;
if ( ImGui : : InputText ( " ##value " , str_value , std : : size ( str_value ) , ImGuiInputTextFlags_CharsDecimal ) )
{
dlg_value = StringUtil : : FromChars < s32 > ( str_value ) . value_or ( dlg_value ) ;
dlg_value_changed = true ;
}
ImGui : : SetCursorPosY ( ImGui : : GetCursorPosY ( ) + LayoutScale ( 10.0f ) ) ;
}
else
{
const ImVec2 & padding ( ImGui : : GetStyle ( ) . FramePadding ) ;
ImVec2 button_pos ( ImGui : : GetCursorPos ( ) ) ;
// Align value text in middle.
ImGui : : SetCursorPosY (
button_pos . y +
( ( LayoutScale ( LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ) + padding . y * 2.0f ) - g_large_font - > FontSize ) * 0.5f ) ;
ImGui : : TextUnformatted ( str_value ) ;
s32 step = 0 ;
if ( FloatingButton ( ICON_FA_CHEVRON_UP , padding . x , button_pos . y , - 1.0f , - 1.0f , 1.0f , 0.0f , true , g_large_font ,
& button_pos , true ) )
{
step = step_value ;
}
if ( FloatingButton ( ICON_FA_CHEVRON_DOWN , button_pos . x - padding . x , button_pos . y , - 1.0f , - 1.0f , - 1.0f , 0.0f , true ,
g_large_font , & button_pos , true ) )
{
step = - step_value ;
}
if ( FloatingButton ( ICON_FA_KEYBOARD , button_pos . x - padding . x , button_pos . y , - 1.0f , - 1.0f , - 1.0f , 0.0f , true ,
g_large_font , & button_pos ) )
{
manual_input = true ;
}
if ( FloatingButton ( ICON_FA_TRASH , button_pos . x - padding . x , button_pos . y , - 1.0f , - 1.0f , - 1.0f , 0.0f , true ,
g_large_font , & button_pos ) )
{
dlg_value = default_value ;
dlg_value_changed = true ;
}
if ( step ! = 0 )
{
dlg_value + = step ;
dlg_value_changed = true ;
}
ImGui : : SetCursorPosY ( button_pos . y + ( padding . y * 2.0f ) +
LayoutScale ( LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY + 10.0f ) ) ;
}
if ( dlg_value_changed )
{
dlg_value = std : : clamp ( dlg_value , min_value , max_value ) ;
if ( IsEditingGameSettings ( bsi ) & & dlg_value = = default_value )
bsi - > DeleteValue ( section , key ) ;
else
bsi - > SetIntValue ( section , key , dlg_value ) ;
SetSettingsChanged ( bsi ) ;
}
2023-08-20 02:38:55 +00:00
if ( MenuButtonWithoutSummary ( FSUI_CSTR ( " OK " ) , true , LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY , g_large_font ,
ImVec2 ( 0.5f , 0.0f ) ) )
2022-10-23 04:09:54 +00:00
{
ImGui : : CloseCurrentPopup ( ) ;
}
EndMenuButtons ( ) ;
ImGui : : EndPopup ( ) ;
}
ImGui : : PopStyleVar ( 4 ) ;
ImGui : : PopFont ( ) ;
}
2022-12-20 11:26:19 +00:00
#if 0
2022-08-25 15:26:55 +00:00
void FullscreenUI : : DrawStringListSetting ( SettingsInterface * bsi , const char * title , const char * summary ,
const char * section , const char * key , const char * default_value ,
const char * const * options , const char * const * option_values ,
size_t option_count , bool enabled , float height , ImFont * font ,
ImFont * summary_font )
2021-03-08 19:42:32 +00:00
{
2022-08-25 15:26:55 +00:00
const bool game_settings = IsEditingGameSettings ( bsi ) ;
2024-04-07 10:43:13 +00:00
const std : : optional < SmallString > value ( bsi - > GetOptionalSmallStringValue (
2022-07-11 13:03:29 +00:00
section , key , game_settings ? std : : nullopt : std : : optional < const char * > ( default_value ) ) ) ;
if ( option_count = = 0 )
2021-03-08 19:42:32 +00:00
{
2022-07-11 13:03:29 +00:00
// select from null entry
while ( options & & options [ option_count ] ! = nullptr )
option_count + + ;
2021-03-08 19:42:32 +00:00
}
2022-07-11 13:03:29 +00:00
size_t index = option_count ;
if ( value . has_value ( ) )
2021-03-08 19:42:32 +00:00
{
2022-07-11 13:03:29 +00:00
for ( size_t i = 0 ; i < option_count ; i + + )
2021-03-08 19:42:32 +00:00
{
2022-07-11 13:03:29 +00:00
if ( value = = option_values [ i ] )
{
index = i ;
break ;
}
2021-03-08 19:42:32 +00:00
}
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
if ( MenuButtonWithValue ( title , summary ,
value . has_value ( ) ? ( ( index < option_count ) ? options [ index ] : " Unknown " ) :
" Use Global Setting " ,
enabled , height , font , summary_font ) )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
ImGuiFullscreen : : ChoiceDialogOptions cd_options ;
cd_options . reserve ( option_count + 1 ) ;
if ( game_settings )
cd_options . emplace_back ( " Use Global Setting " , ! value . has_value ( ) ) ;
for ( size_t i = 0 ; i < option_count ; i + + )
cd_options . emplace_back ( options [ i ] , ( value . has_value ( ) & & i = = static_cast < size_t > ( index ) ) ) ;
OpenChoiceDialog ( title , false , std : : move ( cd_options ) ,
2022-08-25 15:26:55 +00:00
[ game_settings , section , key , option_values ] ( s32 index , const std : : string & title , bool checked ) {
2022-07-11 13:03:29 +00:00
if ( index > = 0 )
{
auto lock = Host : : GetSettingsLock ( ) ;
2022-08-25 15:26:55 +00:00
SettingsInterface * bsi = GetEditingSettingsInterface ( game_settings ) ;
if ( game_settings )
2022-07-11 13:03:29 +00:00
{
if ( index = = 0 )
bsi - > DeleteValue ( section , key ) ;
else
bsi - > SetStringValue ( section , key , option_values [ index - 1 ] ) ;
}
else
{
bsi - > SetStringValue ( section , key , option_values [ index ] ) ;
}
2022-08-25 15:26:55 +00:00
SetSettingsChanged ( bsi ) ;
2022-07-11 13:03:29 +00:00
}
CloseChoiceDialog ( ) ;
} ) ;
}
}
2022-12-20 11:26:19 +00:00
# endif
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
template < typename DataType , typename SizeType >
2022-08-25 15:26:55 +00:00
void FullscreenUI : : DrawEnumSetting ( SettingsInterface * bsi , const char * title , const char * summary , const char * section ,
const char * key , DataType default_value ,
2022-07-11 13:03:29 +00:00
std : : optional < DataType > ( * from_string_function ) ( const char * str ) ,
const char * ( * to_string_function ) ( DataType value ) ,
const char * ( * to_display_string_function ) ( DataType value ) , SizeType option_count ,
bool enabled /*= true*/ ,
float height /*= ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT*/ ,
ImFont * font /*= g_large_font*/ , ImFont * summary_font /*= g_medium_font*/ )
{
2022-08-25 15:26:55 +00:00
const bool game_settings = IsEditingGameSettings ( bsi ) ;
2024-04-07 10:43:13 +00:00
const std : : optional < SmallString > value ( bsi - > GetOptionalSmallStringValue (
2022-07-11 13:03:29 +00:00
section , key , game_settings ? std : : nullopt : std : : optional < const char * > ( to_string_function ( default_value ) ) ) ) ;
2021-06-30 09:12:56 +00:00
2022-07-11 13:03:29 +00:00
const std : : optional < DataType > typed_value ( value . has_value ( ) ? from_string_function ( value - > c_str ( ) ) : std : : nullopt ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
if ( MenuButtonWithValue ( title , summary ,
typed_value . has_value ( ) ? to_display_string_function ( typed_value . value ( ) ) :
2023-08-20 02:38:55 +00:00
FSUI_CSTR ( " Use Global Setting " ) ,
2022-07-11 13:03:29 +00:00
enabled , height , font , summary_font ) )
{
ImGuiFullscreen : : ChoiceDialogOptions cd_options ;
cd_options . reserve ( static_cast < u32 > ( option_count ) + 1 ) ;
if ( game_settings )
2023-08-20 02:38:55 +00:00
cd_options . emplace_back ( FSUI_CSTR ( " Use Global Setting " ) , ! value . has_value ( ) ) ;
2022-07-11 13:03:29 +00:00
for ( u32 i = 0 ; i < static_cast < u32 > ( option_count ) ; i + + )
cd_options . emplace_back ( to_display_string_function ( static_cast < DataType > ( i ) ) ,
( typed_value . has_value ( ) & & i = = static_cast < u32 > ( typed_value . value ( ) ) ) ) ;
2022-08-25 15:26:55 +00:00
OpenChoiceDialog (
title , false , std : : move ( cd_options ) ,
[ section , key , to_string_function , game_settings ] ( s32 index , const std : : string & title , bool checked ) {
if ( index > = 0 )
{
auto lock = Host : : GetSettingsLock ( ) ;
SettingsInterface * bsi = GetEditingSettingsInterface ( game_settings ) ;
if ( game_settings )
{
if ( index = = 0 )
bsi - > DeleteValue ( section , key ) ;
else
bsi - > SetStringValue ( section , key , to_string_function ( static_cast < DataType > ( index - 1 ) ) ) ;
}
else
{
bsi - > SetStringValue ( section , key , to_string_function ( static_cast < DataType > ( index ) ) ) ;
}
2022-07-11 13:03:29 +00:00
2022-08-25 15:26:55 +00:00
SetSettingsChanged ( bsi ) ;
}
2022-07-11 13:03:29 +00:00
2022-08-25 15:26:55 +00:00
CloseChoiceDialog ( ) ;
} ) ;
2022-07-11 13:03:29 +00:00
}
}
2022-08-25 15:26:55 +00:00
void FullscreenUI : : DrawFloatListSetting ( SettingsInterface * bsi , const char * title , const char * summary ,
const char * section , const char * key , float default_value ,
const char * const * options , const float * option_values , size_t option_count ,
2023-09-03 03:20:38 +00:00
bool translate_options , bool enabled , float height , ImFont * font ,
ImFont * summary_font )
2022-07-11 13:03:29 +00:00
{
2022-08-25 15:26:55 +00:00
const bool game_settings = IsEditingGameSettings ( bsi ) ;
2022-07-11 13:03:29 +00:00
const std : : optional < float > value (
bsi - > GetOptionalFloatValue ( section , key , game_settings ? std : : nullopt : std : : optional < float > ( default_value ) ) ) ;
2021-06-30 09:12:56 +00:00
2022-07-11 13:03:29 +00:00
if ( option_count = = 0 )
{
// select from null entry
while ( options & & options [ option_count ] ! = nullptr )
option_count + + ;
}
2021-06-30 09:12:56 +00:00
2022-07-11 13:03:29 +00:00
size_t index = option_count ;
if ( value . has_value ( ) )
{
for ( size_t i = 0 ; i < option_count ; i + + )
2021-06-30 09:12:56 +00:00
{
2022-07-11 13:03:29 +00:00
if ( value = = option_values [ i ] )
2021-06-30 09:12:56 +00:00
{
2022-07-11 13:03:29 +00:00
index = i ;
break ;
2021-06-30 09:12:56 +00:00
}
}
2021-01-30 11:37:49 +00:00
}
2023-09-03 03:20:38 +00:00
if ( MenuButtonWithValue (
title , summary ,
value . has_value ( ) ?
( ( index < option_count ) ?
( translate_options ? Host : : TranslateToCString ( TR_CONTEXT , options [ index ] ) : options [ index ] ) :
FSUI_CSTR ( " Unknown " ) ) :
FSUI_CSTR ( " Use Global Setting " ) ,
enabled , height , font , summary_font ) )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
ImGuiFullscreen : : ChoiceDialogOptions cd_options ;
cd_options . reserve ( option_count + 1 ) ;
if ( game_settings )
2023-08-20 02:38:55 +00:00
cd_options . emplace_back ( FSUI_CSTR ( " Use Global Setting " ) , ! value . has_value ( ) ) ;
2022-07-11 13:03:29 +00:00
for ( size_t i = 0 ; i < option_count ; i + + )
2023-09-03 03:20:38 +00:00
{
cd_options . emplace_back ( translate_options ? Host : : TranslateToString ( TR_CONTEXT , options [ i ] ) :
std : : string ( options [ i ] ) ,
( value . has_value ( ) & & i = = static_cast < size_t > ( index ) ) ) ;
}
2022-07-11 13:03:29 +00:00
OpenChoiceDialog ( title , false , std : : move ( cd_options ) ,
2022-08-25 15:26:55 +00:00
[ game_settings , section , key , option_values ] ( s32 index , const std : : string & title , bool checked ) {
2022-07-11 13:03:29 +00:00
if ( index > = 0 )
{
auto lock = Host : : GetSettingsLock ( ) ;
2022-08-25 15:26:55 +00:00
SettingsInterface * bsi = GetEditingSettingsInterface ( game_settings ) ;
if ( game_settings )
2022-07-11 13:03:29 +00:00
{
if ( index = = 0 )
bsi - > DeleteValue ( section , key ) ;
else
bsi - > SetFloatValue ( section , key , option_values [ index - 1 ] ) ;
}
else
{
bsi - > SetFloatValue ( section , key , option_values [ index ] ) ;
}
2022-08-25 15:26:55 +00:00
SetSettingsChanged ( bsi ) ;
2022-07-11 13:03:29 +00:00
}
CloseChoiceDialog ( ) ;
} ) ;
}
}
2021-01-30 11:37:49 +00:00
2022-08-25 15:26:55 +00:00
void FullscreenUI : : DrawFolderSetting ( SettingsInterface * bsi , const char * title , const char * section , const char * key ,
2022-07-11 13:03:29 +00:00
const std : : string & runtime_var ,
float height /* = ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT */ ,
ImFont * font /* = g_large_font */ , ImFont * summary_font /* = g_medium_font */ )
{
if ( MenuButton ( title , runtime_var . c_str ( ) ) )
{
2022-08-25 15:26:55 +00:00
OpenFileSelector ( title , true ,
[ game_settings = IsEditingGameSettings ( bsi ) , section = std : : string ( section ) ,
key = std : : string ( key ) ] ( const std : : string & dir ) {
if ( dir . empty ( ) )
return ;
2021-01-30 11:37:49 +00:00
2022-08-25 15:26:55 +00:00
auto lock = Host : : GetSettingsLock ( ) ;
SettingsInterface * bsi = GetEditingSettingsInterface ( game_settings ) ;
std : : string relative_path ( Path : : MakeRelative ( dir , EmuFolders : : DataRoot ) ) ;
bsi - > SetStringValue ( section . c_str ( ) , key . c_str ( ) , relative_path . c_str ( ) ) ;
SetSettingsChanged ( bsi ) ;
2021-01-30 11:37:49 +00:00
2022-12-20 11:37:28 +00:00
Host : : RunOnCPUThread ( & EmuFolders : : Update ) ;
2022-10-23 04:09:54 +00:00
s_cover_image_map . clear ( ) ;
2021-01-30 11:37:49 +00:00
2022-08-25 15:26:55 +00:00
CloseFileSelector ( ) ;
} ) ;
2022-07-11 13:03:29 +00:00
}
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
void FullscreenUI : : StartAutomaticBinding ( u32 port )
{
std : : vector < std : : pair < std : : string , std : : string > > devices ( InputManager : : EnumerateDevices ( ) ) ;
if ( devices . empty ( ) )
{
2023-08-20 02:38:55 +00:00
ShowToast ( { } , FSUI_STR ( " Automatic mapping failed, no devices are available. " ) ) ;
2022-07-11 13:03:29 +00:00
return ;
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
std : : vector < std : : string > names ;
ImGuiFullscreen : : ChoiceDialogOptions options ;
options . reserve ( devices . size ( ) ) ;
names . reserve ( devices . size ( ) ) ;
for ( auto & [ name , display_name ] : devices )
{
names . push_back ( std : : move ( name ) ) ;
options . emplace_back ( std : : move ( display_name ) , false ) ;
}
2023-08-20 02:38:55 +00:00
OpenChoiceDialog ( FSUI_CSTR ( " Select Device " ) , false , std : : move ( options ) ,
2022-07-11 13:03:29 +00:00
[ port , names = std : : move ( names ) ] ( s32 index , const std : : string & title , bool checked ) {
if ( index < 0 )
return ;
const std : : string & name = names [ index ] ;
auto lock = Host : : GetSettingsLock ( ) ;
2022-09-17 05:51:05 +00:00
SettingsInterface * bsi = GetEditingSettingsInterface ( ) ;
const bool result =
InputManager : : MapController ( * bsi , port , InputManager : : GetGenericBindingMapping ( name ) ) ;
SetSettingsChanged ( bsi ) ;
2022-07-11 13:03:29 +00:00
// and the toast needs to happen on the UI thread.
2023-08-20 02:38:55 +00:00
ShowToast ( { } , result ? fmt : : format ( FSUI_FSTR ( " Automatic mapping completed for {}. " ) , name ) :
fmt : : format ( FSUI_FSTR ( " Automatic mapping failed for {}. " ) , name ) ) ;
2022-07-11 13:03:29 +00:00
CloseChoiceDialog ( ) ;
} ) ;
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
void FullscreenUI : : SwitchToSettings ( )
{
s_game_settings_entry . reset ( ) ;
s_game_settings_interface . reset ( ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
PopulateGraphicsAdapterList ( ) ;
2023-08-27 12:48:40 +00:00
PopulatePostProcessingChain ( GetEditingSettingsInterface ( ) ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
s_current_main_window = MainWindowType : : Settings ;
s_settings_page = SettingsPage : : Interface ;
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
void FullscreenUI : : SwitchToGameSettingsForSerial ( const std : : string_view & serial )
{
s_game_settings_entry . reset ( ) ;
s_game_settings_interface = std : : make_unique < INISettingsInterface > ( System : : GetGameSettingsPath ( serial ) ) ;
s_game_settings_interface - > Load ( ) ;
s_current_main_window = MainWindowType : : Settings ;
s_settings_page = SettingsPage : : Summary ;
QueueResetFocus ( ) ;
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
void FullscreenUI : : SwitchToGameSettings ( )
{
2023-05-15 13:38:37 +00:00
if ( System : : GetGameSerial ( ) . empty ( ) )
2022-07-11 13:03:29 +00:00
return ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
auto lock = GameList : : GetLock ( ) ;
2023-05-15 13:38:37 +00:00
const GameList : : Entry * entry = GameList : : GetEntryForPath ( System : : GetDiscPath ( ) . c_str ( ) ) ;
2022-07-11 13:03:29 +00:00
if ( ! entry )
{
2023-05-15 13:38:37 +00:00
SwitchToGameSettingsForSerial ( System : : GetGameSerial ( ) ) ;
2022-07-11 13:03:29 +00:00
return ;
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
SwitchToGameSettings ( entry ) ;
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
void FullscreenUI : : SwitchToGameSettingsForPath ( const std : : string & path )
{
auto lock = GameList : : GetLock ( ) ;
const GameList : : Entry * entry = GameList : : GetEntryForPath ( path . c_str ( ) ) ;
if ( entry )
SwitchToGameSettings ( entry ) ;
}
2021-05-23 03:35:10 +00:00
2022-07-11 13:03:29 +00:00
void FullscreenUI : : SwitchToGameSettings ( const GameList : : Entry * entry )
{
SwitchToGameSettingsForSerial ( entry - > serial ) ;
s_game_settings_entry = std : : make_unique < GameList : : Entry > ( * entry ) ;
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
void FullscreenUI : : PopulateGraphicsAdapterList ( )
{
2023-08-13 03:42:02 +00:00
GPUDevice : : AdapterAndModeList ml ( g_gpu_device - > GetAdapterAndModeList ( ) ) ;
2022-07-11 13:03:29 +00:00
s_graphics_adapter_list_cache = std : : move ( ml . adapter_names ) ;
s_fullscreen_mode_list_cache = std : : move ( ml . fullscreen_modes ) ;
2023-08-20 02:38:55 +00:00
s_fullscreen_mode_list_cache . insert ( s_fullscreen_mode_list_cache . begin ( ) , FSUI_STR ( " Borderless Fullscreen " ) ) ;
2022-07-11 13:03:29 +00:00
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
void FullscreenUI : : PopulateGameListDirectoryCache ( SettingsInterface * si )
{
s_game_list_directories_cache . clear ( ) ;
for ( std : : string & dir : si - > GetStringList ( " GameList " , " Paths " ) )
s_game_list_directories_cache . emplace_back ( std : : move ( dir ) , false ) ;
for ( std : : string & dir : si - > GetStringList ( " GameList " , " RecursivePaths " ) )
s_game_list_directories_cache . emplace_back ( std : : move ( dir ) , true ) ;
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DoCopyGameSettings ( )
{
2022-08-27 04:42:16 +00:00
if ( ! s_game_settings_interface )
return ;
Settings temp_settings ;
temp_settings . Load ( * GetEditingSettingsInterface ( false ) ) ;
2024-03-20 14:41:54 +00:00
temp_settings . Save ( * s_game_settings_interface , true ) ;
2022-08-27 04:42:16 +00:00
SetSettingsChanged ( s_game_settings_interface . get ( ) ) ;
2023-08-20 02:38:55 +00:00
ShowToast ( " Game Settings Copied " , fmt : : format ( FSUI_FSTR ( " Game settings initialized with global settings for '{}'. " ) ,
2022-08-27 04:42:16 +00:00
Path : : GetFileTitle ( s_game_settings_interface - > GetFileName ( ) ) ) ) ;
2022-07-11 13:03:29 +00:00
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DoClearGameSettings ( )
{
if ( ! s_game_settings_interface )
return ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
s_game_settings_interface - > Clear ( ) ;
if ( ! s_game_settings_interface - > GetFileName ( ) . empty ( ) )
FileSystem : : DeleteFile ( s_game_settings_interface - > GetFileName ( ) . c_str ( ) ) ;
2021-01-30 11:37:49 +00:00
2022-08-27 04:42:16 +00:00
SetSettingsChanged ( s_game_settings_interface . get ( ) ) ;
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
ShowToast ( " Game Settings Cleared " , fmt : : format ( FSUI_FSTR ( " Game settings have been cleared for '{}'. " ) ,
2022-07-11 13:03:29 +00:00
Path : : GetFileTitle ( s_game_settings_interface - > GetFileName ( ) ) ) ) ;
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DrawSettingsWindow ( )
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
ImVec2 heading_size = ImVec2 (
io . DisplaySize . x , LayoutScale ( LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY + LAYOUT_MENU_BUTTON_Y_PADDING * 2.0f + 2.0f ) ) ;
2021-01-30 11:37:49 +00:00
2022-10-13 14:14:21 +00:00
const float bg_alpha = System : : IsValid ( ) ? ( s_settings_page = = SettingsPage : : PostProcessing ? 0.50f : 0.90f ) : 1.0f ;
2021-05-15 17:25:28 +00:00
2022-09-17 05:51:05 +00:00
if ( BeginFullscreenWindow ( ImVec2 ( 0.0f , 0.0f ) , heading_size , " settings_category " ,
ImVec4 ( UIPrimaryColor . x , UIPrimaryColor . y , UIPrimaryColor . z , bg_alpha ) ) )
2022-07-11 13:03:29 +00:00
{
2022-09-03 03:39:59 +00:00
static constexpr float ITEM_WIDTH = 25.0f ;
2021-01-30 11:37:49 +00:00
2022-08-25 15:26:55 +00:00
static constexpr const char * global_icons [ ] = {
2024-03-02 05:50:46 +00:00
ICON_FA_TV , ICON_FA_DICE_D20 , ICON_FA_COGS , ICON_PF_MICROCHIP ,
ICON_PF_PICTURE , ICON_FA_MAGIC , ICON_PF_SOUND , ICON_PF_GAMEPAD_ALT ,
ICON_PF_KEYBOARD_ALT , ICON_PF_MEMORY_CARD , ICON_FA_TROPHY , ICON_FA_EXCLAMATION_TRIANGLE } ;
static constexpr const char * per_game_icons [ ] = { ICON_FA_PARAGRAPH , ICON_FA_HDD , ICON_FA_COGS ,
ICON_PF_PICTURE , ICON_PF_SOUND , ICON_PF_GAMEPAD_ALT ,
ICON_PF_MEMORY_CARD , ICON_FA_TROPHY , ICON_FA_EXCLAMATION_TRIANGLE } ;
2022-07-11 13:03:29 +00:00
static constexpr SettingsPage global_pages [ ] = {
2022-10-13 14:14:21 +00:00
SettingsPage : : Interface , SettingsPage : : Console , SettingsPage : : Emulation , SettingsPage : : BIOS ,
SettingsPage : : Display , SettingsPage : : PostProcessing , SettingsPage : : Audio , SettingsPage : : Controller ,
SettingsPage : : Hotkey , SettingsPage : : MemoryCards , SettingsPage : : Achievements , SettingsPage : : Advanced } ;
2022-07-11 13:03:29 +00:00
static constexpr SettingsPage per_game_pages [ ] = {
2022-08-25 15:26:55 +00:00
SettingsPage : : Summary , SettingsPage : : Console , SettingsPage : : Emulation ,
SettingsPage : : Display , SettingsPage : : Audio , SettingsPage : : Controller ,
SettingsPage : : MemoryCards , SettingsPage : : Achievements , SettingsPage : : Advanced } ;
2022-07-11 13:03:29 +00:00
static constexpr std : : array < const char * , static_cast < u32 > ( SettingsPage : : Count ) > titles = {
2023-08-20 02:38:55 +00:00
{ FSUI_NSTR ( " Summary " ) , FSUI_NSTR ( " Interface Settings " ) , FSUI_NSTR ( " Console Settings " ) ,
FSUI_NSTR ( " Emulation Settings " ) , FSUI_NSTR ( " BIOS Settings " ) , FSUI_NSTR ( " Controller Settings " ) ,
2024-03-02 09:08:38 +00:00
FSUI_NSTR ( " Hotkey Settings " ) , FSUI_NSTR ( " Memory Card Settings " ) , FSUI_NSTR ( " Graphics Settings " ) ,
2023-08-20 02:38:55 +00:00
FSUI_NSTR ( " Post-Processing Settings " ) , FSUI_NSTR ( " Audio Settings " ) , FSUI_NSTR ( " Achievements Settings " ) ,
FSUI_NSTR ( " Advanced Settings " ) } } ;
2021-01-30 11:37:49 +00:00
2022-08-25 15:26:55 +00:00
const bool game_settings = IsEditingGameSettings ( GetEditingSettingsInterface ( ) ) ;
2022-07-11 13:03:29 +00:00
const u32 count =
game_settings ? static_cast < u32 > ( std : : size ( per_game_pages ) ) : static_cast < u32 > ( std : : size ( global_pages ) ) ;
const char * const * icons = game_settings ? per_game_icons : global_icons ;
const SettingsPage * pages = game_settings ? per_game_pages : global_pages ;
u32 index = 0 ;
for ( u32 i = 0 ; i < count ; i + + )
{
if ( pages [ i ] = = s_settings_page )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
index = i ;
break ;
}
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
BeginNavBar ( ) ;
2021-01-30 11:37:49 +00:00
2022-09-17 05:51:05 +00:00
if ( ! ImGui : : IsPopupOpen ( 0u , ImGuiPopupFlags_AnyPopup ) )
2022-07-11 13:03:29 +00:00
{
2024-04-09 10:04:45 +00:00
if ( ImGui : : IsKeyPressed ( ImGuiKey_GamepadDpadLeft , true ) | |
ImGui : : IsKeyPressed ( ImGuiKey_NavGamepadTweakSlow , true ) | | ImGui : : IsKeyPressed ( ImGuiKey_LeftArrow , true ) )
2022-09-17 05:51:05 +00:00
{
index = ( index = = 0 ) ? ( count - 1 ) : ( index - 1 ) ;
s_settings_page = pages [ index ] ;
2024-04-09 10:04:45 +00:00
QueueResetFocus ( ) ;
2022-09-17 05:51:05 +00:00
}
2024-04-09 10:04:45 +00:00
else if ( ImGui : : IsKeyPressed ( ImGuiKey_GamepadDpadRight , true ) | |
ImGui : : IsKeyPressed ( ImGuiKey_NavGamepadTweakFast , true ) | |
ImGui : : IsKeyPressed ( ImGuiKey_RightArrow , true ) )
2022-09-17 05:51:05 +00:00
{
index = ( index + 1 ) % count ;
s_settings_page = pages [ index ] ;
2024-04-09 10:04:45 +00:00
QueueResetFocus ( ) ;
2022-09-17 05:51:05 +00:00
}
2022-07-11 13:03:29 +00:00
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
if ( NavButton ( ICON_FA_BACKWARD , true , true ) )
2023-09-18 12:29:47 +00:00
ReturnToPreviousWindow ( ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
if ( s_game_settings_entry )
2022-09-03 03:39:59 +00:00
NavTitle ( s_game_settings_entry - > title . c_str ( ) ) ;
2022-07-11 13:03:29 +00:00
else
2023-08-20 02:38:55 +00:00
NavTitle ( Host : : TranslateToCString ( TR_CONTEXT , titles [ static_cast < u32 > ( pages [ index ] ) ] ) ) ;
2022-07-11 13:03:29 +00:00
RightAlignNavButtons ( count , ITEM_WIDTH , LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ) ;
for ( u32 i = 0 ; i < count ; i + + )
{
if ( NavButton ( icons [ i ] , i = = index , true , ITEM_WIDTH , LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ) )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
s_settings_page = pages [ i ] ;
}
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
EndNavBar ( ) ;
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
EndFullscreenWindow ( ) ;
2021-01-30 11:37:49 +00:00
2024-04-09 10:04:45 +00:00
// we have to do this here, because otherwise it uses target, and jumps a frame later.
if ( IsFocusResetQueued ( ) )
ImGui : : SetNextWindowScroll ( ImVec2 ( 0.0f , 0.0f ) ) ;
if ( BeginFullscreenWindow (
ImVec2 ( 0.0f , heading_size . y ) ,
ImVec2 ( io . DisplaySize . x , io . DisplaySize . y - heading_size . y - LayoutScale ( LAYOUT_FOOTER_HEIGHT ) ) ,
TinyString : : from_format ( " settings_page_{} " , static_cast < u32 > ( s_settings_page ) ) . c_str ( ) ,
ImVec4 ( UIBackgroundColor . x , UIBackgroundColor . y , UIBackgroundColor . z , bg_alpha ) ) )
2022-07-11 13:03:29 +00:00
{
ResetFocusHere ( ) ;
2021-01-30 11:37:49 +00:00
2024-04-09 10:04:45 +00:00
if ( ImGui : : IsWindowFocused ( ) & & WantsToCloseMenu ( ) )
ReturnToPreviousWindow ( ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
auto lock = Host : : GetSettingsLock ( ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
switch ( s_settings_page )
{
case SettingsPage : : Summary :
DrawSummarySettingsPage ( ) ;
break ;
2021-03-27 05:18:23 +00:00
2022-07-11 13:03:29 +00:00
case SettingsPage : : Interface :
DrawInterfaceSettingsPage ( ) ;
break ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
case SettingsPage : : BIOS :
DrawBIOSSettingsPage ( ) ;
break ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
case SettingsPage : : Emulation :
DrawEmulationSettingsPage ( ) ;
break ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
case SettingsPage : : Console :
DrawConsoleSettingsPage ( ) ;
break ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
case SettingsPage : : Display :
DrawDisplaySettingsPage ( ) ;
break ;
2021-01-30 11:37:49 +00:00
2022-10-13 14:14:21 +00:00
case SettingsPage : : PostProcessing :
DrawPostProcessingSettingsPage ( ) ;
break ;
2022-07-11 13:03:29 +00:00
case SettingsPage : : Audio :
DrawAudioSettingsPage ( ) ;
break ;
2021-02-13 14:33:46 +00:00
2022-07-11 13:03:29 +00:00
case SettingsPage : : MemoryCards :
DrawMemoryCardSettingsPage ( ) ;
break ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
case SettingsPage : : Controller :
DrawControllerSettingsPage ( ) ;
break ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
case SettingsPage : : Hotkey :
DrawHotkeySettingsPage ( ) ;
break ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
case SettingsPage : : Achievements :
DrawAchievementsSettingsPage ( ) ;
break ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
case SettingsPage : : Advanced :
DrawAdvancedSettingsPage ( ) ;
break ;
2021-05-19 03:43:49 +00:00
2022-07-11 13:03:29 +00:00
default :
break ;
}
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
EndFullscreenWindow ( ) ;
2024-04-09 10:04:45 +00:00
if ( IsGamepadInputSource ( ) )
{
SetFullscreenFooterText ( std : : array { std : : make_pair ( ICON_PF_XBOX_DPAD_LEFT_RIGHT , FSUI_VSTR ( " Change Page " ) ) ,
std : : make_pair ( ICON_PF_XBOX_DPAD_UP_DOWN , FSUI_VSTR ( " Navigate " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_A , FSUI_VSTR ( " Select " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_B , FSUI_VSTR ( " Back " ) ) } ) ;
}
else
{
SetFullscreenFooterText ( std : : array { std : : make_pair ( ICON_PF_ARROW_LEFT ICON_PF_ARROW_RIGHT , FSUI_VSTR ( " Change Page " ) ) ,
std : : make_pair ( ICON_PF_ARROW_UP ICON_PF_ARROW_DOWN , FSUI_VSTR ( " Navigate " ) ) ,
std : : make_pair ( ICON_PF_ENTER , FSUI_VSTR ( " Select " ) ) ,
std : : make_pair ( ICON_PF_ESC , FSUI_VSTR ( " Back " ) ) } ) ;
}
2022-07-11 13:03:29 +00:00
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DrawSummarySettingsPage ( )
{
BeginMenuButtons ( ) ;
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " Details " ) ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
if ( s_game_settings_entry )
{
2023-08-20 02:38:55 +00:00
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_WINDOW_MAXIMIZE , " Title " ) , s_game_settings_entry - > title . c_str ( ) , true ) )
CopyTextToClipboard ( FSUI_STR ( " Game title copied to clipboard. " ) , s_game_settings_entry - > title ) ;
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_PAGER , " Serial " ) , s_game_settings_entry - > serial . c_str ( ) , true ) )
CopyTextToClipboard ( FSUI_STR ( " Game serial copied to clipboard. " ) , s_game_settings_entry - > serial ) ;
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_COMPACT_DISC , " Type " ) ,
GameList : : GetEntryTypeDisplayName ( s_game_settings_entry - > type ) , true ) )
2022-08-25 15:26:55 +00:00
{
2023-08-20 02:38:55 +00:00
CopyTextToClipboard ( FSUI_STR ( " Game type copied to clipboard. " ) ,
2022-08-25 15:26:55 +00:00
GameList : : GetEntryTypeDisplayName ( s_game_settings_entry - > type ) ) ;
}
2023-08-20 02:38:55 +00:00
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_BOX , " Region " ) ,
Settings : : GetDiscRegionDisplayName ( s_game_settings_entry - > region ) , true ) )
2022-08-25 15:26:55 +00:00
{
2023-08-20 02:38:55 +00:00
CopyTextToClipboard ( FSUI_STR ( " Game region copied to clipboard. " ) ,
2022-08-25 15:26:55 +00:00
Settings : : GetDiscRegionDisplayName ( s_game_settings_entry - > region ) ) ;
}
2023-08-20 02:38:55 +00:00
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_STAR , " Compatibility Rating " ) ,
2022-08-25 15:26:55 +00:00
GameDatabase : : GetCompatibilityRatingDisplayName ( s_game_settings_entry - > compatibility ) , true ) )
{
2023-08-20 02:38:55 +00:00
CopyTextToClipboard ( FSUI_STR ( " Game compatibility rating copied to clipboard. " ) ,
2022-08-25 15:26:55 +00:00
GameDatabase : : GetCompatibilityRatingDisplayName ( s_game_settings_entry - > compatibility ) ) ;
}
2023-08-20 02:38:55 +00:00
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_FOLDER_OPEN , " Path " ) , s_game_settings_entry - > path . c_str ( ) , true ) )
2022-08-25 15:26:55 +00:00
{
2023-08-20 02:38:55 +00:00
CopyTextToClipboard ( FSUI_STR ( " Game path copied to clipboard. " ) , s_game_settings_entry - > path ) ;
2022-08-25 15:26:55 +00:00
}
2022-07-11 13:03:29 +00:00
}
else
{
2023-08-20 02:38:55 +00:00
MenuButton ( FSUI_ICONSTR ( ICON_FA_BAN , " Details unavailable for game not scanned in game list. " ) , " " ) ;
2022-07-11 13:03:29 +00:00
}
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " Options " ) ) ;
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_COPY , " Copy Settings " ) ,
FSUI_CSTR ( " Copies the current global settings to this game. " ) ) )
{
2022-07-11 13:03:29 +00:00
DoCopyGameSettings ( ) ;
2023-08-20 02:38:55 +00:00
}
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_TRASH , " Clear Settings " ) , FSUI_CSTR ( " Clears all settings set for this game. " ) ) )
{
2022-07-11 13:03:29 +00:00
DoClearGameSettings ( ) ;
2023-08-20 02:38:55 +00:00
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
EndMenuButtons ( ) ;
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DrawInterfaceSettingsPage ( )
{
2022-08-25 15:26:55 +00:00
SettingsInterface * bsi = GetEditingSettingsInterface ( ) ;
2022-07-11 13:03:29 +00:00
BeginMenuButtons ( ) ;
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " Behavior " ) ) ;
2022-07-11 13:03:29 +00:00
2023-08-20 02:38:55 +00:00
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_PAUSE , " Pause On Start " ) ,
FSUI_CSTR ( " Pauses the emulator when a game is started. " ) , " Main " , " StartPaused " , false ) ;
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_VIDEO , " Pause On Focus Loss " ) ,
FSUI_CSTR ( " Pauses the emulator when you minimize the window or switch to another "
" application, and unpauses when you switch back. " ) ,
2022-07-11 13:03:29 +00:00
" Main " , " PauseOnFocusLoss " , false ) ;
2023-08-20 02:38:55 +00:00
DrawToggleSetting (
bsi , FSUI_ICONSTR ( ICON_FA_POWER_OFF , " Confirm Power Off " ) ,
FSUI_CSTR ( " Determines whether a prompt will be displayed to confirm shutting down the emulator/game "
" when the hotkey is pressed. " ) ,
" Main " , " ConfirmPowerOff " , true ) ;
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_SAVE , " Save State On Exit " ) ,
FSUI_CSTR ( " Automatically saves the emulator state when powering down or exiting. You can then "
" resume directly from where you left off next time. " ) ,
2022-07-11 13:03:29 +00:00
" Main " , " SaveStateOnExit " , true ) ;
2024-02-05 13:34:34 +00:00
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_WINDOW_MAXIMIZE , " Start Fullscreen " ) ,
2023-08-20 02:38:55 +00:00
FSUI_CSTR ( " Automatically switches to fullscreen mode when the program is started. " ) , " Main " ,
" StartFullscreen " , false ) ;
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_MOUSE , " Double-Click Toggles Fullscreen " ) ,
FSUI_CSTR ( " Switches between full screen and windowed when the window is double-clicked. " ) , " Main " ,
2022-09-03 03:39:59 +00:00
" DoubleClickTogglesFullscreen " , true ) ;
2023-09-04 12:45:44 +00:00
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_MOUSE_POINTER , " Hide Cursor In Fullscreen " ) ,
2023-08-20 02:38:55 +00:00
FSUI_CSTR ( " Hides the mouse pointer/cursor when the emulator is in fullscreen mode. " ) , " Main " ,
2022-07-11 13:03:29 +00:00
" HideCursorInFullscreen " , true ) ;
2023-08-20 02:38:55 +00:00
DrawToggleSetting (
bsi , FSUI_ICONSTR ( ICON_FA_MAGIC , " Inhibit Screensaver " ) ,
FSUI_CSTR ( " Prevents the screen saver from activating and the host from sleeping while emulation is running. " ) ,
" Main " , " InhibitScreensaver " , true ) ;
DrawToggleSetting (
bsi , FSUI_ICONSTR ( ICON_FA_COGS , " Apply Per-Game Settings " ) ,
FSUI_CSTR ( " When enabled, per-game settings will be applied, and incompatible enhancements will be disabled. " ) ,
" Main " , " ApplyGameSettings " , true ) ;
if ( DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_PAINT_BRUSH , " Use Light Theme " ) ,
FSUI_CSTR ( " Uses a light coloured theme instead of the default dark theme. " ) , " Main " ,
2022-09-17 05:51:05 +00:00
" UseLightFullscreenUITheme " , false ) )
{
ImGuiFullscreen : : SetTheme ( bsi - > GetBoolValue ( " Main " , " UseLightFullscreenUITheme " , false ) ) ;
}
2021-01-30 11:37:49 +00:00
2023-11-29 10:26:36 +00:00
{
// Have to do this the annoying way, because it's host-derived.
const auto language_list = Host : : GetAvailableLanguageList ( ) ;
2024-04-07 10:43:13 +00:00
TinyString current_language = bsi - > GetTinyStringValue ( " Main " , " Language " , " " ) ;
2023-11-29 10:26:36 +00:00
const char * current_language_name = " Unknown " ;
for ( const auto & [ language , code ] : language_list )
{
if ( current_language = = code )
current_language_name = language ;
}
if ( MenuButtonWithValue ( FSUI_ICONSTR ( ICON_FA_LANGUAGE , " UI Language " ) ,
FSUI_CSTR ( " Chooses the language used for UI elements. " ) , current_language_name ) )
{
ImGuiFullscreen : : ChoiceDialogOptions options ;
for ( const auto & [ language , code ] : language_list )
options . emplace_back ( fmt : : format ( " {} [{}] " , language , code ) , ( current_language = = code ) ) ;
OpenChoiceDialog ( FSUI_ICONSTR ( ICON_FA_LANGUAGE , " UI Language " ) , false , std : : move ( options ) ,
[ language_list ] ( s32 index , const std : : string & title , bool checked ) {
if ( static_cast < u32 > ( index ) > = language_list . size ( ) )
return ;
Host : : RunOnCPUThread (
[ language = language_list [ index ] . second ] ( ) { Host : : ChangeLanguage ( language ) ; } ) ;
2024-04-11 02:52:56 +00:00
ImGuiFullscreen : : CloseChoiceDialog ( ) ;
2023-11-29 10:26:36 +00:00
} ) ;
}
}
2023-09-17 02:28:11 +00:00
# ifdef ENABLE_DISCORD_PRESENCE
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " Integration " ) ) ;
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_CHARGING_STATION , " Enable Discord Presence " ) ,
2023-11-28 16:08:19 +00:00
FSUI_CSTR ( " Shows the game you are currently playing as part of your profile in Discord. " ) , " Main " ,
2022-07-11 13:03:29 +00:00
" EnableDiscordPresence " , false ) ;
2022-04-18 05:09:21 +00:00
# endif
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " On-Screen Display " ) ) ;
DrawIntSpinBoxSetting ( bsi , FSUI_ICONSTR ( ICON_FA_SEARCH , " OSD Scale " ) ,
FSUI_CSTR ( " Determines how large the on-screen messages and monitor are. " ) , " Display " ,
" OSDScale " , 100 , 25 , 500 , 1 , " %d%% " ) ;
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_LIST , " Show OSD Messages " ) ,
FSUI_CSTR ( " Shows on-screen-display messages when events occur. " ) , " Display " , " ShowOSDMessages " ,
true ) ;
2022-08-25 15:26:55 +00:00
DrawToggleSetting (
2023-08-20 02:38:55 +00:00
bsi , FSUI_ICONSTR ( ICON_FA_CLOCK , " Show Speed " ) ,
FSUI_CSTR (
" Shows the current emulation speed of the system in the top-right corner of the display as a percentage. " ) ,
2022-08-25 15:26:55 +00:00
" Display " , " ShowSpeed " , false ) ;
2023-08-20 02:38:55 +00:00
DrawToggleSetting (
bsi , FSUI_ICONSTR ( ICON_FA_RULER , " Show FPS " ) ,
FSUI_CSTR ( " Shows the number of frames (or v-syncs) displayed per second by the system in the top-right "
" corner of the display. " ) ,
" Display " , " ShowFPS " , false ) ;
2024-01-21 09:37:29 +00:00
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_BARS , " Show GPU Statistics " ) ,
FSUI_CSTR ( " Shows information about the emulated GPU in the top-right corner of the display. " ) ,
" Display " , " ShowGPUStatistics " , false ) ;
2024-04-14 04:53:53 +00:00
DrawToggleSetting (
bsi , FSUI_ICONSTR ( ICON_FA_STOPWATCH , " Show Latency Statistics " ) ,
FSUI_CSTR ( " Shows information about input and audio latency in the top-right corner of the display. " ) , " Display " ,
" ShowLatencyStatistics " , false ) ;
2023-08-20 02:38:55 +00:00
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_BATTERY_HALF , " Show CPU Usage " ) ,
FSUI_CSTR ( " Shows the host's CPU usage based on threads in the top-right corner of the display. " ) ,
" Display " , " ShowCPU " , false ) ;
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_SPINNER , " Show GPU Usage " ) ,
FSUI_CSTR ( " Shows the host's GPU usage in the top-right corner of the display. " ) , " Display " ,
" ShowGPU " , false ) ;
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_RULER_HORIZONTAL , " Show Frame Times " ) ,
FSUI_CSTR ( " Shows a visual history of frame times in the upper-left corner of the display. " ) ,
" Display " , " ShowFrameTimes " , false ) ;
DrawToggleSetting (
bsi , FSUI_ICONSTR ( ICON_FA_RULER_VERTICAL , " Show Resolution " ) ,
FSUI_CSTR ( " Shows the current rendering resolution of the system in the top-right corner of the display. " ) ,
" Display " , " ShowResolution " , false ) ;
DrawToggleSetting (
bsi , FSUI_ICONSTR ( ICON_FA_GAMEPAD , " Show Controller Input " ) ,
FSUI_CSTR ( " Shows the current controller state of the system in the bottom-left corner of the display. " ) , " Display " ,
" ShowInputs " , false ) ;
2022-08-25 15:26:55 +00:00
2022-07-11 13:03:29 +00:00
EndMenuButtons ( ) ;
}
2021-02-26 14:44:53 +00:00
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DrawBIOSSettingsPage ( )
{
2023-10-02 03:33:33 +00:00
static constexpr const std : : array config_keys = { " " , " PathNTSCJ " , " PathNTSCU " , " PathPAL " } ;
2021-02-26 14:44:53 +00:00
2022-08-25 15:26:55 +00:00
SettingsInterface * bsi = GetEditingSettingsInterface ( ) ;
const bool game_settings = IsEditingGameSettings ( bsi ) ;
2022-07-11 13:03:29 +00:00
BeginMenuButtons ( ) ;
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " BIOS Selection " ) ) ;
2022-07-11 13:03:29 +00:00
for ( u32 i = 0 ; i < static_cast < u32 > ( ConsoleRegion : : Count ) ; i + + )
{
const ConsoleRegion region = static_cast < ConsoleRegion > ( i ) ;
if ( region = = ConsoleRegion : : Auto )
continue ;
TinyString title ;
2023-12-13 11:06:15 +00:00
title . format ( FSUI_FSTR ( " BIOS for {} " ) , Settings : : GetConsoleRegionDisplayName ( region ) ) ;
2022-07-11 13:03:29 +00:00
2024-04-07 10:43:13 +00:00
const std : : optional < SmallString > filename ( bsi - > GetOptionalSmallStringValue (
2022-08-25 15:26:55 +00:00
" BIOS " , config_keys [ i ] , game_settings ? std : : nullopt : std : : optional < const char * > ( " " ) ) ) ;
2022-07-11 13:03:29 +00:00
if ( MenuButtonWithValue ( title ,
2023-12-13 11:06:15 +00:00
SmallString : : from_format ( FSUI_FSTR ( " BIOS to use when emulating {} consoles. " ) ,
2023-12-14 06:07:57 +00:00
Settings : : GetConsoleRegionDisplayName ( region ) ) ,
2023-08-20 02:38:55 +00:00
filename . has_value ( ) ? ( filename - > empty ( ) ? FSUI_CSTR ( " Auto-Detect " ) : filename - > c_str ( ) ) :
FSUI_CSTR ( " Use Global Setting " ) ) )
2022-07-11 13:03:29 +00:00
{
ImGuiFullscreen : : ChoiceDialogOptions options ;
2022-08-25 15:26:55 +00:00
auto images = BIOS : : FindBIOSImagesInDirectory ( EmuFolders : : Bios . c_str ( ) ) ;
options . reserve ( images . size ( ) + 2 ) ;
if ( IsEditingGameSettings ( bsi ) )
2023-08-20 02:38:55 +00:00
options . emplace_back ( FSUI_STR ( " Use Global Setting " ) , ! filename . has_value ( ) ) ;
options . emplace_back ( FSUI_STR ( " Auto-Detect " ) , filename . has_value ( ) & & filename - > empty ( ) ) ;
2022-07-11 13:03:29 +00:00
for ( auto & [ path , info ] : images )
2021-01-30 11:37:49 +00:00
{
2022-08-25 15:26:55 +00:00
const bool selected = ( filename . has_value ( ) & & filename . value ( ) = = path ) ;
2022-07-11 13:03:29 +00:00
options . emplace_back ( std : : move ( path ) , selected ) ;
}
2021-01-30 11:37:49 +00:00
2022-08-25 15:26:55 +00:00
OpenChoiceDialog ( title , false , std : : move ( options ) ,
[ game_settings , i ] ( s32 index , const std : : string & path , bool checked ) {
if ( index > = 0 )
{
auto lock = Host : : GetSettingsLock ( ) ;
SettingsInterface * bsi = GetEditingSettingsInterface ( game_settings ) ;
if ( game_settings & & index = = 0 )
bsi - > DeleteValue ( " BIOS " , config_keys [ i ] ) ;
else
bsi - > SetStringValue ( " BIOS " , config_keys [ i ] , path . c_str ( ) ) ;
SetSettingsChanged ( bsi ) ;
}
CloseChoiceDialog ( ) ;
} ) ;
2022-07-11 13:03:29 +00:00
}
}
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
DrawFolderSetting ( bsi , FSUI_CSTR ( " BIOS Directory " ) , " BIOS " , " SearchDirectory " , EmuFolders : : Bios ) ;
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " Patches " ) ) ;
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
DrawToggleSetting ( bsi , FSUI_CSTR ( " Enable Fast Boot " ) ,
FSUI_CSTR ( " Patches the BIOS to skip the boot animation. Safe to enable. " ) , " BIOS " , " PatchFastBoot " ,
Settings : : DEFAULT_FAST_BOOT_VALUE ) ;
2023-08-29 11:18:04 +00:00
DrawToggleSetting ( bsi , FSUI_CSTR ( " Enable TTY Logging " ) ,
2023-09-02 12:26:03 +00:00
FSUI_CSTR ( " Logs BIOS calls to printf(). Not all games contain debugging messages. " ) , " BIOS " ,
" TTYLogging " , false ) ;
2022-07-11 13:03:29 +00:00
EndMenuButtons ( ) ;
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DrawConsoleSettingsPage ( )
{
2023-10-02 03:33:33 +00:00
static constexpr const std : : array cdrom_read_speeds = {
2023-08-20 02:38:55 +00:00
FSUI_NSTR ( " None (Double Speed) " ) , FSUI_NSTR ( " 2x (Quad Speed) " ) , FSUI_NSTR ( " 3x (6x Speed) " ) ,
2023-10-02 03:33:33 +00:00
FSUI_NSTR ( " 4x (8x Speed) " ) , FSUI_NSTR ( " 5x (10x Speed) " ) , FSUI_NSTR ( " 6x (12x Speed) " ) ,
FSUI_NSTR ( " 7x (14x Speed) " ) , FSUI_NSTR ( " 8x (16x Speed) " ) , FSUI_NSTR ( " 9x (18x Speed) " ) ,
FSUI_NSTR ( " 10x (20x Speed) " ) ,
} ;
2021-01-30 11:37:49 +00:00
2023-10-02 03:33:33 +00:00
static constexpr const std : : array cdrom_seek_speeds = {
FSUI_NSTR ( " Infinite/Instantaneous " ) ,
FSUI_NSTR ( " None (Normal Speed) " ) ,
FSUI_NSTR ( " 2x " ) ,
FSUI_NSTR ( " 3x " ) ,
FSUI_NSTR ( " 4x " ) ,
FSUI_NSTR ( " 5x " ) ,
FSUI_NSTR ( " 6x " ) ,
FSUI_NSTR ( " 7x " ) ,
FSUI_NSTR ( " 8x " ) ,
FSUI_NSTR ( " 9x " ) ,
FSUI_NSTR ( " 10x " ) ,
} ;
2021-01-30 11:37:49 +00:00
2022-08-25 15:26:55 +00:00
SettingsInterface * bsi = GetEditingSettingsInterface ( ) ;
2022-07-11 13:03:29 +00:00
BeginMenuButtons ( ) ;
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " Console Settings " ) ) ;
2022-07-11 13:03:29 +00:00
2024-03-03 03:43:04 +00:00
DrawEnumSetting ( bsi , FSUI_ICONSTR ( ICON_FA_GLOBE , " Region " ) , FSUI_CSTR ( " Determines the emulated hardware type. " ) ,
" Console " , " Region " , Settings : : DEFAULT_CONSOLE_REGION , & Settings : : ParseConsoleRegionName ,
& Settings : : GetConsoleRegionName , & Settings : : GetConsoleRegionDisplayName , ConsoleRegion : : Count ) ;
2023-08-20 02:38:55 +00:00
DrawToggleSetting (
2024-03-03 03:43:04 +00:00
bsi , FSUI_ICONSTR ( ICON_FA_MEMORY , " Enable 8MB RAM " ) ,
2023-08-20 02:38:55 +00:00
FSUI_CSTR ( " Enables an additional 6MB of RAM to obtain a total of 2+6 = 8MB, usually present on dev consoles. " ) ,
" Console " , " Enable8MBRAM " , false ) ;
2024-03-03 03:43:04 +00:00
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_MAGIC , " Disable All Enhancements " ) ,
FSUI_CSTR ( " Temporarily disables all enhancements, useful when testing. " ) , " Main " ,
" DisableAllEnhancements " , false ) ;
DrawToggleSetting (
bsi , FSUI_ICONSTR ( ICON_FA_FROWN , " Enable Cheats " ) ,
FSUI_CSTR ( " Automatically loads and applies cheats on game start. Cheats can break games and saves. " ) , " Console " ,
" EnableCheats " , false ) ;
2022-07-11 13:03:29 +00:00
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " CPU Emulation " ) ) ;
2022-07-11 13:03:29 +00:00
2024-03-03 03:43:04 +00:00
DrawEnumSetting ( bsi , FSUI_ICONSTR ( ICON_FA_BOLT , " Execution Mode " ) ,
FSUI_CSTR ( " Determines how the emulated CPU executes instructions. " ) , " CPU " , " ExecutionMode " ,
Settings : : DEFAULT_CPU_EXECUTION_MODE , & Settings : : ParseCPUExecutionMode ,
2023-08-20 02:38:55 +00:00
& Settings : : GetCPUExecutionModeName , & Settings : : GetCPUExecutionModeDisplayName ,
CPUExecutionMode : : Count ) ;
2022-07-11 13:03:29 +00:00
2024-03-03 03:43:04 +00:00
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_TACHOMETER_ALT , " Enable Overclocking " ) ,
2023-08-20 02:38:55 +00:00
FSUI_CSTR ( " When this option is chosen, the clock speed set below will be used. " ) , " CPU " ,
" OverclockEnable " , false ) ;
2022-07-11 13:03:29 +00:00
2022-08-29 09:19:50 +00:00
const bool oc_enable = GetEffectiveBoolSetting ( bsi , " CPU " , " OverclockEnable " , false ) ;
if ( oc_enable )
2022-07-11 13:03:29 +00:00
{
2022-08-29 09:19:50 +00:00
u32 oc_numerator = GetEffectiveUIntSetting ( bsi , " CPU " , " OverclockNumerator " , 1 ) ;
u32 oc_denominator = GetEffectiveUIntSetting ( bsi , " CPU " , " OverclockDenominator " , 1 ) ;
s32 oc_percent = static_cast < s32 > ( Settings : : CPUOverclockFractionToPercent ( oc_numerator , oc_denominator ) ) ;
2023-08-20 02:38:55 +00:00
if ( RangeButton ( FSUI_CSTR ( " Overclocking Percentage " ) ,
FSUI_CSTR ( " Selects the percentage of the normal clock speed the emulated hardware will run at. " ) ,
& oc_percent , 10 , 1000 , 10 , " %d%% " ) )
2022-08-29 09:19:50 +00:00
{
Settings : : CPUOverclockPercentToFraction ( oc_percent , & oc_numerator , & oc_denominator ) ;
bsi - > SetUIntValue ( " CPU " , " OverclockNumerator " , oc_numerator ) ;
bsi - > SetUIntValue ( " CPU " , " OverclockDenominator " , oc_denominator ) ;
SetSettingsChanged ( bsi ) ;
}
2021-01-30 11:37:49 +00:00
}
2022-08-29 09:19:50 +00:00
2024-03-03 03:43:04 +00:00
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_MICROCHIP , " Enable Recompiler ICache " ) ,
2023-08-20 02:38:55 +00:00
FSUI_CSTR ( " Makes games run closer to their console framerate, at a small cost to performance. " ) ,
" CPU " , " RecompilerICache " , false ) ;
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " CD-ROM Emulation " ) ) ;
2022-07-11 13:03:29 +00:00
DrawIntListSetting (
2024-03-03 03:43:04 +00:00
bsi , FSUI_ICONSTR ( ICON_FA_COMPACT_DISC , " Read Speedup " ) ,
2023-08-20 02:38:55 +00:00
FSUI_CSTR (
" Speeds up CD-ROM reads by the specified factor. May improve loading speeds in some games, and break others. " ) ,
2023-09-03 03:20:38 +00:00
" CDROM " , " ReadSpeedup " , 1 , cdrom_read_speeds . data ( ) , cdrom_read_speeds . size ( ) , true , 1 ) ;
2022-07-11 13:03:29 +00:00
DrawIntListSetting (
2024-03-03 03:43:04 +00:00
bsi , FSUI_ICONSTR ( ICON_FA_SEARCH , " Seek Speedup " ) ,
2023-08-20 02:38:55 +00:00
FSUI_CSTR (
" Speeds up CD-ROM seeks by the specified factor. May improve loading speeds in some games, and break others. " ) ,
2023-09-03 03:20:38 +00:00
" CDROM " , " SeekSpeedup " , 1 , cdrom_seek_speeds . data ( ) , cdrom_seek_speeds . size ( ) , true ) ;
2022-07-11 13:03:29 +00:00
DrawIntRangeSetting (
2024-03-03 03:43:04 +00:00
bsi , FSUI_ICONSTR ( ICON_FA_FAST_FORWARD , " Readahead Sectors " ) ,
2023-08-20 02:38:55 +00:00
FSUI_CSTR ( " Reduces hitches in emulation by reading/decompressing CD data asynchronously on a worker thread. " ) ,
2024-03-20 12:48:23 +00:00
" CDROM " , " ReadaheadSectors " , Settings : : DEFAULT_CDROM_READAHEAD_SECTORS , 0 , 32 , FSUI_CSTR ( " %d sectors " ) ) ;
2022-07-11 13:03:29 +00:00
DrawToggleSetting (
2024-03-03 03:43:04 +00:00
bsi , FSUI_ICONSTR ( ICON_FA_DOWNLOAD , " Preload Images to RAM " ) ,
2023-08-20 02:38:55 +00:00
FSUI_CSTR ( " Loads the game image into RAM. Useful for network paths that may become unreliable during gameplay. " ) ,
" CDROM " , " LoadImageToRAM " , false ) ;
2022-07-11 13:03:29 +00:00
DrawToggleSetting (
2024-03-03 03:43:04 +00:00
bsi , FSUI_ICONSTR ( ICON_FA_VEST_PATCHES , " Apply Image Patches " ) ,
2023-08-20 02:38:55 +00:00
FSUI_CSTR ( " Automatically applies patches to disc images when they are present, currently only PPF is supported. " ) ,
" CDROM " , " LoadImagePatches " , false ) ;
2022-07-11 13:03:29 +00:00
EndMenuButtons ( ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DrawEmulationSettingsPage ( )
2021-01-30 11:37:49 +00:00
{
2023-10-02 03:33:33 +00:00
static constexpr const std : : array emulation_speed_values = {
0.0f , 0.1f , 0.2f , 0.3f , 0.4f , 0.5f , 0.6f , 0.7f , 0.8f , 0.9f , 1.0f , 1.25f , 1.5f ,
1.75f , 2.0f , 2.5f , 3.0f , 3.5f , 4.0f , 4.5f , 5.0f , 6.0f , 7.0f , 8.0f , 9.0f , 10.0f ,
} ;
static constexpr const std : : array emulation_speed_titles = {
FSUI_NSTR ( " Unlimited " ) ,
" 10% [6 FPS (NTSC) / 5 FPS (PAL)] " ,
FSUI_NSTR ( " 20% [12 FPS (NTSC) / 10 FPS (PAL)] " ) ,
FSUI_NSTR ( " 30% [18 FPS (NTSC) / 15 FPS (PAL)] " ) ,
FSUI_NSTR ( " 40% [24 FPS (NTSC) / 20 FPS (PAL)] " ) ,
FSUI_NSTR ( " 50% [30 FPS (NTSC) / 25 FPS (PAL)] " ) ,
FSUI_NSTR ( " 60% [36 FPS (NTSC) / 30 FPS (PAL)] " ) ,
FSUI_NSTR ( " 70% [42 FPS (NTSC) / 35 FPS (PAL)] " ) ,
FSUI_NSTR ( " 80% [48 FPS (NTSC) / 40 FPS (PAL)] " ) ,
FSUI_NSTR ( " 90% [54 FPS (NTSC) / 45 FPS (PAL)] " ) ,
FSUI_NSTR ( " 100% [60 FPS (NTSC) / 50 FPS (PAL)] " ) ,
FSUI_NSTR ( " 125% [75 FPS (NTSC) / 62 FPS (PAL)] " ) ,
FSUI_NSTR ( " 150% [90 FPS (NTSC) / 75 FPS (PAL)] " ) ,
FSUI_NSTR ( " 175% [105 FPS (NTSC) / 87 FPS (PAL)] " ) ,
FSUI_NSTR ( " 200% [120 FPS (NTSC) / 100 FPS (PAL)] " ) ,
FSUI_NSTR ( " 250% [150 FPS (NTSC) / 125 FPS (PAL)] " ) ,
FSUI_NSTR ( " 300% [180 FPS (NTSC) / 150 FPS (PAL)] " ) ,
FSUI_NSTR ( " 350% [210 FPS (NTSC) / 175 FPS (PAL)] " ) ,
FSUI_NSTR ( " 400% [240 FPS (NTSC) / 200 FPS (PAL)] " ) ,
FSUI_NSTR ( " 450% [270 FPS (NTSC) / 225 FPS (PAL)] " ) ,
FSUI_NSTR ( " 500% [300 FPS (NTSC) / 250 FPS (PAL)] " ) ,
FSUI_NSTR ( " 600% [360 FPS (NTSC) / 300 FPS (PAL)] " ) ,
FSUI_NSTR ( " 700% [420 FPS (NTSC) / 350 FPS (PAL)] " ) ,
FSUI_NSTR ( " 800% [480 FPS (NTSC) / 400 FPS (PAL)] " ) ,
FSUI_NSTR ( " 900% [540 FPS (NTSC) / 450 FPS (PAL)] " ) ,
FSUI_NSTR ( " 1000% [600 FPS (NTSC) / 500 FPS (PAL)] " ) ,
} ;
2021-01-30 11:37:49 +00:00
2022-08-25 15:26:55 +00:00
SettingsInterface * bsi = GetEditingSettingsInterface ( ) ;
2022-07-11 13:03:29 +00:00
BeginMenuButtons ( ) ;
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " Speed Control " ) ) ;
2022-07-11 13:03:29 +00:00
DrawFloatListSetting (
2024-04-13 09:56:08 +00:00
bsi , FSUI_ICONSTR ( ICON_FA_STOPWATCH , " Emulation Speed " ) ,
2023-08-20 02:38:55 +00:00
FSUI_CSTR ( " Sets the target emulation speed. It is not guaranteed that this speed will be reached on all systems. " ) ,
" Main " , " EmulationSpeed " , 1.0f , emulation_speed_titles . data ( ) , emulation_speed_values . data ( ) ,
2023-09-03 03:20:38 +00:00
emulation_speed_titles . size ( ) , true ) ;
2022-07-11 13:03:29 +00:00
DrawFloatListSetting (
2024-04-13 09:56:08 +00:00
bsi , FSUI_ICONSTR ( ICON_FA_BOLT , " Fast Forward Speed " ) ,
2023-08-20 02:38:55 +00:00
FSUI_CSTR ( " Sets the fast forward speed. It is not guaranteed that this speed will be reached on all systems. " ) ,
" Main " , " FastForwardSpeed " , 0.0f , emulation_speed_titles . data ( ) , emulation_speed_values . data ( ) ,
2023-09-03 03:20:38 +00:00
emulation_speed_titles . size ( ) , true ) ;
2023-08-20 02:38:55 +00:00
DrawFloatListSetting (
2024-04-13 09:56:08 +00:00
bsi , FSUI_ICONSTR ( ICON_FA_BOLT , " Turbo Speed " ) ,
2023-08-20 02:38:55 +00:00
FSUI_CSTR ( " Sets the turbo speed. It is not guaranteed that this speed will be reached on all systems. " ) , " Main " ,
2023-09-03 03:20:38 +00:00
" TurboSpeed " , 2.0f , emulation_speed_titles . data ( ) , emulation_speed_values . data ( ) , emulation_speed_titles . size ( ) ,
true ) ;
2022-07-11 13:03:29 +00:00
2024-04-13 09:56:08 +00:00
MenuHeading ( FSUI_CSTR ( " Latency Control " ) ) ;
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_TV , " Vertical Sync (VSync) " ) ,
FSUI_CSTR ( " Synchronizes presentation of the console's frames to the host. GSync/FreeSync users "
" should enable Optimal Frame Pacing instead. " ) ,
" Display " , " VSync " , false ) ;
DrawToggleSetting (
bsi , FSUI_ICONSTR ( ICON_FA_LIGHTBULB , " Sync To Host Refresh Rate " ) ,
FSUI_CSTR ( " Adjusts the emulation speed so the console's refresh rate matches the host when VSync is enabled. " ) ,
" Main " , " SyncToHostRefreshRate " , false ) ;
DrawToggleSetting (
bsi , FSUI_ICONSTR ( ICON_FA_TACHOMETER_ALT , " Optimal Frame Pacing " ) ,
FSUI_CSTR ( " Ensures every frame generated is displayed for optimal pacing. Enable for variable refresh displays, "
" such as GSync/FreeSync. Disable if you are having speed or sound issues. " ) ,
" Display " , " OptimalFramePacing " , false ) ;
const bool optimal_frame_pacing_active = GetEffectiveBoolSetting ( bsi , " Display " , " OptimalFramePacing " , false ) ;
DrawToggleSetting (
bsi , FSUI_ICONSTR ( ICON_FA_STOPWATCH_20 , " Reduce Input Latency " ) ,
FSUI_CSTR ( " Reduces input latency by delaying the start of frame until closer to the presentation time. " ) , " Display " ,
" PreFrameSleep " , false , optimal_frame_pacing_active ) ;
const bool pre_frame_sleep_active =
( optimal_frame_pacing_active & & GetEffectiveBoolSetting ( bsi , " Display " , " PreFrameSleep " , false ) ) ;
DrawFloatRangeSetting (
bsi , FSUI_ICONSTR ( ICON_FA_BATTERY_FULL , " Frame Time Buffer " ) ,
FSUI_CSTR ( " Specifies the amount of buffer time added, which reduces the additional sleep time introduced. " ) ,
" Display " , " PreFrameSleepBuffer " , Settings : : DEFAULT_DISPLAY_PRE_FRAME_SLEEP_BUFFER , 0.0f , 20.0f , " %.1f " , 1.0f ,
pre_frame_sleep_active ) ;
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " Runahead/Rewind " ) ) ;
2022-07-11 13:03:29 +00:00
2024-04-13 09:56:08 +00:00
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_BACKWARD , " Enable Rewinding " ) ,
2023-08-20 02:38:55 +00:00
FSUI_CSTR ( " Saves state periodically so you can rewind any mistakes while playing. " ) , " Main " ,
" RewindEnable " , false ) ;
2022-07-11 13:03:29 +00:00
DrawFloatRangeSetting (
2024-04-13 09:56:08 +00:00
bsi , FSUI_ICONSTR ( ICON_FA_SAVE , " Rewind Save Frequency " ) ,
2023-08-20 02:38:55 +00:00
FSUI_CSTR ( " How often a rewind state will be created. Higher frequencies have greater system requirements. " ) , " Main " ,
2024-03-20 12:48:23 +00:00
" RewindFrequency " , 10.0f , 0.0f , 3600.0f , FSUI_CSTR ( " %.2f Seconds " ) ) ;
2023-08-20 02:38:55 +00:00
DrawIntRangeSetting (
2024-04-13 09:56:08 +00:00
bsi , FSUI_ICONSTR ( ICON_FA_GLASS_WHISKEY , " Rewind Save Slots " ) ,
2023-08-20 02:38:55 +00:00
FSUI_CSTR ( " How many saves will be kept for rewinding. Higher values have greater memory requirements. " ) , " Main " ,
2024-03-20 12:48:23 +00:00
" RewindSaveSlots " , 10 , 1 , 10000 , FSUI_CSTR ( " %d Frames " ) ) ;
2022-07-11 13:03:29 +00:00
2022-08-25 15:26:55 +00:00
const s32 runahead_frames = GetEffectiveIntSetting ( bsi , " Main " , " RunaheadFrameCount " , 0 ) ;
2022-07-11 13:03:29 +00:00
const bool runahead_enabled = ( runahead_frames > 0 ) ;
2022-08-25 15:26:55 +00:00
const bool rewind_enabled = GetEffectiveBoolSetting ( bsi , " Main " , " RewindEnable " , false ) ;
2022-07-11 13:03:29 +00:00
2023-10-02 03:33:33 +00:00
static constexpr const std : : array runahead_options = {
FSUI_NSTR ( " Disabled " ) , FSUI_NSTR ( " 1 Frame " ) , FSUI_NSTR ( " 2 Frames " ) , FSUI_NSTR ( " 3 Frames " ) ,
FSUI_NSTR ( " 4 Frames " ) , FSUI_NSTR ( " 5 Frames " ) , FSUI_NSTR ( " 6 Frames " ) , FSUI_NSTR ( " 7 Frames " ) ,
FSUI_NSTR ( " 8 Frames " ) , FSUI_NSTR ( " 9 Frames " ) , FSUI_NSTR ( " 10 Frames " ) } ;
2022-07-11 13:03:29 +00:00
DrawIntListSetting (
2024-04-13 09:56:08 +00:00
bsi , FSUI_ICONSTR ( ICON_FA_RUNNING , " Runahead " ) ,
2023-08-20 02:38:55 +00:00
FSUI_CSTR (
" Simulates the system ahead of time and rolls back/replays to reduce input lag. Very high system requirements. " ) ,
2023-09-03 03:20:38 +00:00
" Main " , " RunaheadFrameCount " , 0 , runahead_options . data ( ) , runahead_options . size ( ) , true ) ;
2022-07-11 13:03:29 +00:00
TinyString rewind_summary ;
if ( runahead_enabled )
{
2023-08-20 02:38:55 +00:00
rewind_summary = FSUI_VSTR ( " Rewind is disabled because runahead is enabled. Runahead will significantly increase "
" system requirements. " ) ;
2022-07-11 13:03:29 +00:00
}
else if ( rewind_enabled )
{
2023-12-18 10:36:07 +00:00
const u32 resolution_scale = GetEffectiveUIntSetting ( bsi , " GPU " , " ResolutionScale " , 1 ) ;
2022-08-25 15:26:55 +00:00
const float rewind_frequency = GetEffectiveFloatSetting ( bsi , " Main " , " RewindFrequency " , 10.0f ) ;
const s32 rewind_save_slots = GetEffectiveIntSetting ( bsi , " Main " , " RewindSaveSlots " , 10 ) ;
2022-07-11 13:03:29 +00:00
const float duration =
( ( rewind_frequency < = std : : numeric_limits < float > : : epsilon ( ) ) ? ( 1.0f / 60.0f ) : rewind_frequency ) *
static_cast < float > ( rewind_save_slots ) ;
u64 ram_usage , vram_usage ;
2023-12-18 10:36:07 +00:00
System : : CalculateRewindMemoryUsage ( rewind_save_slots , resolution_scale , & ram_usage , & vram_usage ) ;
2023-12-13 11:06:15 +00:00
rewind_summary . format (
2023-11-28 16:08:19 +00:00
FSUI_FSTR ( " Rewind for {0} frames, lasting {1:.2f} seconds will require up to {2} MB of RAM and {3} MB of VRAM. " ) ,
2023-08-20 02:38:55 +00:00
rewind_save_slots , duration , ram_usage / 1048576 , vram_usage / 1048576 ) ;
2022-07-11 13:03:29 +00:00
}
else
{
2023-09-16 09:06:59 +00:00
rewind_summary = FSUI_VSTR ( " Rewind is not enabled. Please note that enabling rewind may significantly increase "
" system requirements. " ) ;
2022-07-11 13:03:29 +00:00
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
ActiveButton ( rewind_summary , false , false , ImGuiFullscreen : : LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY , g_large_font ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
EndMenuButtons ( ) ;
}
2021-06-20 04:01:10 +00:00
2022-08-25 15:26:55 +00:00
void FullscreenUI : : CopyGlobalControllerSettingsToGame ( )
{
SettingsInterface * dsi = GetEditingSettingsInterface ( true ) ;
SettingsInterface * ssi = GetEditingSettingsInterface ( false ) ;
InputManager : : CopyConfiguration ( dsi , * ssi , true , true , false ) ;
SetSettingsChanged ( dsi ) ;
2023-08-20 02:38:55 +00:00
ShowToast ( std : : string ( ) , FSUI_STR ( " Per-game controller configuration initialized with global settings. " ) ) ;
2022-08-25 15:26:55 +00:00
}
2022-08-27 04:42:16 +00:00
void FullscreenUI : : DoLoadInputProfile ( )
{
2024-04-07 10:43:13 +00:00
std : : vector < std : : string > profiles = InputManager : : GetInputProfileNames ( ) ;
2022-08-27 04:42:16 +00:00
if ( profiles . empty ( ) )
{
2023-08-20 02:38:55 +00:00
ShowToast ( std : : string ( ) , FSUI_STR ( " No input profiles available. " ) ) ;
2022-08-27 04:42:16 +00:00
return ;
}
ImGuiFullscreen : : ChoiceDialogOptions coptions ;
coptions . reserve ( profiles . size ( ) ) ;
for ( std : : string & name : profiles )
coptions . emplace_back ( std : : move ( name ) , false ) ;
2023-08-20 02:38:55 +00:00
OpenChoiceDialog ( FSUI_ICONSTR ( ICON_FA_FOLDER_OPEN , " Load Profile " ) , false , std : : move ( coptions ) ,
2022-08-27 04:42:16 +00:00
[ ] ( s32 index , const std : : string & title , bool checked ) {
if ( index < 0 )
return ;
INISettingsInterface ssi ( System : : GetInputProfilePath ( title ) ) ;
if ( ! ssi . Load ( ) )
{
2023-08-20 02:38:55 +00:00
ShowToast ( std : : string ( ) , fmt : : format ( FSUI_FSTR ( " Failed to load '{}'. " ) , title ) ) ;
2022-08-27 04:42:16 +00:00
CloseChoiceDialog ( ) ;
return ;
}
auto lock = Host : : GetSettingsLock ( ) ;
SettingsInterface * dsi = GetEditingSettingsInterface ( ) ;
InputManager : : CopyConfiguration ( dsi , ssi , true , true , IsEditingGameSettings ( dsi ) ) ;
SetSettingsChanged ( dsi ) ;
2023-08-20 02:38:55 +00:00
ShowToast ( std : : string ( ) , fmt : : format ( FSUI_FSTR ( " Input profile '{}' loaded. " ) , title ) ) ;
2022-08-27 04:42:16 +00:00
CloseChoiceDialog ( ) ;
} ) ;
}
void FullscreenUI : : DoSaveInputProfile ( const std : : string & name )
{
INISettingsInterface dsi ( System : : GetInputProfilePath ( name ) ) ;
auto lock = Host : : GetSettingsLock ( ) ;
SettingsInterface * ssi = GetEditingSettingsInterface ( ) ;
InputManager : : CopyConfiguration ( & dsi , * ssi , true , true , IsEditingGameSettings ( ssi ) ) ;
if ( dsi . Save ( ) )
2023-08-20 02:38:55 +00:00
ShowToast ( std : : string ( ) , fmt : : format ( FSUI_FSTR ( " Input profile '{}' saved. " ) , name ) ) ;
2022-08-27 04:42:16 +00:00
else
2023-08-20 02:38:55 +00:00
ShowToast ( std : : string ( ) , fmt : : format ( FSUI_FSTR ( " Failed to save input profile '{}'. " ) , name ) ) ;
2022-08-27 04:42:16 +00:00
}
2024-04-07 10:43:13 +00:00
void FullscreenUI : : DoSaveNewInputProfile ( )
{
OpenInputStringDialog ( FSUI_ICONSTR ( ICON_FA_SAVE , " Save Profile " ) ,
2024-04-09 10:04:45 +00:00
FSUI_STR ( " Enter the name of the input profile you wish to create. " ) , std : : string ( ) ,
FSUI_ICONSTR ( ICON_FA_FOLDER_PLUS , " Create " ) , [ ] ( std : : string title ) {
if ( ! title . empty ( ) )
DoSaveInputProfile ( title ) ;
} ) ;
2024-04-07 10:43:13 +00:00
}
2022-08-27 04:42:16 +00:00
void FullscreenUI : : DoSaveInputProfile ( )
{
2024-04-07 10:43:13 +00:00
std : : vector < std : : string > profiles = InputManager : : GetInputProfileNames ( ) ;
2022-08-27 04:42:16 +00:00
if ( profiles . empty ( ) )
{
2024-04-07 10:43:13 +00:00
DoSaveNewInputProfile ( ) ;
2022-08-27 04:42:16 +00:00
return ;
}
ImGuiFullscreen : : ChoiceDialogOptions coptions ;
coptions . reserve ( profiles . size ( ) + 1 ) ;
2024-04-07 10:43:13 +00:00
coptions . emplace_back ( FSUI_STR ( " Create New... " ) , false ) ;
2022-08-27 04:42:16 +00:00
for ( std : : string & name : profiles )
coptions . emplace_back ( std : : move ( name ) , false ) ;
2023-08-20 02:38:55 +00:00
OpenChoiceDialog ( FSUI_ICONSTR ( ICON_FA_SAVE , " Save Profile " ) , false , std : : move ( coptions ) ,
[ ] ( s32 index , const std : : string & title , bool checked ) {
if ( index < 0 )
return ;
2022-08-27 04:42:16 +00:00
2024-04-07 10:43:13 +00:00
if ( index > 0 )
2024-04-13 04:41:10 +00:00
{
2024-04-07 10:43:13 +00:00
DoSaveInputProfile ( title ) ;
2024-04-13 04:41:10 +00:00
CloseChoiceDialog ( ) ;
}
2024-04-07 10:43:13 +00:00
else
2024-04-13 04:41:10 +00:00
{
CloseChoiceDialog ( ) ;
2024-04-07 10:43:13 +00:00
DoSaveNewInputProfile ( ) ;
2024-04-13 04:41:10 +00:00
}
2023-08-20 02:38:55 +00:00
} ) ;
2022-08-27 04:42:16 +00:00
}
2022-08-25 15:26:55 +00:00
void FullscreenUI : : ResetControllerSettings ( )
{
SettingsInterface * dsi = GetEditingSettingsInterface ( ) ;
2023-08-23 12:06:48 +00:00
Settings : : SetDefaultControllerConfig ( * dsi ) ;
2023-08-20 02:38:55 +00:00
ShowToast ( std : : string ( ) , FSUI_STR ( " Controller settings reset to default. " ) ) ;
2022-08-25 15:26:55 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DrawControllerSettingsPage ( )
{
BeginMenuButtons ( ) ;
2021-06-20 04:01:10 +00:00
2022-07-11 13:03:29 +00:00
SettingsInterface * bsi = GetEditingSettingsInterface ( ) ;
2022-08-25 15:26:55 +00:00
const bool game_settings = IsEditingGameSettings ( bsi ) ;
2023-11-28 16:08:19 +00:00
MenuHeading ( FSUI_CSTR ( " Configuration " ) ) ;
2022-08-25 15:26:55 +00:00
if ( IsEditingGameSettings ( bsi ) )
{
2023-08-20 02:38:55 +00:00
if ( DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_COG , " Per-Game Configuration " ) ,
FSUI_CSTR ( " Uses game-specific settings for controllers for this game. " ) , " Pad " ,
2022-08-25 15:26:55 +00:00
" UseGameSettingsForController " , false , IsEditingGameSettings ( bsi ) , false ) )
{
// did we just enable per-game for the first time?
if ( bsi - > GetBoolValue ( " Pad " , " UseGameSettingsForController " , false ) & &
! bsi - > GetBoolValue ( " Pad " , " GameSettingsInitialized " , false ) )
{
bsi - > SetBoolValue ( " Pad " , " GameSettingsInitialized " , true ) ;
CopyGlobalControllerSettingsToGame ( ) ;
}
}
}
if ( IsEditingGameSettings ( bsi ) & & ! bsi - > GetBoolValue ( " Pad " , " UseGameSettingsForController " , false ) )
{
// nothing to edit..
EndMenuButtons ( ) ;
return ;
}
if ( IsEditingGameSettings ( bsi ) )
{
2023-08-20 02:38:55 +00:00
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_COPY , " Copy Global Settings " ) ,
FSUI_CSTR ( " Copies the global controller configuration to this game. " ) ) )
2022-08-25 15:26:55 +00:00
CopyGlobalControllerSettingsToGame ( ) ;
}
else
{
2024-02-05 13:34:34 +00:00
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_DUMPSTER_FIRE , " Reset Settings " ) ,
2023-08-20 02:38:55 +00:00
FSUI_CSTR ( " Resets all configuration to defaults (including bindings). " ) ) )
2022-08-27 04:42:16 +00:00
{
2022-08-25 15:26:55 +00:00
ResetControllerSettings ( ) ;
2022-08-27 04:42:16 +00:00
}
2022-08-25 15:26:55 +00:00
}
2023-08-20 02:38:55 +00:00
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_FOLDER_OPEN , " Load Profile " ) ,
FSUI_CSTR ( " Replaces these settings with a previously saved input profile. " ) ) )
2022-08-25 15:26:55 +00:00
{
2022-08-27 04:42:16 +00:00
DoLoadInputProfile ( ) ;
2022-08-25 15:26:55 +00:00
}
2023-08-20 02:38:55 +00:00
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_SAVE , " Save Profile " ) ,
FSUI_CSTR ( " Stores the current settings to an input profile. " ) ) )
2022-08-25 15:26:55 +00:00
{
2022-08-27 04:42:16 +00:00
DoSaveInputProfile ( ) ;
2022-08-25 15:26:55 +00:00
}
2021-06-20 04:01:10 +00:00
2023-09-16 09:06:59 +00:00
MenuHeading ( FSUI_CSTR ( " Input Sources " ) ) ;
2021-06-20 04:01:10 +00:00
2023-09-17 02:28:11 +00:00
# ifdef ENABLE_SDL2
2023-08-20 02:38:55 +00:00
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_COG , " Enable SDL Input Source " ) ,
FSUI_CSTR ( " The SDL input source supports most controllers. " ) , " InputSources " , " SDL " , true , true ,
2022-08-25 15:26:55 +00:00
false ) ;
2023-08-20 02:38:55 +00:00
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_WIFI , " SDL DualShock 4 / DualSense Enhanced Mode " ) ,
FSUI_CSTR ( " Provides vibration and LED control support over Bluetooth. " ) , " InputSources " ,
" SDLControllerEnhancedMode " , false , bsi - > GetBoolValue ( " InputSources " , " SDL " , true ) , false ) ;
2022-07-11 13:03:29 +00:00
# endif
# ifdef _WIN32
2023-08-20 02:38:55 +00:00
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_COG , " Enable XInput Input Source " ) ,
FSUI_CSTR ( " The XInput source provides support for XBox 360/XBox One/XBox Series controllers. " ) ,
" InputSources " , " XInput " , false ) ;
2021-06-20 04:01:10 +00:00
# endif
2021-01-30 11:37:49 +00:00
2023-11-28 16:08:19 +00:00
MenuHeading ( FSUI_CSTR ( " Multitap " ) ) ;
2023-08-20 02:38:55 +00:00
DrawEnumSetting ( bsi , FSUI_ICONSTR ( ICON_FA_PLUS_SQUARE , " Multitap Mode " ) ,
FSUI_CSTR ( " Enables an additional three controller slots on each port. Not supported in all games. " ) ,
2022-07-11 13:03:29 +00:00
" ControllerPorts " , " MultitapMode " , Settings : : DEFAULT_MULTITAP_MODE , & Settings : : ParseMultitapModeName ,
& Settings : : GetMultitapModeName , & Settings : : GetMultitapModeDisplayName , MultitapMode : : Count ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
// load mtap settings
MultitapMode mtap_mode = g_settings . multitap_mode ;
2022-08-25 15:26:55 +00:00
if ( IsEditingGameSettings ( bsi ) )
2022-07-11 13:03:29 +00:00
{
2024-04-07 10:43:13 +00:00
mtap_mode = Settings : : ParseMultitapModeName ( bsi - > GetTinyStringValue ( " ControllerPorts " , " MultitapMode " , " " ) . c_str ( ) )
2022-07-11 13:03:29 +00:00
. value_or ( g_settings . multitap_mode ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
const std : : array < bool , 2 > mtap_enabled = {
{ ( mtap_mode = = MultitapMode : : Port1Only | | mtap_mode = = MultitapMode : : BothPorts ) ,
( mtap_mode = = MultitapMode : : Port2Only | | mtap_mode = = MultitapMode : : BothPorts ) } } ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
// we reorder things a little to make it look less silly for mtap
static constexpr const std : : array < char , 4 > mtap_slot_names = { { ' A ' , ' B ' , ' C ' , ' D ' } } ;
static constexpr const std : : array < u32 , NUM_CONTROLLER_AND_CARD_PORTS > mtap_port_order = { { 0 , 2 , 3 , 4 , 1 , 5 , 6 , 7 } } ;
// create the ports
for ( u32 global_slot : mtap_port_order )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
const auto [ mtap_port , mtap_slot ] = Controller : : ConvertPadToPortAndSlot ( global_slot ) ;
const bool is_mtap_port = Controller : : PortAndSlotIsMultitap ( mtap_port , mtap_slot ) ;
if ( is_mtap_port & & ! mtap_enabled [ mtap_port ] )
continue ;
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
if ( mtap_enabled [ mtap_port ] )
{
2023-12-14 06:07:57 +00:00
MenuHeading ( TinyString : : from_format ( fmt : : runtime ( FSUI_ICONSTR ( ICON_FA_PLUG , " Controller Port {}{} " ) ) ,
mtap_port + 1 , mtap_slot_names [ mtap_slot ] ) ) ;
2023-08-20 02:38:55 +00:00
}
else
{
2023-12-14 06:07:57 +00:00
MenuHeading (
TinyString : : from_format ( fmt : : runtime ( FSUI_ICONSTR ( ICON_FA_PLUG , " Controller Port {} " ) ) , mtap_port + 1 ) ) ;
2023-08-20 02:38:55 +00:00
}
2021-01-30 11:37:49 +00:00
2023-12-13 11:06:15 +00:00
const TinyString section = TinyString : : from_format ( " Pad{} " , global_slot + 1 ) ;
2024-04-07 10:43:13 +00:00
const TinyString type =
bsi - > GetTinyStringValue ( section . c_str ( ) , " Type " , Controller : : GetDefaultPadType ( global_slot ) ) ;
2022-07-11 13:03:29 +00:00
const Controller : : ControllerInfo * ci = Controller : : GetControllerInfo ( type ) ;
2023-12-13 11:06:15 +00:00
if ( MenuButton ( TinyString : : from_format ( " {}##type{} " , FSUI_ICONSTR ( ICON_FA_GAMEPAD , " Controller Type " ) , global_slot ) ,
2023-11-30 04:21:44 +00:00
ci ? Host : : TranslateToCString ( " ControllerType " , ci - > display_name ) : FSUI_CSTR ( " Unknown " ) ) )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
std : : vector < std : : pair < std : : string , std : : string > > raw_options ( Controller : : GetControllerTypeNames ( ) ) ;
ImGuiFullscreen : : ChoiceDialogOptions options ;
options . reserve ( raw_options . size ( ) ) ;
for ( auto & it : raw_options )
{
options . emplace_back ( std : : move ( it . second ) , type = = it . first ) ;
}
2023-12-13 11:06:15 +00:00
OpenChoiceDialog ( TinyString : : from_format ( FSUI_FSTR ( " Port {} Controller Type " ) , global_slot + 1 ) , false ,
2023-08-20 02:38:55 +00:00
std : : move ( options ) ,
2022-08-25 15:26:55 +00:00
[ game_settings , section ,
raw_options = std : : move ( raw_options ) ] ( s32 index , const std : : string & title , bool checked ) {
if ( index < 0 )
return ;
2022-07-11 13:03:29 +00:00
2022-08-25 15:26:55 +00:00
auto lock = Host : : GetSettingsLock ( ) ;
SettingsInterface * bsi = GetEditingSettingsInterface ( game_settings ) ;
bsi - > SetStringValue ( section . c_str ( ) , " Type " , raw_options [ index ] . first . c_str ( ) ) ;
SetSettingsChanged ( bsi ) ;
CloseChoiceDialog ( ) ;
} ) ;
2021-01-30 11:37:49 +00:00
}
2023-10-12 09:29:09 +00:00
if ( ! ci | | ci - > bindings . empty ( ) )
2022-07-11 13:03:29 +00:00
continue ;
2021-06-18 21:40:11 +00:00
2023-08-20 02:38:55 +00:00
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_MAGIC , " Automatic Mapping " ) ,
FSUI_CSTR ( " Attempts to map the selected port to a chosen controller. " ) ) )
{
2022-07-11 13:03:29 +00:00
StartAutomaticBinding ( global_slot ) ;
2023-08-20 02:38:55 +00:00
}
2021-02-26 14:44:53 +00:00
2023-09-20 07:10:41 +00:00
for ( const Controller : : ControllerBindingInfo & bi : ci - > bindings )
2023-10-12 09:29:09 +00:00
{
DrawInputBindingButton ( bsi , bi . type , section . c_str ( ) , bi . name ,
2023-11-26 10:30:10 +00:00
Host : : TranslateToCString ( ci - > name , bi . display_name ) , bi . icon_name , true ) ;
2023-10-12 09:29:09 +00:00
}
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
if ( mtap_enabled [ mtap_port ] )
{
2023-12-13 11:06:15 +00:00
MenuHeading ( SmallString : : from_format ( fmt : : runtime ( FSUI_ICONSTR ( ICON_FA_MICROCHIP , " Controller Port {}{} Macros " ) ) ,
2023-12-14 06:07:57 +00:00
mtap_port + 1 , mtap_slot_names [ mtap_slot ] ) ) ;
2023-08-20 02:38:55 +00:00
}
else
{
2023-12-13 11:06:15 +00:00
MenuHeading ( SmallString : : from_format ( fmt : : runtime ( FSUI_ICONSTR ( ICON_FA_MICROCHIP , " Controller Port {} Macros " ) ) ,
2023-12-14 06:07:57 +00:00
mtap_port + 1 ) ) ;
2023-08-20 02:38:55 +00:00
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
for ( u32 macro_index = 0 ; macro_index < InputManager : : NUM_MACRO_BUTTONS_PER_CONTROLLER ; macro_index + + )
2021-01-30 11:37:49 +00:00
{
2023-01-15 04:00:51 +00:00
DrawInputBindingButton ( bsi , InputBindingInfo : : Type : : Macro , section . c_str ( ) ,
2023-12-13 11:06:15 +00:00
TinyString : : from_format ( " Macro{} " , macro_index + 1 ) ,
TinyString : : from_format ( FSUI_FSTR ( " Macro {} Trigger " ) , macro_index + 1 ) , nullptr ) ;
2022-07-11 13:03:29 +00:00
2024-04-07 10:43:13 +00:00
SmallString binds_string =
bsi - > GetSmallStringValue ( section . c_str ( ) , fmt : : format ( " Macro{}Binds " , macro_index + 1 ) . c_str ( ) ) ;
2023-11-26 11:34:00 +00:00
TinyString pretty_binds_string ;
if ( ! binds_string . empty ( ) )
{
for ( const std : : string_view & bind : StringUtil : : SplitString ( binds_string , ' & ' , true ) )
{
const char * dispname = nullptr ;
for ( const Controller : : ControllerBindingInfo & bi : ci - > bindings )
{
if ( bind = = bi . name )
{
dispname = bi . icon_name ? bi . icon_name : Host : : TranslateToCString ( ci - > name , bi . display_name ) ;
break ;
}
}
2023-12-13 11:06:15 +00:00
pretty_binds_string . append_format ( " {}{} " , pretty_binds_string . empty ( ) ? " " : " " , dispname ) ;
2023-11-26 11:34:00 +00:00
}
}
if ( MenuButtonWithValue (
2023-12-13 11:06:15 +00:00
TinyString : : from_format ( fmt : : runtime ( FSUI_ICONSTR ( ICON_FA_KEYBOARD , " Macro {} Buttons " ) ) , macro_index + 1 ) ,
2023-11-26 11:34:00 +00:00
nullptr , pretty_binds_string . empty ( ) ? FSUI_CSTR ( " - " ) : pretty_binds_string . c_str ( ) , true ,
LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ) )
2022-07-11 13:03:29 +00:00
{
std : : vector < std : : string_view > buttons_split ( StringUtil : : SplitString ( binds_string , ' & ' , true ) ) ;
ImGuiFullscreen : : ChoiceDialogOptions options ;
2023-09-20 07:10:41 +00:00
for ( const Controller : : ControllerBindingInfo & bi : ci - > bindings )
2022-07-11 13:03:29 +00:00
{
2023-01-15 04:00:51 +00:00
if ( bi . type ! = InputBindingInfo : : Type : : Button & & bi . type ! = InputBindingInfo : : Type : : Axis & &
bi . type ! = InputBindingInfo : : Type : : HalfAxis )
2022-07-11 13:03:29 +00:00
{
continue ;
}
2023-10-12 09:29:09 +00:00
options . emplace_back ( Host : : TranslateToString ( ci - > name , bi . display_name ) ,
2022-07-11 13:03:29 +00:00
std : : any_of ( buttons_split . begin ( ) , buttons_split . end ( ) ,
[ bi ] ( const std : : string_view & it ) { return ( it = = bi . name ) ; } ) ) ;
}
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
OpenChoiceDialog (
2023-12-13 11:06:15 +00:00
TinyString : : from_format ( FSUI_FSTR ( " Select Macro {} Binds " ) , macro_index + 1 ) , true , std : : move ( options ) ,
2023-08-20 02:38:55 +00:00
[ game_settings , section , macro_index , ci ] ( s32 index , const std : : string & title , bool checked ) {
// convert display name back to bind name
std : : string_view to_modify ;
2023-09-20 07:10:41 +00:00
for ( const Controller : : ControllerBindingInfo & bi : ci - > bindings )
2023-08-20 02:38:55 +00:00
{
2023-10-12 09:29:09 +00:00
if ( title = = Host : : TranslateToStringView ( ci - > name , bi . display_name ) )
2023-08-20 02:38:55 +00:00
{
to_modify = bi . name ;
break ;
}
}
if ( to_modify . empty ( ) )
{
// wtf?
return ;
}
2022-07-11 13:03:29 +00:00
2023-08-20 02:38:55 +00:00
auto lock = Host : : GetSettingsLock ( ) ;
SettingsInterface * bsi = GetEditingSettingsInterface ( game_settings ) ;
2023-12-13 11:06:15 +00:00
const TinyString key = TinyString : : from_format ( " Macro{}Binds " , macro_index + 1 ) ;
2022-07-11 13:03:29 +00:00
2023-12-06 10:12:08 +00:00
std : : string binds_string = bsi - > GetStringValue ( section . c_str ( ) , key . c_str ( ) ) ;
2023-08-20 02:38:55 +00:00
std : : vector < std : : string_view > buttons_split ( StringUtil : : SplitString ( binds_string , ' & ' , true ) ) ;
auto it = std : : find ( buttons_split . begin ( ) , buttons_split . end ( ) , to_modify ) ;
if ( checked )
{
if ( it = = buttons_split . end ( ) )
buttons_split . push_back ( to_modify ) ;
}
else
{
if ( it ! = buttons_split . end ( ) )
buttons_split . erase ( it ) ;
}
2022-07-11 13:03:29 +00:00
2023-08-20 02:38:55 +00:00
binds_string = StringUtil : : JoinString ( buttons_split . begin ( ) , buttons_split . end ( ) , " & " ) ;
if ( binds_string . empty ( ) )
bsi - > DeleteValue ( section . c_str ( ) , key . c_str ( ) ) ;
else
bsi - > SetStringValue ( section . c_str ( ) , key . c_str ( ) , binds_string . c_str ( ) ) ;
} ) ;
2022-07-11 13:03:29 +00:00
}
2021-01-30 11:37:49 +00:00
2023-12-13 11:06:15 +00:00
const TinyString freq_key = TinyString : : from_format ( " Macro{}Frequency " , macro_index + 1 ) ;
2023-08-20 02:38:55 +00:00
const SmallString freq_title =
2023-12-13 11:06:15 +00:00
SmallString : : from_format ( fmt : : runtime ( FSUI_ICONSTR ( ICON_FA_LIGHTBULB , " Macro {} Frequency " ) ) , macro_index + 1 ) ;
2022-07-11 13:03:29 +00:00
s32 frequency = bsi - > GetIntValue ( section . c_str ( ) , freq_key . c_str ( ) , 0 ) ;
2023-08-20 02:38:55 +00:00
SmallString freq_summary ;
if ( frequency = = 0 )
2023-11-26 11:34:00 +00:00
freq_summary = FSUI_VSTR ( " Disabled " ) ;
2023-08-20 02:38:55 +00:00
else
2023-12-13 11:06:15 +00:00
freq_summary . format ( FSUI_FSTR ( " {} Frames " ) , frequency ) ;
2023-11-26 11:34:00 +00:00
if ( MenuButtonWithValue ( freq_title , nullptr , freq_summary , true , LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ) )
2023-08-20 02:38:55 +00:00
ImGui : : OpenPopup ( freq_title ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
ImGui : : SetNextWindowSize ( LayoutScale ( 500.0f , 180.0f ) ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
ImGui : : PushFont ( g_large_font ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowRounding , LayoutScale ( 10.0f ) ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , LayoutScale ( ImGuiFullscreen : : LAYOUT_MENU_BUTTON_X_PADDING ,
ImGuiFullscreen : : LAYOUT_MENU_BUTTON_Y_PADDING ) ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowPadding , LayoutScale ( 20.0f , 20.0f ) ) ;
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
if ( ImGui : : BeginPopupModal ( freq_title , nullptr ,
2022-07-11 13:03:29 +00:00
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove ) )
{
ImGui : : SetNextItemWidth ( LayoutScale ( 450.0f ) ) ;
2023-08-20 02:38:55 +00:00
if ( ImGui : : SliderInt ( " ##value " , & frequency , 0 , 60 , FSUI_CSTR ( " Toggle every %d frames " ) ,
ImGuiSliderFlags_NoInput ) )
2022-07-11 13:03:29 +00:00
{
if ( frequency = = 0 )
bsi - > DeleteValue ( section . c_str ( ) , freq_key . c_str ( ) ) ;
else
bsi - > SetIntValue ( section . c_str ( ) , freq_key . c_str ( ) , frequency ) ;
}
BeginMenuButtons ( ) ;
2023-12-06 10:12:08 +00:00
if ( MenuButton ( FSUI_CSTR ( " OK " ) , nullptr , true , LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ) )
2022-07-11 13:03:29 +00:00
ImGui : : CloseCurrentPopup ( ) ;
EndMenuButtons ( ) ;
ImGui : : EndPopup ( ) ;
}
ImGui : : PopStyleVar ( 3 ) ;
ImGui : : PopFont ( ) ;
2021-01-30 11:37:49 +00:00
}
2023-09-20 07:10:41 +00:00
if ( ! ci - > settings . empty ( ) )
2021-01-30 11:37:49 +00:00
{
2023-08-20 02:38:55 +00:00
if ( mtap_enabled [ mtap_port ] )
{
2023-09-20 13:49:14 +00:00
MenuHeading (
2023-12-13 11:06:15 +00:00
SmallString : : from_format ( fmt : : runtime ( FSUI_ICONSTR ( ICON_FA_SLIDERS_H , " Controller Port {}{} Settings " ) ) ,
2023-12-14 06:07:57 +00:00
mtap_port + 1 , mtap_slot_names [ mtap_slot ] ) ) ;
2023-08-20 02:38:55 +00:00
}
else
{
2023-12-14 06:07:57 +00:00
MenuHeading ( SmallString : : from_format (
fmt : : runtime ( FSUI_ICONSTR ( ICON_FA_SLIDERS_H , " Controller Port {} Settings " ) ) , mtap_port + 1 ) ) ;
2023-08-20 02:38:55 +00:00
}
2022-08-25 15:26:55 +00:00
2023-09-20 07:10:41 +00:00
for ( const SettingInfo & si : ci - > settings )
2022-08-25 15:26:55 +00:00
{
TinyString title ;
2023-12-13 11:06:15 +00:00
title . format ( ICON_FA_COG " {} " , Host : : TranslateToStringView ( ci - > name , si . display_name ) ) ;
2023-10-12 09:29:09 +00:00
const char * description = Host : : TranslateToCString ( ci - > name , si . description ) ;
2022-08-25 15:26:55 +00:00
switch ( si . type )
{
case SettingInfo : : Type : : Boolean :
2023-10-12 09:29:09 +00:00
DrawToggleSetting ( bsi , title , description , section . c_str ( ) , si . name , si . BooleanDefaultValue ( ) , true , false ) ;
2022-08-25 15:26:55 +00:00
break ;
case SettingInfo : : Type : : Integer :
2023-10-12 09:29:09 +00:00
DrawIntRangeSetting ( bsi , title , description , section . c_str ( ) , si . name , si . IntegerDefaultValue ( ) ,
2022-08-25 15:26:55 +00:00
si . IntegerMinValue ( ) , si . IntegerMaxValue ( ) , si . format , true ) ;
break ;
2022-09-22 03:50:31 +00:00
case SettingInfo : : Type : : IntegerList :
2023-10-12 09:29:09 +00:00
DrawIntListSetting ( bsi , title , description , section . c_str ( ) , si . name , si . IntegerDefaultValue ( ) , si . options ,
2023-11-30 04:21:44 +00:00
0 , true , si . IntegerMinValue ( ) , true , LAYOUT_MENU_BUTTON_HEIGHT , g_large_font ,
2023-10-12 09:29:09 +00:00
g_medium_font , ci - > name ) ;
2022-09-22 03:50:31 +00:00
break ;
2022-08-25 15:26:55 +00:00
case SettingInfo : : Type : : Float :
2023-10-12 09:29:09 +00:00
DrawFloatSpinBoxSetting ( bsi , title , description , section . c_str ( ) , si . name , si . FloatDefaultValue ( ) ,
2022-10-31 08:08:26 +00:00
si . FloatMinValue ( ) , si . FloatMaxValue ( ) , si . FloatStepValue ( ) , si . multiplier ,
si . format , true ) ;
2022-08-25 15:26:55 +00:00
break ;
default :
break ;
}
}
2021-01-30 11:37:49 +00:00
}
}
2022-07-11 13:03:29 +00:00
EndMenuButtons ( ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DrawHotkeySettingsPage ( )
2021-01-30 11:37:49 +00:00
{
2022-08-25 15:26:55 +00:00
SettingsInterface * bsi = GetEditingSettingsInterface ( ) ;
2022-07-11 13:03:29 +00:00
BeginMenuButtons ( ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
const HotkeyInfo * last_category = nullptr ;
for ( const HotkeyInfo * hotkey : s_hotkey_list_cache )
{
2022-10-31 08:08:26 +00:00
if ( ! last_category | | std : : strcmp ( hotkey - > category , last_category - > category ) ! = 0 )
2022-07-11 13:03:29 +00:00
{
2023-11-28 16:08:19 +00:00
MenuHeading ( Host : : TranslateToCString ( " Hotkeys " , hotkey - > category ) ) ;
2022-07-11 13:03:29 +00:00
last_category = hotkey ;
}
2023-10-12 09:29:09 +00:00
DrawInputBindingButton ( bsi , InputBindingInfo : : Type : : Button , " Hotkeys " , hotkey - > name ,
2023-11-26 10:30:10 +00:00
Host : : TranslateToCString ( " Hotkeys " , hotkey - > display_name ) , nullptr , false ) ;
2022-07-11 13:03:29 +00:00
}
EndMenuButtons ( ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DrawMemoryCardSettingsPage ( )
2021-01-30 11:37:49 +00:00
{
2023-10-02 03:33:33 +00:00
static constexpr const std : : array type_keys = { " Card1Type " , " Card2Type " } ;
static constexpr const std : : array path_keys = { " Card1Path " , " Card2Path " } ;
2022-07-11 13:03:29 +00:00
2022-08-25 15:26:55 +00:00
SettingsInterface * bsi = GetEditingSettingsInterface ( ) ;
const bool game_settings = IsEditingGameSettings ( bsi ) ;
2022-07-11 13:03:29 +00:00
2022-08-25 15:26:55 +00:00
BeginMenuButtons ( ) ;
2021-01-30 11:37:49 +00:00
2023-09-16 09:06:59 +00:00
MenuHeading ( FSUI_CSTR ( " Settings and Operations " ) ) ;
2023-08-20 02:38:55 +00:00
DrawFolderSetting ( bsi , FSUI_ICONSTR ( ICON_FA_FOLDER_OPEN , " Memory Card Directory " ) , " MemoryCards " , " Directory " ,
2022-08-25 15:26:55 +00:00
EmuFolders : : MemoryCards ) ;
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
if ( ! game_settings & & MenuButton ( FSUI_ICONSTR ( ICON_FA_MAGIC , " Reset Memory Card Directory " ) ,
FSUI_CSTR ( " Resets memory card directory to default (user directory). " ) ) )
2021-01-30 11:37:49 +00:00
{
2022-08-25 15:26:55 +00:00
bsi - > SetStringValue ( " MemoryCards " , " Directory " , " memcards " ) ;
SetSettingsChanged ( bsi ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
2023-08-23 08:40:59 +00:00
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_SEARCH , " Use Single Card For Multi-Disc Games " ) ,
FSUI_CSTR ( " When playing a multi-disc game and using per-game (title) memory cards, "
2023-08-20 02:38:55 +00:00
" use a single memory card for all discs. " ) ,
2022-08-25 15:26:55 +00:00
" MemoryCards " , " UsePlaylistTitle " , true ) ;
2022-07-11 13:03:29 +00:00
2022-08-25 15:26:55 +00:00
for ( u32 i = 0 ; i < 2 ; i + + )
2021-01-30 11:37:49 +00:00
{
2023-12-13 11:06:15 +00:00
MenuHeading ( TinyString : : from_format ( FSUI_FSTR ( " Memory Card Port {} " ) , i + 1 ) ) ;
2021-01-30 11:37:49 +00:00
2022-08-25 15:26:55 +00:00
const MemoryCardType default_type =
( i = = 0 ) ? Settings : : DEFAULT_MEMORY_CARD_1_TYPE : Settings : : DEFAULT_MEMORY_CARD_2_TYPE ;
2023-08-20 02:38:55 +00:00
DrawEnumSetting (
2023-12-13 11:06:15 +00:00
bsi , TinyString : : from_format ( fmt : : runtime ( FSUI_ICONSTR ( ICON_FA_SD_CARD , " Memory Card {} Type " ) ) , i + 1 ) ,
SmallString : : from_format ( FSUI_FSTR ( " Sets which sort of memory card image will be used for slot {}. " ) , i + 1 ) ,
2023-08-20 02:38:55 +00:00
" MemoryCards " , type_keys [ i ] , default_type , & Settings : : ParseMemoryCardTypeName , & Settings : : GetMemoryCardTypeName ,
& Settings : : GetMemoryCardTypeDisplayName , MemoryCardType : : Count ) ;
2021-01-30 11:37:49 +00:00
2022-08-25 15:26:55 +00:00
const MemoryCardType effective_type =
Settings : : ParseMemoryCardTypeName (
2024-04-07 10:43:13 +00:00
GetEffectiveTinyStringSetting ( bsi , " MemoryCards " , type_keys [ i ] , Settings : : GetMemoryCardTypeName ( default_type ) )
2022-08-25 15:26:55 +00:00
. c_str ( ) )
. value_or ( default_type ) ;
const bool is_shared = ( effective_type = = MemoryCardType : : Shared ) ;
2024-04-07 10:43:13 +00:00
std : : optional < SmallString > path_value ( bsi - > GetOptionalSmallStringValue (
2022-08-25 15:26:55 +00:00
" MemoryCards " , path_keys [ i ] ,
IsEditingGameSettings ( bsi ) ? std : : nullopt :
std : : optional < const char * > ( ( i = = 0 ) ? " shared_card_1.mcd " : " shared_card_2.mcd " ) ) ) ;
TinyString title ;
2023-12-13 11:06:15 +00:00
title . format ( " {}##card_name_{} " , FSUI_ICONSTR ( ICON_FA_FILE , " Shared Card Name " ) , i ) ;
2023-08-20 02:38:55 +00:00
if ( MenuButtonWithValue ( title ,
FSUI_CSTR ( " The selected memory card image will be used in shared mode for this slot. " ) ,
2023-11-30 04:21:44 +00:00
path_value . has_value ( ) ? path_value - > c_str ( ) : FSUI_CSTR ( " Use Global Setting " ) , is_shared ) )
2022-08-25 15:26:55 +00:00
{
ImGuiFullscreen : : ChoiceDialogOptions options ;
std : : vector < std : : string > names ;
if ( IsEditingGameSettings ( bsi ) )
options . emplace_back ( " Use Global Setting " , ! path_value . has_value ( ) ) ;
if ( path_value . has_value ( ) & & ! path_value - > empty ( ) )
{
options . emplace_back ( fmt : : format ( " {} (Current) " , path_value . value ( ) ) , true ) ;
2024-04-07 10:43:13 +00:00
names . emplace_back ( path_value . value ( ) . view ( ) ) ;
2022-08-25 15:26:55 +00:00
}
FileSystem : : FindResultsArray results ;
FileSystem : : FindFiles ( EmuFolders : : MemoryCards . c_str ( ) , " *.mcd " ,
FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_HIDDEN_FILES | FILESYSTEM_FIND_RELATIVE_PATHS ,
& results ) ;
for ( FILESYSTEM_FIND_DATA & ffd : results )
{
2024-04-07 10:43:13 +00:00
const bool selected = ( path_value . has_value ( ) & & path_value . value ( ) = = ffd . FileName ) ;
2022-08-25 15:26:55 +00:00
options . emplace_back ( std : : move ( ffd . FileName ) , selected ) ;
}
OpenChoiceDialog (
title , false , std : : move ( options ) ,
[ game_settings = IsEditingGameSettings ( bsi ) , i ] ( s32 index , const std : : string & title , bool checked ) {
if ( index < 0 )
return ;
auto lock = Host : : GetSettingsLock ( ) ;
SettingsInterface * bsi = GetEditingSettingsInterface ( game_settings ) ;
if ( game_settings & & index = = 0 )
{
bsi - > DeleteValue ( " MemoryCards " , path_keys [ i ] ) ;
}
else
{
if ( game_settings )
index - - ;
bsi - > SetStringValue ( " MemoryCards " , path_keys [ i ] , title . c_str ( ) ) ;
}
SetSettingsChanged ( bsi ) ;
CloseChoiceDialog ( ) ;
} ) ;
}
}
EndMenuButtons ( ) ;
}
void FullscreenUI : : DrawDisplaySettingsPage ( )
{
2023-10-02 03:33:33 +00:00
static constexpr const std : : array resolution_scales = {
FSUI_NSTR ( " Automatic based on window size " ) ,
FSUI_NSTR ( " 1x " ) ,
FSUI_NSTR ( " 2x " ) ,
FSUI_NSTR ( " 3x (for 720p) " ) ,
FSUI_NSTR ( " 4x " ) ,
FSUI_NSTR ( " 5x (for 1080p) " ) ,
FSUI_NSTR ( " 6x (for 1440p) " ) ,
FSUI_NSTR ( " 7x " ) ,
FSUI_NSTR ( " 8x " ) ,
FSUI_NSTR ( " 9x (for 4K) " ) ,
FSUI_NSTR ( " 10x " ) ,
FSUI_NSTR ( " 11x " ) ,
FSUI_NSTR ( " 12x " ) ,
FSUI_NSTR ( " 13x " ) ,
FSUI_NSTR ( " 14x " ) ,
FSUI_NSTR ( " 15x " ) ,
FSUI_NSTR ( " 16x " ) ,
} ;
2022-08-25 15:26:55 +00:00
SettingsInterface * bsi = GetEditingSettingsInterface ( ) ;
2022-08-29 09:19:50 +00:00
const bool game_settings = IsEditingGameSettings ( bsi ) ;
2022-08-25 15:26:55 +00:00
BeginMenuButtons ( ) ;
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " Device Settings " ) ) ;
2022-07-11 13:03:29 +00:00
2023-08-20 02:38:55 +00:00
DrawEnumSetting ( bsi , FSUI_CSTR ( " GPU Renderer " ) ,
FSUI_CSTR ( " Chooses the backend to use for rendering the console/game visuals. " ) , " GPU " , " Renderer " ,
Settings : : DEFAULT_GPU_RENDERER , & Settings : : ParseRendererName , & Settings : : GetRendererName ,
2022-07-11 13:03:29 +00:00
& Settings : : GetRendererDisplayName , GPURenderer : : Count ) ;
2022-08-29 09:19:50 +00:00
const GPURenderer renderer =
Settings : : ParseRendererName (
2024-04-07 10:43:13 +00:00
GetEffectiveTinyStringSetting ( bsi , " GPU " , " Renderer " , Settings : : GetRendererName ( Settings : : DEFAULT_GPU_RENDERER ) )
2022-08-29 09:19:50 +00:00
. c_str ( ) )
. value_or ( Settings : : DEFAULT_GPU_RENDERER ) ;
const bool is_hardware = ( renderer ! = GPURenderer : : Software ) ;
2021-07-13 12:39:55 +00:00
2024-04-07 10:43:13 +00:00
std : : optional < SmallString > strvalue =
bsi - > GetOptionalSmallStringValue ( " GPU " , " Adapter " , game_settings ? std : : nullopt : std : : optional < const char * > ( " " ) ) ;
2022-09-03 03:39:59 +00:00
2023-08-20 02:38:55 +00:00
if ( MenuButtonWithValue ( FSUI_CSTR ( " GPU Adapter " ) , FSUI_CSTR ( " Selects the GPU to use for rendering. " ) ,
2024-04-07 10:43:13 +00:00
strvalue . has_value ( ) ? ( strvalue - > empty ( ) ? FSUI_CSTR ( " Default " ) : strvalue - > c_str ( ) ) :
FSUI_CSTR ( " Use Global Setting " ) ) )
2021-01-30 11:37:49 +00:00
{
2023-08-13 03:42:02 +00:00
GPUDevice : : AdapterAndModeList aml ( g_gpu_device - > GetAdapterAndModeList ( ) ) ;
2022-07-11 13:03:29 +00:00
ImGuiFullscreen : : ChoiceDialogOptions options ;
2022-08-29 09:19:50 +00:00
options . reserve ( aml . adapter_names . size ( ) + 2 ) ;
if ( game_settings )
2024-04-07 10:43:13 +00:00
options . emplace_back ( FSUI_STR ( " Use Global Setting " ) , ! strvalue . has_value ( ) ) ;
options . emplace_back ( FSUI_STR ( " Default " ) , strvalue . has_value ( ) & & strvalue - > empty ( ) ) ;
2022-08-29 09:19:50 +00:00
for ( std : : string & mode : aml . adapter_names )
{
2024-04-07 10:43:13 +00:00
const bool checked = ( strvalue . has_value ( ) & & strvalue . value ( ) = = mode ) ;
2022-08-29 09:19:50 +00:00
options . emplace_back ( std : : move ( mode ) , checked ) ;
}
2022-07-11 13:03:29 +00:00
2022-08-29 09:19:50 +00:00
auto callback = [ game_settings ] ( s32 index , const std : : string & title , bool checked ) {
2022-07-11 13:03:29 +00:00
if ( index < 0 )
return ;
2022-08-29 09:19:50 +00:00
const char * value ;
if ( game_settings & & index = = 0 )
value = nullptr ;
else if ( ( ! game_settings & & index = = 0 ) | | ( game_settings & & index = = 1 ) )
value = " " ;
2021-01-30 11:37:49 +00:00
else
2022-08-29 09:19:50 +00:00
value = title . c_str ( ) ;
2021-01-30 11:37:49 +00:00
2022-08-29 09:19:50 +00:00
SettingsInterface * bsi = GetEditingSettingsInterface ( game_settings ) ;
if ( ! value )
bsi - > DeleteValue ( " GPU " , " Adapter " ) ;
else
bsi - > SetStringValue ( " GPU " , " Adapter " , value ) ;
SetSettingsChanged ( bsi ) ;
2023-08-20 02:38:55 +00:00
ShowToast ( std : : string ( ) , FSUI_STR ( " GPU adapter will be applied after restarting. " ) , 10.0f ) ;
2022-07-11 13:03:29 +00:00
CloseChoiceDialog ( ) ;
} ;
2023-08-20 02:38:55 +00:00
OpenChoiceDialog ( FSUI_ICONSTR ( ICON_FA_TV , " GPU Adapter " ) , false , std : : move ( options ) , std : : move ( callback ) ) ;
2021-01-30 11:37:49 +00:00
}
2024-04-07 10:43:13 +00:00
strvalue = bsi - > GetOptionalSmallStringValue ( " GPU " , " FullscreenMode " ,
game_settings ? std : : nullopt : std : : optional < const char * > ( " " ) ) ;
2022-08-25 15:26:55 +00:00
2023-08-20 02:38:55 +00:00
if ( MenuButtonWithValue (
FSUI_CSTR ( " Fullscreen Resolution " ) , FSUI_CSTR ( " Selects the resolution to use in fullscreen modes. " ) ,
2024-04-07 10:43:13 +00:00
strvalue . has_value ( ) ? ( strvalue - > empty ( ) ? FSUI_CSTR ( " Borderless Fullscreen " ) : strvalue - > c_str ( ) ) :
FSUI_CSTR ( " Use Global Setting " ) ) )
2022-08-29 09:19:50 +00:00
{
2023-08-13 03:42:02 +00:00
GPUDevice : : AdapterAndModeList aml ( g_gpu_device - > GetAdapterAndModeList ( ) ) ;
2022-08-25 15:26:55 +00:00
2022-08-29 09:19:50 +00:00
ImGuiFullscreen : : ChoiceDialogOptions options ;
options . reserve ( aml . fullscreen_modes . size ( ) + 2 ) ;
if ( game_settings )
2024-04-07 10:43:13 +00:00
options . emplace_back ( FSUI_STR ( " Use Global Setting " ) , ! strvalue . has_value ( ) ) ;
options . emplace_back ( FSUI_STR ( " Borderless Fullscreen " ) , strvalue . has_value ( ) & & strvalue - > empty ( ) ) ;
2022-08-29 09:19:50 +00:00
for ( std : : string & mode : aml . fullscreen_modes )
{
2024-04-07 10:43:13 +00:00
const bool checked = ( strvalue . has_value ( ) & & strvalue . value ( ) = = mode ) ;
2022-08-29 09:19:50 +00:00
options . emplace_back ( std : : move ( mode ) , checked ) ;
}
2022-08-25 15:26:55 +00:00
2022-08-29 09:19:50 +00:00
auto callback = [ game_settings ] ( s32 index , const std : : string & title , bool checked ) {
if ( index < 0 )
return ;
2022-08-25 15:26:55 +00:00
2022-08-29 09:19:50 +00:00
const char * value ;
if ( game_settings & & index = = 0 )
value = nullptr ;
else if ( ( ! game_settings & & index = = 0 ) | | ( game_settings & & index = = 1 ) )
value = " " ;
else
value = title . c_str ( ) ;
2022-08-25 15:26:55 +00:00
2022-08-29 09:19:50 +00:00
SettingsInterface * bsi = GetEditingSettingsInterface ( game_settings ) ;
if ( ! value )
bsi - > DeleteValue ( " GPU " , " FullscreenMode " ) ;
else
bsi - > SetStringValue ( " GPU " , " FullscreenMode " , value ) ;
SetSettingsChanged ( bsi ) ;
2023-08-20 02:38:55 +00:00
ShowToast ( std : : string ( ) , FSUI_STR ( " Resolution change will be applied after restarting. " ) , 10.0f ) ;
2022-08-29 09:19:50 +00:00
CloseChoiceDialog ( ) ;
} ;
2023-08-20 02:38:55 +00:00
OpenChoiceDialog ( FSUI_ICONSTR ( ICON_FA_TV , " Fullscreen Resolution " ) , false , std : : move ( options ) , std : : move ( callback ) ) ;
2022-08-29 09:19:50 +00:00
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
switch ( renderer )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
# ifdef _WIN32
case GPURenderer : : HardwareD3D11 :
{
2023-08-20 02:38:55 +00:00
DrawToggleSetting (
bsi , FSUI_CSTR ( " Use Blit Swap Chain " ) ,
FSUI_CSTR ( " Uses a blit presentation model instead of flipping. This may be needed on some systems. " ) , " Display " ,
" UseBlitSwapChain " , false ) ;
2022-07-11 13:03:29 +00:00
}
break ;
# endif
2021-01-30 11:37:49 +00:00
2023-09-17 02:28:11 +00:00
# ifdef ENABLE_VULKAN
2022-07-11 13:03:29 +00:00
case GPURenderer : : HardwareVulkan :
2021-01-30 11:37:49 +00:00
{
2023-08-20 02:38:55 +00:00
DrawToggleSetting ( bsi , FSUI_CSTR ( " Threaded Presentation " ) ,
FSUI_CSTR ( " Presents frames on a background thread when fast forwarding or vsync is disabled. " ) ,
" GPU " , " ThreadedPresentation " , true ) ;
2022-07-11 13:03:29 +00:00
}
break ;
2022-07-30 15:06:40 +00:00
# endif
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
case GPURenderer : : Software :
{
2023-08-20 02:38:55 +00:00
DrawToggleSetting ( bsi , FSUI_CSTR ( " Threaded Rendering " ) ,
FSUI_CSTR ( " Uses a second thread for drawing graphics. Speed boost, and safe to use. " ) , " GPU " ,
" UseThread " , true ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
break ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
default :
break ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
if ( renderer ! = GPURenderer : : Software )
2021-01-30 11:37:49 +00:00
{
2023-08-20 02:38:55 +00:00
DrawToggleSetting (
bsi , FSUI_CSTR ( " Use Software Renderer For Readbacks " ) ,
FSUI_CSTR ( " Runs the software renderer in parallel for VRAM readbacks. On some systems, this may result "
" in greater performance. " ) ,
" GPU " , " UseSoftwareRendererForReadbacks " , false ) ;
2021-01-30 11:37:49 +00:00
}
2023-09-16 09:06:59 +00:00
MenuHeading ( FSUI_CSTR ( " Rendering " ) ) ;
2022-08-29 09:19:50 +00:00
DrawIntListSetting (
2024-03-02 09:08:38 +00:00
bsi , FSUI_CSTR ( " Internal Resolution " ) ,
2023-08-20 02:38:55 +00:00
FSUI_CSTR ( " Scales internal VRAM resolution by the specified multiplier. Some games require 1x VRAM resolution. " ) ,
2023-09-03 03:20:38 +00:00
" GPU " , " ResolutionScale " , 1 , resolution_scales . data ( ) , resolution_scales . size ( ) , true , 0 , is_hardware ) ;
2023-08-20 02:38:55 +00:00
DrawEnumSetting (
bsi , FSUI_CSTR ( " Texture Filtering " ) , FSUI_CSTR ( " Smooths out the blockiness of magnified textures on 3D objects. " ) ,
" GPU " , " TextureFilter " , Settings : : DEFAULT_GPU_TEXTURE_FILTER , & Settings : : ParseTextureFilterName ,
& Settings : : GetTextureFilterName , & Settings : : GetTextureFilterDisplayName , GPUTextureFilter : : Count , is_hardware ) ;
2024-03-02 05:50:46 +00:00
DrawEnumSetting ( bsi , FSUI_CSTR ( " Line Detection " ) ,
FSUI_CSTR ( " Attempts to detect one pixel high/wide lines that rely on non-upscaled rasterization "
" behavior, filling in gaps introduced by upscaling. " ) ,
" GPU " , " LineDetectMode " , Settings : : DEFAULT_GPU_LINE_DETECT_MODE , & Settings : : ParseLineDetectModeName ,
& Settings : : GetLineDetectModeName , & Settings : : GetLineDetectModeDisplayName , GPULineDetectMode : : Count ,
is_hardware ) ;
2023-08-20 02:38:55 +00:00
DrawToggleSetting ( bsi , FSUI_CSTR ( " True Color Rendering " ) ,
FSUI_CSTR ( " Disables dithering and uses the full 8 bits per channel of color information. " ) , " GPU " ,
" TrueColor " , true , is_hardware ) ;
2022-08-29 09:19:50 +00:00
2024-01-20 10:09:32 +00:00
DrawToggleSetting (
bsi , FSUI_CSTR ( " True Color Debanding " ) ,
FSUI_CSTR ( " Applies modern dithering techniques to further smooth out gradients when true color is enabled. " ) , " GPU " ,
" Debanding " , false , is_hardware & & bsi - > GetBoolValue ( " GPU " , " TrueColor " , false ) ) ;
2024-01-18 22:33:37 +00:00
2023-11-28 16:08:19 +00:00
DrawToggleSetting ( bsi , FSUI_CSTR ( " Widescreen Hack " ) ,
2023-08-20 02:38:55 +00:00
FSUI_CSTR ( " Increases the field of view from 4:3 to the chosen display aspect ratio in 3D games. " ) ,
" GPU " , " WidescreenHack " , false , is_hardware ) ;
2022-08-29 09:19:50 +00:00
2023-08-20 02:38:55 +00:00
DrawToggleSetting (
bsi , FSUI_CSTR ( " PGXP Geometry Correction " ) ,
FSUI_CSTR ( " Reduces \" wobbly \" polygons by attempting to preserve the fractional component through memory "
" transfers. " ) ,
" GPU " , " PGXPEnable " , false ) ;
2022-08-29 09:19:50 +00:00
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " Screen Display " ) ) ;
2022-07-11 13:03:29 +00:00
2023-08-20 02:38:55 +00:00
DrawEnumSetting ( bsi , FSUI_CSTR ( " Aspect Ratio " ) ,
FSUI_CSTR ( " Changes the aspect ratio used to display the console's output to the screen. " ) , " Display " ,
" AspectRatio " , Settings : : DEFAULT_DISPLAY_ASPECT_RATIO , & Settings : : ParseDisplayAspectRatio ,
2023-08-20 03:25:43 +00:00
& Settings : : GetDisplayAspectRatioName , & Settings : : GetDisplayAspectRatioDisplayName ,
2022-07-11 13:03:29 +00:00
DisplayAspectRatio : : Count ) ;
2024-03-15 16:02:03 +00:00
DrawEnumSetting (
bsi , FSUI_CSTR ( " Deinterlacing Mode " ) ,
FSUI_CSTR (
" Determines which algorithm is used to convert interlaced frames to progressive for display on your system. " ) ,
" Display " , " DeinterlacingMode " , Settings : : DEFAULT_DISPLAY_DEINTERLACING_MODE ,
& Settings : : ParseDisplayDeinterlacingMode , & Settings : : GetDisplayDeinterlacingModeName ,
& Settings : : GetDisplayDeinterlacingModeDisplayName , DisplayDeinterlacingMode : : Count ) ;
2023-08-20 02:38:55 +00:00
DrawEnumSetting ( bsi , FSUI_CSTR ( " Crop Mode " ) ,
FSUI_CSTR ( " Determines how much of the area typically not visible on a consumer TV set to crop/hide. " ) ,
" Display " , " CropMode " , Settings : : DEFAULT_DISPLAY_CROP_MODE , & Settings : : ParseDisplayCropMode ,
2022-07-11 13:03:29 +00:00
& Settings : : GetDisplayCropModeName , & Settings : : GetDisplayCropModeDisplayName , DisplayCropMode : : Count ) ;
2023-08-20 02:38:55 +00:00
DrawEnumSetting (
bsi , FSUI_CSTR ( " Position " ) , FSUI_CSTR ( " Determines the position on the screen when black borders must be added. " ) ,
" Display " , " Alignment " , Settings : : DEFAULT_DISPLAY_ALIGNMENT , & Settings : : ParseDisplayAlignment ,
2023-08-31 13:37:17 +00:00
& Settings : : GetDisplayAlignmentName , & Settings : : GetDisplayAlignmentDisplayName , DisplayAlignment : : Count ) ;
2022-10-13 07:40:58 +00:00
2023-08-20 02:38:55 +00:00
DrawEnumSetting ( bsi , FSUI_CSTR ( " Downsampling " ) ,
FSUI_CSTR ( " Downsamples the rendered image prior to displaying it. Can improve "
" overall image quality in mixed 2D/3D games. " ) ,
2022-07-11 13:03:29 +00:00
" GPU " , " DownsampleMode " , Settings : : DEFAULT_GPU_DOWNSAMPLE_MODE , & Settings : : ParseDownsampleModeName ,
& Settings : : GetDownsampleModeName , & Settings : : GetDownsampleModeDisplayName , GPUDownsampleMode : : Count ,
( renderer ! = GPURenderer : : Software ) ) ;
2023-09-03 07:10:40 +00:00
if ( Settings : : ParseDownsampleModeName (
2024-04-07 10:43:13 +00:00
GetEffectiveTinyStringSetting ( bsi , " GPU " , " DownsampleMode " ,
Settings : : GetDownsampleModeName ( Settings : : DEFAULT_GPU_DOWNSAMPLE_MODE ) )
2023-09-03 07:10:40 +00:00
. c_str ( ) )
. value_or ( Settings : : DEFAULT_GPU_DOWNSAMPLE_MODE ) = = GPUDownsampleMode : : Box )
{
DrawIntRangeSetting ( bsi , FSUI_CSTR ( " Downsampling Display Scale " ) ,
FSUI_CSTR ( " Selects the resolution scale that will be applied to the final image. 1x will "
" downsample to the original console resolution. " ) ,
" GPU " , " DownsampleScale " , 1 , 1 , GPU : : MAX_RESOLUTION_SCALE , " %dx " ) ;
}
2022-07-11 13:03:29 +00:00
2023-08-31 13:37:17 +00:00
DrawEnumSetting (
bsi , FSUI_CSTR ( " Scaling " ) ,
FSUI_CSTR ( " Determines how the emulated console's output is upscaled or downscaled to your monitor's resolution. " ) ,
" Display " , " Scaling " , Settings : : DEFAULT_DISPLAY_SCALING , & Settings : : ParseDisplayScaling ,
& Settings : : GetDisplayScalingName , & Settings : : GetDisplayScalingDisplayName , DisplayScalingMode : : Count ) ;
2022-07-11 13:03:29 +00:00
2024-03-02 09:08:38 +00:00
DrawEnumSetting ( bsi , FSUI_CSTR ( " Screenshot Size " ) ,
FSUI_CSTR ( " Determines the size of screenshots created by DuckStation. " ) , " Display " , " ScreenshotMode " ,
Settings : : DEFAULT_DISPLAY_SCREENSHOT_MODE , & Settings : : ParseDisplayScreenshotMode ,
& Settings : : GetDisplayScreenshotModeName , & Settings : : GetDisplayScreenshotModeDisplayName ,
DisplayScreenshotMode : : Count ) ;
DrawEnumSetting ( bsi , FSUI_CSTR ( " Screenshot Format " ) ,
FSUI_CSTR ( " Determines the format that screenshots will be saved/compressed with. " ) , " Display " ,
" ScreenshotFormat " , Settings : : DEFAULT_DISPLAY_SCREENSHOT_FORMAT ,
& Settings : : ParseDisplayScreenshotFormat , & Settings : : GetDisplayScreenshotFormatName ,
& Settings : : GetDisplayScreenshotFormatDisplayName , DisplayScreenshotFormat : : Count ) ;
DrawIntRangeSetting ( bsi , FSUI_CSTR ( " Screenshot Quality " ) ,
FSUI_CSTR ( " Selects the quality at which screenshots will be compressed. " ) , " Display " ,
" ScreenshotQuality " , Settings : : DEFAULT_DISPLAY_SCREENSHOT_QUALITY , 1 , 100 , " %d%% " ) ;
2022-07-11 13:03:29 +00:00
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " Enhancements " ) ) ;
DrawToggleSetting (
bsi , FSUI_CSTR ( " Scaled Dithering " ) ,
FSUI_CSTR ( " Scales the dithering pattern with the internal rendering resolution, making it less noticeable. "
" Usually safe to enable. " ) ,
" GPU " , " ScaledDithering " , true , is_hardware ) ;
DrawToggleSetting (
bsi , FSUI_CSTR ( " Disable Interlacing " ) ,
FSUI_CSTR ( " Disables interlaced rendering and display in the GPU. Some games can render in 480p this way, "
" but others will break. " ) ,
" GPU " , " DisableInterlacing " , true ) ;
DrawToggleSetting (
bsi , FSUI_CSTR ( " Force NTSC Timings " ) ,
FSUI_CSTR ( " Forces PAL games to run at NTSC timings, i.e. 60hz. Some PAL games will run at their \" normal \" "
" speeds, while others will break. " ) ,
" GPU " , " ForceNTSCTimings " , false ) ;
DrawToggleSetting (
bsi , FSUI_CSTR ( " Force 4:3 For 24-Bit Display " ) ,
FSUI_CSTR ( " Switches back to 4:3 display aspect ratio when displaying 24-bit content, usually FMVs. " ) , " Display " ,
" Force4_3For24Bit " , false ) ;
DrawToggleSetting ( bsi , FSUI_CSTR ( " Chroma Smoothing For 24-Bit Display " ) ,
FSUI_CSTR ( " Smooths out blockyness between colour transitions in 24-bit content, usually FMVs. Only "
" applies to the hardware renderers. " ) ,
2022-07-11 13:03:29 +00:00
" GPU " , " ChromaSmoothing24Bit " , false ) ;
2023-09-16 09:06:59 +00:00
MenuHeading ( FSUI_CSTR ( " PGXP (Precision Geometry Transform Pipeline) " ) ) ;
2022-07-11 13:03:29 +00:00
2022-08-25 15:26:55 +00:00
const bool pgxp_enabled = GetEffectiveBoolSetting ( bsi , " GPU " , " PGXPEnable " , false ) ;
const bool texture_correction_enabled = GetEffectiveBoolSetting ( bsi , " GPU " , " PGXPTextureCorrection " , true ) ;
2022-10-03 10:03:30 +00:00
DrawToggleSetting (
2023-08-20 02:38:55 +00:00
bsi , FSUI_CSTR ( " Perspective Correct Textures " ) ,
FSUI_CSTR ( " Uses perspective-correct interpolation for texture coordinates, straightening out warped textures. " ) ,
" GPU " , " PGXPTextureCorrection " , true , pgxp_enabled ) ;
DrawToggleSetting (
bsi , FSUI_CSTR ( " Perspective Correct Colors " ) ,
FSUI_CSTR ( " Uses perspective-correct interpolation for colors, which can improve visuals in some games. " ) , " GPU " ,
" PGXPColorCorrection " , false , pgxp_enabled ) ;
DrawToggleSetting ( bsi , FSUI_CSTR ( " Culling Correction " ) ,
FSUI_CSTR ( " Increases the precision of polygon culling, reducing the number of holes in geometry. " ) ,
" GPU " , " PGXPCulling " , true , pgxp_enabled ) ;
DrawToggleSetting (
bsi , FSUI_CSTR ( " Preserve Projection Precision " ) ,
FSUI_CSTR ( " Adds additional precision to PGXP data post-projection. May improve visuals in some games. " ) , " GPU " ,
" PGXPPreserveProjFP " , false , pgxp_enabled ) ;
DrawToggleSetting ( bsi , FSUI_CSTR ( " Depth Buffer " ) ,
FSUI_CSTR ( " Reduces polygon Z-fighting through depth testing. Low compatibility with games. " ) , " GPU " ,
2022-07-11 13:03:29 +00:00
" PGXPDepthBuffer " , false , pgxp_enabled & & texture_correction_enabled ) ;
2023-08-20 02:38:55 +00:00
DrawToggleSetting ( bsi , FSUI_CSTR ( " CPU Mode " ) ,
FSUI_CSTR ( " Uses PGXP for all instructions, not just memory operations. " ) , " GPU " , " PGXPCPU " , false ,
pgxp_enabled ) ;
2022-08-25 15:26:55 +00:00
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " Texture Replacements " ) ) ;
2022-08-25 15:26:55 +00:00
2023-08-20 02:38:55 +00:00
DrawToggleSetting ( bsi , FSUI_CSTR ( " Enable VRAM Write Texture Replacement " ) ,
FSUI_CSTR ( " Enables the replacement of background textures in supported games. " ) ,
" TextureReplacements " , " EnableVRAMWriteReplacements " , false ) ;
DrawToggleSetting ( bsi , FSUI_CSTR ( " Preload Replacement Textures " ) ,
FSUI_CSTR ( " Loads all replacement texture to RAM, reducing stuttering at runtime. " ) ,
" TextureReplacements " , " PreloadTextures " , false ) ;
2022-07-11 13:03:29 +00:00
EndMenuButtons ( ) ;
2021-01-30 11:37:49 +00:00
}
2023-08-27 12:48:40 +00:00
void FullscreenUI : : PopulatePostProcessingChain ( SettingsInterface * si )
2022-10-13 14:14:21 +00:00
{
2023-08-27 12:48:40 +00:00
const u32 stages = PostProcessing : : Config : : GetStageCount ( * si ) ;
s_postprocessing_stages . reserve ( stages ) ;
for ( u32 i = 0 ; i < stages ; i + + )
{
PostProcessingStageInfo psi ;
psi . name = PostProcessing : : Config : : GetStageShaderName ( * si , i ) ;
psi . options = PostProcessing : : Config : : GetStageOptions ( * si , i ) ;
s_postprocessing_stages . push_back ( std : : move ( psi ) ) ;
}
2022-10-13 14:14:21 +00:00
}
2022-12-03 19:26:24 +00:00
enum
{
POSTPROCESSING_ACTION_NONE = 0 ,
POSTPROCESSING_ACTION_REMOVE ,
POSTPROCESSING_ACTION_MOVE_UP ,
POSTPROCESSING_ACTION_MOVE_DOWN ,
} ;
2022-10-13 14:14:21 +00:00
void FullscreenUI : : DrawPostProcessingSettingsPage ( )
{
SettingsInterface * bsi = GetEditingSettingsInterface ( ) ;
BeginMenuButtons ( ) ;
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " Controls " ) ) ;
2022-10-13 14:14:21 +00:00
2023-08-20 02:38:55 +00:00
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_MAGIC , " Enable Post Processing " ) ,
FSUI_CSTR ( " If not enabled, the current post processing chain will be ignored. " ) , " Display " ,
" PostProcessing " , false ) ;
2022-10-13 14:14:21 +00:00
2023-08-20 02:38:55 +00:00
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_SEARCH , " Reload Shaders " ) ,
FSUI_CSTR ( " Reloads the shaders from disk, applying any changes. " ) ,
2022-10-13 14:14:21 +00:00
bsi - > GetBoolValue ( " Display " , " PostProcessing " , false ) ) )
{
2023-08-27 12:48:40 +00:00
if ( System : : IsValid ( ) & & PostProcessing : : ReloadShaders ( ) )
2023-08-20 02:38:55 +00:00
ShowToast ( std : : string ( ) , FSUI_STR ( " Post-processing shaders reloaded. " ) ) ;
2022-10-13 14:14:21 +00:00
}
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " Operations " ) ) ;
2022-10-13 14:14:21 +00:00
2023-08-20 02:38:55 +00:00
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_PLUS , " Add Shader " ) , FSUI_CSTR ( " Adds a new shader to the chain. " ) ) )
2022-10-13 14:14:21 +00:00
{
2023-08-27 12:48:40 +00:00
std : : vector < std : : pair < std : : string , std : : string > > shaders = PostProcessing : : GetAvailableShaderNames ( ) ;
2022-10-13 14:14:21 +00:00
ImGuiFullscreen : : ChoiceDialogOptions options ;
2023-08-27 12:48:40 +00:00
options . reserve ( shaders . size ( ) ) ;
for ( auto & [ display_name , name ] : shaders )
options . emplace_back ( std : : move ( display_name ) , false ) ;
2022-10-13 14:14:21 +00:00
2023-08-20 02:38:55 +00:00
OpenChoiceDialog ( FSUI_ICONSTR ( ICON_FA_PLUS , " Add Shader " ) , false , std : : move ( options ) ,
2023-08-27 12:48:40 +00:00
[ shaders = std : : move ( shaders ) ] ( s32 index , const std : : string & title , bool checked ) {
if ( index < 0 | | static_cast < u32 > ( index ) > = shaders . size ( ) )
2023-08-20 02:38:55 +00:00
return ;
2022-10-13 14:14:21 +00:00
2023-08-27 12:48:40 +00:00
const std : : string & shader_name = shaders [ index ] . second ;
SettingsInterface * bsi = GetEditingSettingsInterface ( ) ;
Error error ;
if ( PostProcessing : : Config : : AddStage ( * bsi , shader_name , & error ) )
2023-08-20 02:38:55 +00:00
{
ShowToast ( std : : string ( ) , fmt : : format ( FSUI_FSTR ( " Shader {} added as stage {}. " ) , title ,
2023-08-27 12:48:40 +00:00
PostProcessing : : Config : : GetStageCount ( * bsi ) ) ) ;
PopulatePostProcessingChain ( bsi ) ;
SetSettingsChanged ( bsi ) ;
2023-08-20 02:38:55 +00:00
}
else
{
ShowToast ( std : : string ( ) ,
2023-08-27 12:48:40 +00:00
fmt : : format ( FSUI_FSTR ( " Failed to load shader {}. It may be invalid. \n Error was: " ) ,
title , error . GetDescription ( ) ) ) ;
2023-08-20 02:38:55 +00:00
}
2022-10-13 14:14:21 +00:00
2023-08-20 02:38:55 +00:00
CloseChoiceDialog ( ) ;
} ) ;
2022-10-13 14:14:21 +00:00
}
2023-08-20 02:38:55 +00:00
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_TIMES , " Clear Shaders " ) , FSUI_CSTR ( " Clears a shader from the chain. " ) ) )
2022-10-13 14:14:21 +00:00
{
OpenConfirmMessageDialog (
2023-08-20 02:38:55 +00:00
FSUI_ICONSTR ( ICON_FA_TIMES , " Clear Shaders " ) ,
FSUI_CSTR ( " Are you sure you want to clear the current post-processing chain? All configuration will be lost. " ) ,
2022-10-13 14:14:21 +00:00
[ ] ( bool confirmed ) {
if ( ! confirmed )
return ;
2023-08-27 12:48:40 +00:00
SettingsInterface * bsi = GetEditingSettingsInterface ( ) ;
PostProcessing : : Config : : ClearStages ( * bsi ) ;
PopulatePostProcessingChain ( bsi ) ;
SetSettingsChanged ( bsi ) ;
2023-08-20 02:38:55 +00:00
ShowToast ( std : : string ( ) , FSUI_STR ( " Post-processing chain cleared. " ) ) ;
2022-10-13 14:14:21 +00:00
} ) ;
}
2022-12-03 19:26:24 +00:00
u32 postprocessing_action = POSTPROCESSING_ACTION_NONE ;
2022-12-20 11:26:19 +00:00
u32 postprocessing_action_index = 0 ;
2022-12-03 19:26:24 +00:00
2022-10-13 14:14:21 +00:00
SmallString str ;
SmallString tstr ;
2023-08-27 12:48:40 +00:00
for ( u32 stage_index = 0 ; stage_index < static_cast < u32 > ( s_postprocessing_stages . size ( ) ) ; stage_index + + )
2022-10-13 14:14:21 +00:00
{
2023-08-27 12:48:40 +00:00
PostProcessingStageInfo & si = s_postprocessing_stages [ stage_index ] ;
2022-12-03 19:26:24 +00:00
ImGui : : PushID ( stage_index ) ;
2023-12-13 11:06:15 +00:00
str . format ( FSUI_FSTR ( " Stage {}: {} " ) , stage_index + 1 , si . name ) ;
2022-10-13 14:14:21 +00:00
MenuHeading ( str ) ;
2023-08-20 02:38:55 +00:00
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_TIMES , " Remove From Chain " ) , FSUI_CSTR ( " Removes this shader from the chain. " ) ) )
2022-10-13 14:14:21 +00:00
{
2022-12-03 19:26:24 +00:00
postprocessing_action = POSTPROCESSING_ACTION_REMOVE ;
postprocessing_action_index = stage_index ;
2022-10-13 14:14:21 +00:00
}
2023-08-20 02:38:55 +00:00
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_ARROW_UP , " Move Up " ) ,
FSUI_CSTR ( " Moves this shader higher in the chain, applying it earlier. " ) , ( stage_index > 0 ) ) )
2022-10-13 14:14:21 +00:00
{
2022-12-03 19:26:24 +00:00
postprocessing_action = POSTPROCESSING_ACTION_MOVE_UP ;
postprocessing_action_index = stage_index ;
2022-10-13 14:14:21 +00:00
}
2023-08-20 02:38:55 +00:00
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_ARROW_DOWN , " Move Down " ) ,
FSUI_CSTR ( " Moves this shader lower in the chain, applying it later. " ) ,
2023-08-27 12:48:40 +00:00
( stage_index ! = ( s_postprocessing_stages . size ( ) - 1 ) ) ) )
2022-10-13 14:14:21 +00:00
{
2022-12-03 19:26:24 +00:00
postprocessing_action = POSTPROCESSING_ACTION_MOVE_DOWN ;
postprocessing_action_index = stage_index ;
2022-10-13 14:14:21 +00:00
}
2023-08-27 12:48:40 +00:00
for ( PostProcessing : : ShaderOption & opt : si . options )
2022-10-13 14:14:21 +00:00
{
2023-08-27 12:48:40 +00:00
if ( opt . ui_name . empty ( ) )
continue ;
2022-10-13 14:14:21 +00:00
switch ( opt . type )
{
2023-08-27 12:48:40 +00:00
case PostProcessing : : ShaderOption : : Type : : Bool :
2022-10-13 14:14:21 +00:00
{
bool value = ( opt . value [ 0 ] . int_value ! = 0 ) ;
2023-12-13 11:06:15 +00:00
tstr . format ( ICON_FA_COGS " {} " , opt . ui_name ) ;
2023-08-20 02:38:55 +00:00
if ( ToggleButton ( tstr ,
( opt . default_value [ 0 ] . int_value ! = 0 ) ? FSUI_CSTR ( " Default: Enabled " ) :
FSUI_CSTR ( " Default: Disabled " ) ,
& value ) )
2022-10-13 14:14:21 +00:00
{
opt . value [ 0 ] . int_value = ( value ! = 0 ) ;
2023-08-27 12:48:40 +00:00
PostProcessing : : Config : : SetStageOption ( * bsi , stage_index , opt ) ;
SetSettingsChanged ( bsi ) ;
2022-10-13 14:14:21 +00:00
}
}
break ;
2023-08-27 12:48:40 +00:00
case PostProcessing : : ShaderOption : : Type : : Float :
2022-10-13 14:14:21 +00:00
{
2023-12-13 11:06:15 +00:00
tstr . format ( ICON_FA_RULER_VERTICAL " {}##{} " , opt . ui_name , opt . name ) ;
str . format ( FSUI_FSTR ( " Value: {} | Default: {} | Minimum: {} | Maximum: {} " ) , opt . value [ 0 ] . float_value ,
2023-12-14 06:07:57 +00:00
opt . default_value [ 0 ] . float_value , opt . min_value [ 0 ] . float_value , opt . max_value [ 0 ] . float_value ) ;
2022-10-13 14:14:21 +00:00
if ( MenuButton ( tstr , str ) )
ImGui : : OpenPopup ( tstr ) ;
ImGui : : SetNextWindowSize ( LayoutScale ( 500.0f , 190.0f ) ) ;
ImGui : : SetNextWindowPos ( ImGui : : GetIO ( ) . DisplaySize * 0.5f , ImGuiCond_Always , ImVec2 ( 0.5f , 0.5f ) ) ;
ImGui : : PushFont ( g_large_font ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowRounding , LayoutScale ( 10.0f ) ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , LayoutScale ( ImGuiFullscreen : : LAYOUT_MENU_BUTTON_X_PADDING ,
ImGuiFullscreen : : LAYOUT_MENU_BUTTON_Y_PADDING ) ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowPadding , LayoutScale ( 20.0f , 20.0f ) ) ;
bool is_open = true ;
if ( ImGui : : BeginPopupModal ( tstr , & is_open ,
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove ) )
{
BeginMenuButtons ( ) ;
const float end = ImGui : : GetCurrentWindow ( ) - > WorkRect . GetWidth ( ) ;
#if 0
for ( u32 i = 0 ; i < opt . vector_size ; i + + )
{
static constexpr const char * components [ ] = { " X " , " Y " , " Z " , " W " } ;
if ( opt . vector_size = = 1 )
tstr . Assign ( " ##value " ) ;
else
tstr . Fmt ( " {}##value{} " , components [ i ] , i ) ;
ImGui : : SetNextItemWidth ( end ) ;
if ( ImGui : : SliderFloat ( tstr , & opt . value [ i ] . float_value , opt . min_value [ i ] . float_value ,
opt . max_value [ i ] . float_value , " %f " , ImGuiSliderFlags_NoInput ) )
{
SavePostProcessingChain ( ) ;
}
}
# else
ImGui : : SetNextItemWidth ( end ) ;
2023-08-27 12:48:40 +00:00
bool changed = false ;
2022-10-13 14:14:21 +00:00
switch ( opt . vector_size )
{
case 1 :
{
2023-08-27 12:48:40 +00:00
changed = ImGui : : SliderFloat ( " ##value " , & opt . value [ 0 ] . float_value , opt . min_value [ 0 ] . float_value ,
opt . max_value [ 0 ] . float_value ) ;
2022-10-13 14:14:21 +00:00
}
break ;
case 2 :
{
2023-08-27 12:48:40 +00:00
changed = ImGui : : SliderFloat2 ( " ##value " , & opt . value [ 0 ] . float_value , opt . min_value [ 0 ] . float_value ,
opt . max_value [ 0 ] . float_value ) ;
2022-10-13 14:14:21 +00:00
}
break ;
case 3 :
{
2023-08-27 12:48:40 +00:00
changed = ImGui : : SliderFloat3 ( " ##value " , & opt . value [ 0 ] . float_value , opt . min_value [ 0 ] . float_value ,
opt . max_value [ 0 ] . float_value ) ;
2022-10-13 14:14:21 +00:00
}
break ;
case 4 :
{
2023-08-27 12:48:40 +00:00
changed = ImGui : : SliderFloat4 ( " ##value " , & opt . value [ 0 ] . float_value , opt . min_value [ 0 ] . float_value ,
opt . max_value [ 0 ] . float_value ) ;
2022-10-13 14:14:21 +00:00
}
break ;
}
2023-08-27 12:48:40 +00:00
if ( changed )
{
PostProcessing : : Config : : SetStageOption ( * bsi , stage_index , opt ) ;
SetSettingsChanged ( bsi ) ;
}
2022-10-13 14:14:21 +00:00
# endif
ImGui : : SetCursorPosY ( ImGui : : GetCursorPosY ( ) + LayoutScale ( 10.0f ) ) ;
2023-08-20 02:38:55 +00:00
if ( MenuButtonWithoutSummary ( FSUI_CSTR ( " OK " ) , true , LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY , g_large_font ,
2022-10-13 14:14:21 +00:00
ImVec2 ( 0.5f , 0.0f ) ) )
{
ImGui : : CloseCurrentPopup ( ) ;
}
EndMenuButtons ( ) ;
ImGui : : EndPopup ( ) ;
}
ImGui : : PopStyleVar ( 3 ) ;
ImGui : : PopFont ( ) ;
}
break ;
2023-08-27 12:48:40 +00:00
case PostProcessing : : ShaderOption : : Type : : Int :
2022-10-13 14:14:21 +00:00
{
2023-12-13 11:06:15 +00:00
tstr . format ( ICON_FA_RULER_VERTICAL " {}##{} " , opt . ui_name , opt . name ) ;
str . format ( FSUI_FSTR ( " Value: {} | Default: {} | Minimum: {} | Maximum: {} " ) , opt . value [ 0 ] . int_value ,
2023-12-14 06:07:57 +00:00
opt . default_value [ 0 ] . int_value , opt . min_value [ 0 ] . int_value , opt . max_value [ 0 ] . int_value ) ;
2022-10-13 14:14:21 +00:00
if ( MenuButton ( tstr , str ) )
ImGui : : OpenPopup ( tstr ) ;
ImGui : : SetNextWindowSize ( LayoutScale ( 500.0f , 190.0f ) ) ;
ImGui : : SetNextWindowPos ( ImGui : : GetIO ( ) . DisplaySize * 0.5f , ImGuiCond_Always , ImVec2 ( 0.5f , 0.5f ) ) ;
ImGui : : PushFont ( g_large_font ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowRounding , LayoutScale ( 10.0f ) ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , LayoutScale ( ImGuiFullscreen : : LAYOUT_MENU_BUTTON_X_PADDING ,
ImGuiFullscreen : : LAYOUT_MENU_BUTTON_Y_PADDING ) ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowPadding , LayoutScale ( 20.0f , 20.0f ) ) ;
bool is_open = true ;
if ( ImGui : : BeginPopupModal ( tstr , & is_open ,
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove ) )
{
BeginMenuButtons ( ) ;
const float end = ImGui : : GetCurrentWindow ( ) - > WorkRect . GetWidth ( ) ;
#if 0
for ( u32 i = 0 ; i < opt . vector_size ; i + + )
{
static constexpr const char * components [ ] = { " X " , " Y " , " Z " , " W " } ;
if ( opt . vector_size = = 1 )
tstr . Assign ( " ##value " ) ;
else
tstr . Fmt ( " {}##value{} " , components [ i ] , i ) ;
ImGui : : SetNextItemWidth ( end ) ;
if ( ImGui : : SliderInt ( tstr , & opt . value [ i ] . int_value , opt . min_value [ i ] . int_value ,
opt . max_value [ i ] . int_value , " %d " , ImGuiSliderFlags_NoInput ) )
{
SavePostProcessingChain ( ) ;
}
}
# else
2023-08-27 12:48:40 +00:00
bool changed = false ;
2022-10-13 14:14:21 +00:00
ImGui : : SetNextItemWidth ( end ) ;
switch ( opt . vector_size )
{
case 1 :
{
2023-08-27 12:48:40 +00:00
changed = ImGui : : SliderInt ( " ##value " , & opt . value [ 0 ] . int_value , opt . min_value [ 0 ] . int_value ,
opt . max_value [ 0 ] . int_value ) ;
2022-10-13 14:14:21 +00:00
}
break ;
case 2 :
{
2023-08-27 12:48:40 +00:00
changed = ImGui : : SliderInt2 ( " ##value " , & opt . value [ 0 ] . int_value , opt . min_value [ 0 ] . int_value ,
opt . max_value [ 0 ] . int_value ) ;
2022-10-13 14:14:21 +00:00
}
break ;
case 3 :
{
2023-08-27 12:48:40 +00:00
changed = ImGui : : SliderInt2 ( " ##value " , & opt . value [ 0 ] . int_value , opt . min_value [ 0 ] . int_value ,
opt . max_value [ 0 ] . int_value ) ;
2022-10-13 14:14:21 +00:00
}
break ;
case 4 :
{
2023-08-27 12:48:40 +00:00
changed = ImGui : : SliderInt4 ( " ##value " , & opt . value [ 0 ] . int_value , opt . min_value [ 0 ] . int_value ,
opt . max_value [ 0 ] . int_value ) ;
2022-10-13 14:14:21 +00:00
}
break ;
}
2023-08-27 12:48:40 +00:00
if ( changed )
{
PostProcessing : : Config : : SetStageOption ( * bsi , stage_index , opt ) ;
SetSettingsChanged ( bsi ) ;
}
2022-10-13 14:14:21 +00:00
# endif
ImGui : : SetCursorPosY ( ImGui : : GetCursorPosY ( ) + LayoutScale ( 10.0f ) ) ;
2023-08-20 02:38:55 +00:00
if ( MenuButtonWithoutSummary ( FSUI_CSTR ( " OK " ) , true , LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY , g_large_font ,
2022-10-13 14:14:21 +00:00
ImVec2 ( 0.5f , 0.0f ) ) )
{
ImGui : : CloseCurrentPopup ( ) ;
}
EndMenuButtons ( ) ;
ImGui : : EndPopup ( ) ;
}
ImGui : : PopStyleVar ( 3 ) ;
ImGui : : PopFont ( ) ;
}
break ;
2023-09-03 04:30:26 +00:00
default :
break ;
2022-10-13 14:14:21 +00:00
}
}
2022-12-03 19:26:24 +00:00
ImGui : : PopID ( ) ;
}
switch ( postprocessing_action )
{
case POSTPROCESSING_ACTION_REMOVE :
{
2023-08-27 12:48:40 +00:00
const PostProcessingStageInfo & si = s_postprocessing_stages [ postprocessing_action_index ] ;
2023-08-20 02:38:55 +00:00
ShowToast ( std : : string ( ) ,
2023-08-27 12:48:40 +00:00
fmt : : format ( FSUI_FSTR ( " Removed stage {} ({}). " ) , postprocessing_action_index + 1 , si . name ) ) ;
PostProcessing : : Config : : RemoveStage ( * bsi , postprocessing_action_index ) ;
PopulatePostProcessingChain ( bsi ) ;
SetSettingsChanged ( bsi ) ;
2022-12-03 19:26:24 +00:00
}
break ;
case POSTPROCESSING_ACTION_MOVE_UP :
{
2023-08-27 12:48:40 +00:00
PostProcessing : : Config : : MoveStageUp ( * bsi , postprocessing_action_index ) ;
PopulatePostProcessingChain ( bsi ) ;
SetSettingsChanged ( bsi ) ;
2022-12-03 19:26:24 +00:00
}
break ;
case POSTPROCESSING_ACTION_MOVE_DOWN :
{
2023-08-27 12:48:40 +00:00
PostProcessing : : Config : : MoveStageDown ( * bsi , postprocessing_action_index ) ;
PopulatePostProcessingChain ( bsi ) ;
SetSettingsChanged ( bsi ) ;
2022-12-03 19:26:24 +00:00
}
break ;
default :
break ;
2022-10-13 14:14:21 +00:00
}
EndMenuButtons ( ) ;
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DrawAudioSettingsPage ( )
2021-01-30 11:37:49 +00:00
{
2022-08-25 15:26:55 +00:00
SettingsInterface * bsi = GetEditingSettingsInterface ( ) ;
2022-07-11 13:03:29 +00:00
BeginMenuButtons ( ) ;
2021-01-30 11:37:49 +00:00
2023-11-28 16:08:19 +00:00
MenuHeading ( FSUI_CSTR ( " Audio Control " ) ) ;
2022-07-11 13:03:29 +00:00
2023-08-20 02:38:55 +00:00
DrawIntRangeSetting ( bsi , FSUI_CSTR ( " Output Volume " ) ,
FSUI_CSTR ( " Controls the volume of the audio played on the host. " ) , " Audio " , " OutputVolume " , 100 ,
0 , 100 , " %d%% " ) ;
DrawIntRangeSetting ( bsi , FSUI_CSTR ( " Fast Forward Volume " ) ,
FSUI_CSTR ( " Controls the volume of the audio played on the host when fast forwarding. " ) , " Audio " ,
2022-07-11 13:03:29 +00:00
" FastForwardVolume " , 100 , 0 , 100 , " %d%% " ) ;
2023-08-20 02:38:55 +00:00
DrawToggleSetting ( bsi , FSUI_CSTR ( " Mute All Sound " ) ,
FSUI_CSTR ( " Prevents the emulator from producing any audible sound. " ) , " Audio " , " OutputMuted " ,
false ) ;
DrawToggleSetting ( bsi , FSUI_CSTR ( " Mute CD Audio " ) ,
FSUI_CSTR ( " Forcibly mutes both CD-DA and XA audio from the CD-ROM. Can be used to "
" disable background music in some games. " ) ,
2022-07-11 13:03:29 +00:00
" CDROM " , " MuteCDAudio " , false ) ;
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " Backend Settings " ) ) ;
2022-07-11 13:03:29 +00:00
2023-08-20 02:38:55 +00:00
DrawEnumSetting (
bsi , FSUI_CSTR ( " Audio Backend " ) ,
FSUI_CSTR ( " The audio backend determines how frames produced by the emulator are submitted to the host. " ) , " Audio " ,
" Backend " , Settings : : DEFAULT_AUDIO_BACKEND , & Settings : : ParseAudioBackend , & Settings : : GetAudioBackendName ,
& Settings : : GetAudioBackendDisplayName , AudioBackend : : Count ) ;
DrawEnumSetting ( bsi , FSUI_CSTR ( " Stretch Mode " ) ,
FSUI_CSTR ( " Determines quality of audio when not running at 100% speed. " ) , " Audio " , " StretchMode " ,
Settings : : DEFAULT_AUDIO_STRETCH_MODE , & AudioStream : : ParseStretchMode ,
2022-08-25 15:26:55 +00:00
& AudioStream : : GetStretchModeName , & AudioStream : : GetStretchModeDisplayName , AudioStretchMode : : Count ) ;
2023-08-20 02:38:55 +00:00
DrawIntRangeSetting ( bsi , FSUI_CSTR ( " Buffer Size " ) ,
FSUI_CSTR ( " Determines the amount of audio buffered before being pulled by the host API. " ) ,
" Audio " , " BufferMS " , Settings : : DEFAULT_AUDIO_BUFFER_MS , 10 , 500 , " %d ms " ) ;
2022-08-25 15:26:55 +00:00
const u32 output_latency =
GetEffectiveUIntSetting ( bsi , " Audio " , " OutputLatencyMS " , Settings : : DEFAULT_AUDIO_OUTPUT_LATENCY_MS ) ;
2022-07-29 12:29:25 +00:00
bool output_latency_minimal = ( output_latency = = 0 ) ;
2023-08-20 02:38:55 +00:00
if ( ToggleButton ( FSUI_CSTR ( " Minimal Output Latency " ) ,
FSUI_CSTR ( " When enabled, the minimum supported output latency will be used for the host API. " ) ,
2022-07-29 12:29:25 +00:00
& output_latency_minimal ) )
{
2022-08-25 15:26:55 +00:00
bsi - > SetUIntValue ( " Audio " , " OutputLatencyMS " ,
output_latency_minimal ? 0 : Settings : : DEFAULT_AUDIO_OUTPUT_LATENCY_MS ) ;
SetSettingsChanged ( bsi ) ;
2022-07-29 12:29:25 +00:00
}
if ( ! output_latency_minimal )
{
2023-08-20 02:38:55 +00:00
DrawIntRangeSetting (
bsi , FSUI_CSTR ( " Output Latency " ) ,
FSUI_CSTR ( " Determines how much latency there is between the audio being picked up by the host API, and "
" played through speakers. " ) ,
" Audio " , " OutputLatencyMS " , Settings : : DEFAULT_AUDIO_OUTPUT_LATENCY_MS , 1 , 500 , " %d ms " ) ;
2022-07-29 12:29:25 +00:00
}
2022-07-11 13:03:29 +00:00
EndMenuButtons ( ) ;
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DrawAchievementsSettingsPage ( )
{
2023-09-17 02:28:11 +00:00
# ifdef ENABLE_RAINTEGRATION
2022-08-25 15:26:55 +00:00
if ( Achievements : : IsUsingRAIntegration ( ) )
2022-07-11 13:03:29 +00:00
{
BeginMenuButtons ( ) ;
2023-08-20 02:38:55 +00:00
ActiveButton (
FSUI_ICONSTR ( ICON_FA_BAN ,
FSUI_CSTR ( " RAIntegration is being used instead of the built-in achievements implementation. " ) ) ,
false , false , LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ) ;
2022-07-11 13:03:29 +00:00
EndMenuButtons ( ) ;
2022-08-25 15:26:55 +00:00
return ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
# endif
2021-01-30 11:37:49 +00:00
2022-08-25 15:26:55 +00:00
SettingsInterface * bsi = GetEditingSettingsInterface ( ) ;
2021-01-30 11:37:49 +00:00
BeginMenuButtons ( ) ;
2023-09-16 09:06:59 +00:00
MenuHeading ( FSUI_CSTR ( " Settings " ) ) ;
2023-08-20 02:38:55 +00:00
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_TROPHY , " Enable Achievements " ) ,
FSUI_CSTR ( " When enabled and logged in, DuckStation will scan for achievements on startup. " ) ,
" Cheevos " , " Enabled " , false ) ;
2022-08-25 15:26:55 +00:00
const bool enabled = bsi - > GetBoolValue ( " Cheevos " , " Enabled " , false ) ;
2023-08-20 02:38:55 +00:00
if ( DrawToggleSetting (
bsi , FSUI_ICONSTR ( ICON_FA_HARD_HAT , " Hardcore Mode " ) ,
FSUI_CSTR ( " \" Challenge \" mode for achievements, including leaderboard tracking. Disables save state, "
" cheats, and slowdown functions. " ) ,
" Cheevos " , " ChallengeMode " , false , enabled ) )
2022-08-25 15:26:55 +00:00
{
if ( System : : IsValid ( ) & & bsi - > GetBoolValue ( " Cheevos " , " ChallengeMode " , false ) )
2023-09-07 10:13:48 +00:00
ShowToast ( std : : string ( ) , FSUI_STR ( " Hardcore mode will be enabled on next game restart. " ) ) ;
2022-08-25 15:26:55 +00:00
}
2023-08-20 02:38:55 +00:00
DrawToggleSetting (
2023-09-07 10:13:48 +00:00
bsi , FSUI_ICONSTR ( ICON_FA_INBOX , " Achievement Notifications " ) ,
2023-08-20 02:38:55 +00:00
FSUI_CSTR ( " Displays popup messages on events such as achievement unlocks and leaderboard submissions. " ) , " Cheevos " ,
" Notifications " , true , enabled ) ;
2023-09-07 10:13:48 +00:00
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_LIST_OL , " Leaderboard Notifications " ) ,
FSUI_CSTR ( " Displays popup messages when starting, submitting, or failing a leaderboard challenge. " ) ,
2023-09-18 12:29:47 +00:00
" Cheevos " , " LeaderboardNotifications " , true , enabled ) ;
2023-08-20 02:38:55 +00:00
DrawToggleSetting (
2023-09-07 10:13:48 +00:00
bsi , FSUI_ICONSTR ( ICON_FA_HEADPHONES , " Sound Effects " ) ,
2023-08-20 02:38:55 +00:00
FSUI_CSTR ( " Plays sound effects for events such as achievement unlocks and leaderboard submissions. " ) , " Cheevos " ,
" SoundEffects " , true , enabled ) ;
DrawToggleSetting (
2023-09-07 10:13:48 +00:00
bsi , FSUI_ICONSTR ( ICON_FA_MAGIC , " Enable In-Game Overlays " ) ,
2023-08-20 02:38:55 +00:00
FSUI_CSTR ( " Shows icons in the lower-right corner of the screen when a challenge/primed achievement is active. " ) ,
2023-09-07 10:13:48 +00:00
" Cheevos " , " Overlays " , true , enabled ) ;
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_USER_FRIENDS , " Encore Mode " ) ,
FSUI_CSTR ( " When enabled, each session will behave as if no achievements have been unlocked. " ) ,
" Cheevos " , " EncoreMode " , false , enabled ) ;
DrawToggleSetting ( bsi , FSUI_ICONSTR ( ICON_FA_STETHOSCOPE , " Spectator Mode " ) ,
FSUI_CSTR ( " When enabled, DuckStation will assume all achievements are locked and not send any "
" unlock notifications to the server. " ) ,
" Cheevos " , " SpectatorMode " , false , enabled ) ;
2022-10-08 10:25:34 +00:00
DrawToggleSetting (
2023-08-20 02:38:55 +00:00
bsi , FSUI_ICONSTR ( ICON_FA_MEDAL , " Test Unofficial Achievements " ) ,
FSUI_CSTR ( " When enabled, DuckStation will list achievements from unofficial sets. These achievements are not "
" tracked by RetroAchievements. " ) ,
" Cheevos " , " UnofficialTestMode " , false , enabled ) ;
2021-01-30 11:37:49 +00:00
2023-09-07 10:13:48 +00:00
if ( ! IsEditingGameSettings ( bsi ) )
2022-07-11 13:03:29 +00:00
{
2023-09-16 09:06:59 +00:00
MenuHeading ( FSUI_CSTR ( " Account " ) ) ;
2023-09-07 10:13:48 +00:00
if ( bsi - > ContainsValue ( " Cheevos " , " Token " ) )
2022-08-25 15:26:55 +00:00
{
2023-09-07 10:13:48 +00:00
ImGui : : PushStyleColor ( ImGuiCol_TextDisabled , ImGui : : GetStyle ( ) . Colors [ ImGuiCol_Text ] ) ;
2023-12-13 11:06:15 +00:00
ActiveButton ( SmallString : : from_format ( fmt : : runtime ( FSUI_ICONSTR ( ICON_FA_USER , " Username: {} " ) ) ,
2024-04-07 10:43:13 +00:00
bsi - > GetTinyStringValue ( " Cheevos " , " Username " ) ) ,
2023-09-07 10:13:48 +00:00
false , false , ImGuiFullscreen : : LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ) ;
TinyString ts_string ;
2023-12-13 11:06:15 +00:00
ts_string . format (
2024-04-09 10:04:45 +00:00
FSUI_FSTR ( " {:%Y-%m-%d %H:%M:%S} " ) ,
2024-04-07 10:43:13 +00:00
fmt : : localtime (
StringUtil : : FromChars < u64 > ( bsi - > GetTinyStringValue ( " Cheevos " , " LoginTimestamp " , " 0 " ) ) . value_or ( 0 ) ) ) ;
2023-09-20 13:49:14 +00:00
ActiveButton (
2023-12-13 11:06:15 +00:00
SmallString : : from_format ( fmt : : runtime ( FSUI_ICONSTR ( ICON_FA_CLOCK , " Login token generated on {} " ) ) , ts_string ) ,
2023-09-20 13:49:14 +00:00
false , false , ImGuiFullscreen : : LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ) ;
2023-09-07 10:13:48 +00:00
ImGui : : PopStyleColor ( ) ;
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_KEY , " Logout " ) , FSUI_CSTR ( " Logs out of RetroAchievements. " ) ) )
{
Host : : RunOnCPUThread ( [ ] ( ) { Achievements : : Logout ( ) ; } ) ;
}
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
else
2021-01-30 11:37:49 +00:00
{
2023-09-07 10:13:48 +00:00
ActiveButton ( FSUI_ICONSTR ( ICON_FA_USER , " Not Logged In " ) , false , false ,
ImGuiFullscreen : : LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ) ;
2022-08-25 15:26:55 +00:00
2023-09-07 10:13:48 +00:00
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_KEY , " Login " ) , FSUI_CSTR ( " Logs in to RetroAchievements. " ) ) )
Host : : OnAchievementsLoginRequested ( Achievements : : LoginRequestReason : : UserInitiated ) ;
}
2022-08-25 15:26:55 +00:00
2023-09-16 09:06:59 +00:00
MenuHeading ( FSUI_CSTR ( " Current Game " ) ) ;
2023-09-07 10:13:48 +00:00
if ( Achievements : : HasActiveGame ( ) )
{
2023-09-18 12:29:47 +00:00
const auto lock = Achievements : : GetLock ( ) ;
2023-09-07 10:13:48 +00:00
ImGui : : PushStyleColor ( ImGuiCol_TextDisabled , ImGui : : GetStyle ( ) . Colors [ ImGuiCol_Text ] ) ;
2023-12-13 11:06:15 +00:00
ActiveButton ( SmallString : : from_format ( fmt : : runtime ( FSUI_ICONSTR ( ICON_FA_BOOKMARK , " Game: {} ({}) " ) ) ,
2023-12-14 06:07:57 +00:00
Achievements : : GetGameID ( ) , Achievements : : GetGameTitle ( ) ) ,
2023-09-07 10:13:48 +00:00
false , false , LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ) ;
2022-08-25 15:26:55 +00:00
2023-09-07 10:13:48 +00:00
const std : : string & rich_presence_string = Achievements : : GetRichPresenceString ( ) ;
if ( ! rich_presence_string . empty ( ) )
{
2023-12-13 11:06:15 +00:00
ActiveButton ( SmallString : : from_format ( ICON_FA_MAP " {} " , rich_presence_string ) , false , false ,
2023-09-07 10:13:48 +00:00
LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ) ;
}
else
{
ActiveButton ( FSUI_ICONSTR ( ICON_FA_MAP , " Rich presence inactive or unsupported. " ) , false , false ,
LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ) ;
}
2022-08-25 15:26:55 +00:00
2023-09-07 10:13:48 +00:00
ImGui : : PopStyleColor ( ) ;
2022-08-25 15:26:55 +00:00
}
2023-09-07 10:13:48 +00:00
else
2022-08-25 15:26:55 +00:00
{
2023-09-07 10:13:48 +00:00
ActiveButton ( FSUI_ICONSTR ( ICON_FA_BAN , " Game not loaded or no RetroAchievements available. " ) , false , false ,
LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ) ;
2022-08-25 15:26:55 +00:00
}
}
2022-07-11 13:03:29 +00:00
EndMenuButtons ( ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DrawAdvancedSettingsPage ( )
2021-01-30 11:37:49 +00:00
{
2022-08-25 15:26:55 +00:00
SettingsInterface * bsi = GetEditingSettingsInterface ( ) ;
2022-07-11 13:03:29 +00:00
BeginMenuButtons ( ) ;
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " Logging Settings " ) ) ;
DrawEnumSetting ( bsi , FSUI_CSTR ( " Log Level " ) ,
FSUI_CSTR ( " Sets the verbosity of messages logged. Higher levels will log more messages. " ) , " Logging " ,
" LogLevel " , Settings : : DEFAULT_LOG_LEVEL , & Settings : : ParseLogLevelName , & Settings : : GetLogLevelName ,
& Settings : : GetLogLevelDisplayName , LOGLEVEL_COUNT ) ;
DrawToggleSetting ( bsi , FSUI_CSTR ( " Log To System Console " ) , FSUI_CSTR ( " Logs messages to the console window. " ) ,
FSUI_CSTR ( " Logging " ) , " LogToConsole " , Settings : : DEFAULT_LOG_TO_CONSOLE ) ;
DrawToggleSetting ( bsi , FSUI_CSTR ( " Log To Debug Console " ) ,
FSUI_CSTR ( " Logs messages to the debug console where supported. " ) , " Logging " , " LogToDebug " , false ) ;
DrawToggleSetting ( bsi , FSUI_CSTR ( " Log To File " ) , FSUI_CSTR ( " Logs messages to duckstation.log in the user directory. " ) ,
" Logging " , " LogToFile " , false ) ;
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " Debugging Settings " ) ) ;
2022-07-11 13:03:29 +00:00
2023-08-20 02:38:55 +00:00
DrawToggleSetting ( bsi , FSUI_CSTR ( " Use Debug GPU Device " ) ,
FSUI_CSTR ( " Enable debugging when supported by the host's renderer API. Only for developer use. " ) ,
" GPU " , " UseDebugDevice " , false ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
# ifdef _WIN32
2023-08-20 02:38:55 +00:00
DrawToggleSetting ( bsi , FSUI_CSTR ( " Increase Timer Resolution " ) ,
FSUI_CSTR ( " Enables more precise frame pacing at the cost of battery life. " ) , " Main " ,
" IncreaseTimerResolution " , true ) ;
2022-07-11 13:03:29 +00:00
# endif
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
DrawToggleSetting ( bsi , FSUI_CSTR ( " Allow Booting Without SBI File " ) ,
FSUI_CSTR ( " Allows loading protected games without subchannel information. " ) , " CDROM " ,
2022-08-25 15:26:55 +00:00
" AllowBootingWithoutSBIFile " , false ) ;
2022-07-11 13:03:29 +00:00
2023-08-20 02:38:55 +00:00
DrawToggleSetting ( bsi , FSUI_CSTR ( " Create Save State Backups " ) ,
FSUI_CSTR ( " Renames existing save states when saving to a backup file. " ) , " Main " ,
" CreateSaveStateBackups " , false ) ;
2024-03-03 03:43:04 +00:00
DrawToggleSetting (
bsi , FSUI_ICONSTR ( ICON_FA_GAMEPAD , " Load Devices From Save States " ) ,
FSUI_CSTR ( " When enabled, memory cards and controllers will be overwritten when save states are loaded. " ) , " Main " ,
" LoadDevicesFromSaveStates " , false ) ;
2022-07-11 13:03:29 +00:00
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " Display Settings " ) ) ;
DrawToggleSetting ( bsi , FSUI_CSTR ( " Show Status Indicators " ) ,
FSUI_CSTR ( " Shows persistent icons when turbo is active or when paused. " ) , " Display " ,
" ShowStatusIndicators " , true ) ;
DrawToggleSetting ( bsi , FSUI_CSTR ( " Show Enhancement Settings " ) ,
FSUI_CSTR ( " Shows enhancement settings in the bottom-right corner of the screen. " ) , " Display " ,
2022-08-25 15:26:55 +00:00
" ShowEnhancements " , false ) ;
2023-08-20 02:38:55 +00:00
DrawFloatRangeSetting (
bsi , FSUI_CSTR ( " Display FPS Limit " ) ,
FSUI_CSTR ( " Limits how many frames are displayed to the screen. These frames are still rendered. " ) , " Display " ,
" MaxFPS " , Settings : : DEFAULT_DISPLAY_MAX_FPS , 0.0f , 500.0f , " %.2f FPS " ) ;
2023-08-19 14:08:03 +00:00
DrawToggleSetting (
2023-08-20 02:38:55 +00:00
bsi , FSUI_CSTR ( " Stretch Display Vertically " ) ,
FSUI_CSTR ( " Stretches the display to match the aspect ratio by multiplying vertically instead of horizontally. " ) ,
" Display " , " StretchVertically " , false ) ;
2023-09-02 12:26:03 +00:00
DrawEnumSetting ( bsi , FSUI_CSTR ( " Wireframe Rendering " ) ,
FSUI_CSTR ( " Overlays or replaces normal triangle drawing with a wireframe/line view. " ) , " GPU " ,
" WireframeMode " , GPUWireframeMode : : Disabled , & Settings : : ParseGPUWireframeMode ,
& Settings : : GetGPUWireframeModeName , & Settings : : GetGPUWireframeModeDisplayName ,
GPUWireframeMode : : Count ) ;
2022-07-11 13:03:29 +00:00
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " PGXP Settings " ) ) ;
2022-07-11 13:03:29 +00:00
2022-08-25 15:26:55 +00:00
const bool pgxp_enabled = GetEffectiveBoolSetting ( bsi , " GPU " , " PGXPEnable " , false ) ;
2022-07-11 13:03:29 +00:00
2023-08-20 02:38:55 +00:00
DrawToggleSetting ( bsi , FSUI_CSTR ( " Enable PGXP Vertex Cache " ) ,
FSUI_CSTR ( " Uses screen positions to resolve PGXP data. May improve visuals in some games. " ) , " GPU " ,
2022-07-11 13:03:29 +00:00
" PGXPVertexCache " , pgxp_enabled ) ;
DrawFloatRangeSetting (
2023-08-20 02:38:55 +00:00
bsi , FSUI_CSTR ( " PGXP Geometry Tolerance " ) ,
FSUI_CSTR ( " Sets a threshold for discarding precise values when exceeded. May help with glitches in some games. " ) ,
" GPU " , " PGXPTolerance " , - 1.0f , - 1.0f , 10.0f , " %.1f " , pgxp_enabled ) ;
DrawFloatRangeSetting ( bsi , FSUI_CSTR ( " PGXP Depth Clear Threshold " ) ,
FSUI_CSTR ( " Sets a threshold for discarding the emulated depth buffer. May help in some games. " ) ,
" GPU " , " PGXPDepthBuffer " , Settings : : DEFAULT_GPU_PGXP_DEPTH_THRESHOLD , 0.0f , 4096.0f , " %.1f " ,
2022-08-25 15:26:55 +00:00
pgxp_enabled ) ;
2022-07-11 13:03:29 +00:00
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " Texture Dumping " ) ) ;
2022-07-11 13:03:29 +00:00
2023-08-20 02:38:55 +00:00
DrawToggleSetting ( bsi , FSUI_CSTR ( " Dump Replaceable VRAM Writes " ) ,
FSUI_CSTR ( " Writes textures which can be replaced to the dump directory. " ) , " TextureReplacements " ,
" DumpVRAMWrites " , false ) ;
DrawToggleSetting ( bsi , FSUI_CSTR ( " Set VRAM Write Dump Alpha Channel " ) ,
FSUI_CSTR ( " Clears the mask/transparency bit in VRAM write dumps. " ) , " TextureReplacements " ,
" DumpVRAMWriteForceAlphaChannel " , true ) ;
2022-07-11 13:03:29 +00:00
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " CPU Emulation " ) ) ;
2022-07-11 13:03:29 +00:00
2023-08-20 02:38:55 +00:00
DrawToggleSetting (
bsi , FSUI_CSTR ( " Enable Recompiler ICache " ) ,
FSUI_CSTR ( " Simulates the CPU's instruction cache in the recompiler. Can help with games running too fast. " ) , " CPU " ,
" RecompilerICache " , false ) ;
DrawToggleSetting ( bsi , FSUI_CSTR ( " Enable Recompiler Memory Exceptions " ) ,
FSUI_CSTR ( " Enables alignment and bus exceptions. Not needed for any known games. " ) , " CPU " ,
2022-07-11 13:03:29 +00:00
" RecompilerMemoryExceptions " , false ) ;
2023-08-20 02:38:55 +00:00
DrawToggleSetting (
bsi , FSUI_CSTR ( " Enable Recompiler Block Linking " ) ,
FSUI_CSTR ( " Performance enhancement - jumps directly between blocks instead of returning to the dispatcher. " ) , " CPU " ,
" RecompilerBlockLinking " , true ) ;
DrawEnumSetting ( bsi , FSUI_CSTR ( " Recompiler Fast Memory Access " ) ,
FSUI_CSTR ( " Avoids calls to C++ code, significantly speeding up the recompiler. " ) , " CPU " ,
" FastmemMode " , Settings : : DEFAULT_CPU_FASTMEM_MODE , & Settings : : ParseCPUFastmemMode ,
& Settings : : GetCPUFastmemModeName , & Settings : : GetCPUFastmemModeDisplayName , CPUFastmemMode : : Count ) ;
2021-01-30 11:37:49 +00:00
2024-03-03 03:43:04 +00:00
MenuHeading ( FSUI_CSTR ( " CD-ROM Emulation " ) ) ;
DrawToggleSetting ( bsi , FSUI_CSTR ( " Enable Region Check " ) ,
FSUI_CSTR ( " Simulates the region check present in original, unmodified consoles. " ) , " CDROM " ,
" RegionCheck " , false ) ;
2022-07-11 13:03:29 +00:00
EndMenuButtons ( ) ;
}
2021-01-30 11:37:49 +00:00
2023-09-18 12:29:47 +00:00
void FullscreenUI : : DrawPauseMenu ( )
2022-07-11 13:03:29 +00:00
{
2022-10-23 04:09:54 +00:00
SmallString buffer ;
2022-07-11 13:03:29 +00:00
ImDrawList * dl = ImGui : : GetBackgroundDrawList ( ) ;
const ImVec2 display_size ( ImGui : : GetIO ( ) . DisplaySize ) ;
2023-09-19 14:09:31 +00:00
const ImU32 text_color = ImGui : : GetColorU32 ( UIBackgroundTextColor ) | IM_COL32_A_MASK ;
dl - > AddRectFilled ( ImVec2 ( 0.0f , 0.0f ) , display_size ,
( ImGui : : GetColorU32 ( UIBackgroundColor ) & ~ IM_COL32_A_MASK ) | ( 200 < < IM_COL32_A_SHIFT ) ) ;
2021-01-31 07:40:50 +00:00
2022-07-11 13:03:29 +00:00
// title info
{
2023-05-15 13:38:37 +00:00
const std : : string & title = System : : GetGameTitle ( ) ;
const std : : string & serial = System : : GetGameSerial ( ) ;
2022-07-11 13:03:29 +00:00
2022-10-05 08:29:08 +00:00
if ( ! serial . empty ( ) )
2023-12-13 11:06:15 +00:00
buffer . format ( " {} - " , serial ) ;
2023-09-20 13:49:14 +00:00
buffer . append ( Path : : GetFileName ( System : : GetDiscPath ( ) ) ) ;
2022-07-11 13:03:29 +00:00
2023-12-01 17:08:19 +00:00
const float image_width = 60.0f ;
const float image_height = 60.0f ;
2022-07-11 13:03:29 +00:00
const ImVec2 title_size (
g_large_font - > CalcTextSizeA ( g_large_font - > FontSize , std : : numeric_limits < float > : : max ( ) , - 1.0f , title . c_str ( ) ) ) ;
const ImVec2 subtitle_size (
2023-12-01 17:08:19 +00:00
g_medium_font - > CalcTextSizeA ( g_medium_font - > FontSize , std : : numeric_limits < float > : : max ( ) , - 1.0f , buffer . c_str ( ) ) ) ;
2022-07-11 13:03:29 +00:00
2023-12-01 17:08:19 +00:00
ImVec2 title_pos ( display_size . x - LayoutScale ( 10.0f + image_width + 20.0f ) - title_size . x ,
2024-04-09 10:04:45 +00:00
display_size . y - LayoutScale ( LAYOUT_FOOTER_HEIGHT ) - LayoutScale ( 10.0f + image_height ) ) ;
2023-12-01 17:08:19 +00:00
ImVec2 subtitle_pos ( display_size . x - LayoutScale ( 10.0f + image_width + 20.0f ) - subtitle_size . x ,
2022-07-11 13:03:29 +00:00
title_pos . y + g_large_font - > FontSize + LayoutScale ( 4.0f ) ) ;
2023-12-01 17:08:19 +00:00
float rp_height = 0.0f ;
2022-07-11 13:03:29 +00:00
{
2023-09-07 10:13:48 +00:00
const auto lock = Achievements : : GetLock ( ) ;
2023-12-01 17:08:19 +00:00
const std : : string & rp = Achievements : : IsActive ( ) ? Achievements : : GetRichPresenceString ( ) : std : : string ( ) ;
2022-07-11 13:03:29 +00:00
if ( ! rp . empty ( ) )
{
const float wrap_width = LayoutScale ( 350.0f ) ;
const ImVec2 rp_size = g_medium_font - > CalcTextSizeA ( g_medium_font - > FontSize , std : : numeric_limits < float > : : max ( ) ,
2023-12-01 17:08:19 +00:00
wrap_width , rp . data ( ) , rp . data ( ) + rp . length ( ) ) ;
// Add a small extra gap if any Rich Presence is displayed
rp_height = rp_size . y - g_medium_font - > FontSize + LayoutScale ( 2.0f ) ;
2022-07-11 13:03:29 +00:00
2023-12-01 17:08:19 +00:00
const ImVec2 rp_pos ( display_size . x - LayoutScale ( 20.0f + 50.0f + 20.0f ) - rp_size . x ,
subtitle_pos . y + g_medium_font - > FontSize + LayoutScale ( 4.0f ) - rp_height ) ;
2022-07-11 13:03:29 +00:00
title_pos . y - = rp_height ;
subtitle_pos . y - = rp_height ;
2023-12-01 17:08:19 +00:00
DrawShadowedText ( dl , g_medium_font , rp_pos , text_color , rp . data ( ) , rp . data ( ) + rp . length ( ) , wrap_width ) ;
2022-07-11 13:03:29 +00:00
}
2021-01-30 11:37:49 +00:00
}
2023-12-01 17:08:19 +00:00
DrawShadowedText ( dl , g_large_font , title_pos , text_color , title . c_str ( ) ) ;
DrawShadowedText ( dl , g_medium_font , subtitle_pos , text_color , buffer . c_str ( ) ) ;
2022-07-11 13:03:29 +00:00
2023-12-01 17:08:19 +00:00
GPUTexture * const cover = GetCoverForCurrentGame ( ) ;
const ImVec2 image_min ( display_size . x - LayoutScale ( 10.0f + image_width ) ,
2024-04-09 10:04:45 +00:00
display_size . y - LayoutScale ( LAYOUT_FOOTER_HEIGHT ) - LayoutScale ( 10.0f + image_height ) -
rp_height ) ;
2023-12-01 17:08:19 +00:00
const ImVec2 image_max ( image_min . x + LayoutScale ( image_width ) , image_min . y + LayoutScale ( image_height ) + rp_height ) ;
const ImRect image_rect ( CenterImage ( ImRect ( image_min , image_max ) , ImVec2 ( static_cast < float > ( cover - > GetWidth ( ) ) ,
static_cast < float > ( cover - > GetHeight ( ) ) ) ) ) ;
dl - > AddImage ( cover , image_rect . Min , image_rect . Max ) ;
2021-01-30 11:37:49 +00:00
}
2022-10-23 04:09:54 +00:00
// current time / play time
{
2023-12-13 11:06:15 +00:00
buffer . format ( " {:%X} " , fmt : : localtime ( std : : time ( nullptr ) ) ) ;
2022-10-23 04:09:54 +00:00
const ImVec2 time_size ( g_large_font - > CalcTextSizeA ( g_large_font - > FontSize , std : : numeric_limits < float > : : max ( ) , - 1.0f ,
2023-09-20 13:49:14 +00:00
buffer . c_str ( ) , buffer . end_ptr ( ) ) ) ;
2022-10-23 04:09:54 +00:00
const ImVec2 time_pos ( display_size . x - LayoutScale ( 10.0f ) - time_size . x , LayoutScale ( 10.0f ) ) ;
2023-09-20 13:49:14 +00:00
DrawShadowedText ( dl , g_large_font , time_pos , text_color , buffer . c_str ( ) , buffer . end_ptr ( ) ) ;
2022-10-23 04:09:54 +00:00
2023-05-15 13:38:37 +00:00
const std : : string & serial = System : : GetGameSerial ( ) ;
2022-10-23 04:09:54 +00:00
if ( ! serial . empty ( ) )
{
const std : : time_t cached_played_time = GameList : : GetCachedPlayedTimeForSerial ( serial ) ;
2023-08-23 12:06:48 +00:00
const std : : time_t session_time = static_cast < std : : time_t > ( System : : GetSessionPlayedTime ( ) ) ;
2022-10-23 04:09:54 +00:00
2023-12-13 11:06:15 +00:00
buffer . format ( FSUI_FSTR ( " Session: {} " ) , GameList : : FormatTimespan ( session_time , true ) ) ;
2022-10-23 04:09:54 +00:00
const ImVec2 session_size ( g_medium_font - > CalcTextSizeA ( g_medium_font - > FontSize , std : : numeric_limits < float > : : max ( ) ,
2023-09-20 13:49:14 +00:00
- 1.0f , buffer . c_str ( ) , buffer . end_ptr ( ) ) ) ;
2022-10-23 04:09:54 +00:00
const ImVec2 session_pos ( display_size . x - LayoutScale ( 10.0f ) - session_size . x ,
time_pos . y + g_large_font - > FontSize + LayoutScale ( 4.0f ) ) ;
2023-09-20 13:49:14 +00:00
DrawShadowedText ( dl , g_medium_font , session_pos , text_color , buffer . c_str ( ) , buffer . end_ptr ( ) ) ;
2022-10-23 04:09:54 +00:00
2023-12-13 11:06:15 +00:00
buffer . format ( FSUI_FSTR ( " All Time: {} " ) , GameList : : FormatTimespan ( cached_played_time + session_time , true ) ) ;
2022-10-23 04:09:54 +00:00
const ImVec2 total_size ( g_medium_font - > CalcTextSizeA ( g_medium_font - > FontSize , std : : numeric_limits < float > : : max ( ) ,
2023-09-20 13:49:14 +00:00
- 1.0f , buffer . c_str ( ) , buffer . end_ptr ( ) ) ) ;
2022-10-23 04:09:54 +00:00
const ImVec2 total_pos ( display_size . x - LayoutScale ( 10.0f ) - total_size . x ,
session_pos . y + g_medium_font - > FontSize + LayoutScale ( 4.0f ) ) ;
2023-09-20 13:49:14 +00:00
DrawShadowedText ( dl , g_medium_font , total_pos , text_color , buffer . c_str ( ) , buffer . end_ptr ( ) ) ;
2022-10-23 04:09:54 +00:00
}
}
2022-07-11 13:03:29 +00:00
const ImVec2 window_size ( LayoutScale ( 500.0f , LAYOUT_SCREEN_HEIGHT ) ) ;
2024-04-09 10:04:45 +00:00
const ImVec2 window_pos ( 0.0f , display_size . y - LayoutScale ( LAYOUT_FOOTER_HEIGHT ) - window_size . y ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
if ( BeginFullscreenWindow ( window_pos , window_size , " pause_menu " , ImVec4 ( 0.0f , 0.0f , 0.0f , 0.0f ) , 0.0f , 10.0f ,
ImGuiWindowFlags_NoBackground ) )
{
static constexpr u32 submenu_item_count [ ] = {
2022-07-30 02:58:03 +00:00
12 , // None
2022-07-11 13:03:29 +00:00
4 , // Exit
2023-09-16 09:06:59 +00:00
3 , // Achievements
2022-07-11 13:03:29 +00:00
} ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
const bool just_focused = ResetFocusHere ( ) ;
BeginMenuButtons ( submenu_item_count [ static_cast < u32 > ( s_current_pause_submenu ) ] , 1.0f ,
ImGuiFullscreen : : LAYOUT_MENU_BUTTON_X_PADDING , ImGuiFullscreen : : LAYOUT_MENU_BUTTON_Y_PADDING ,
ImGuiFullscreen : : LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
switch ( s_current_pause_submenu )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
case PauseSubMenu : : None :
{
// NOTE: Menu close must come first, because otherwise VM destruction options will race.
2023-05-15 13:38:37 +00:00
const bool has_game = System : : IsValid ( ) & & ! System : : GetGameSerial ( ) . empty ( ) ;
2021-01-30 11:37:49 +00:00
2023-09-18 12:29:47 +00:00
if ( just_focused )
ImGui : : SetFocusID ( ImGui : : GetID ( FSUI_ICONSTR ( ICON_FA_PLAY , " Resume Game " ) ) , ImGui : : GetCurrentWindow ( ) ) ;
2023-08-20 02:38:55 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_PLAY , " Resume Game " ) , false ) | | WantsToCloseMenu ( ) )
2022-07-11 13:03:29 +00:00
ClosePauseMenu ( ) ;
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_FAST_FORWARD , " Toggle Fast Forward " ) , false ) )
2022-07-11 13:03:29 +00:00
{
ClosePauseMenu ( ) ;
DoToggleFastForward ( ) ;
}
2023-08-20 02:38:55 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_UNDO , " Load State " ) , false , has_game ) )
2022-07-11 13:03:29 +00:00
{
if ( OpenSaveStateSelector ( true ) )
s_current_main_window = MainWindowType : : None ;
}
2023-08-20 02:38:55 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_DOWNLOAD , " Save State " ) , false , has_game ) )
2022-07-11 13:03:29 +00:00
{
if ( OpenSaveStateSelector ( false ) )
s_current_main_window = MainWindowType : : None ;
}
2023-08-20 02:38:55 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_FROWN_OPEN , " Cheat List " ) , false ,
2024-03-03 03:43:04 +00:00
! System : : GetGameSerial ( ) . empty ( ) & & g_settings . enable_cheats ) )
2022-07-11 13:03:29 +00:00
{
s_current_main_window = MainWindowType : : None ;
DoCheatsMenu ( ) ;
}
2023-08-20 02:38:55 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_GAMEPAD , " Toggle Analog " ) , false ) )
2022-07-11 13:03:29 +00:00
{
2022-07-30 02:58:03 +00:00
ClosePauseMenu ( ) ;
2022-07-11 13:03:29 +00:00
DoToggleAnalogMode ( ) ;
}
2023-08-20 02:38:55 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_WRENCH , " Game Properties " ) , false , has_game ) )
2022-07-11 13:03:29 +00:00
{
SwitchToGameSettings ( ) ;
}
2023-08-20 02:38:55 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_TROPHY , " Achievements " ) , false ,
2023-09-18 12:29:47 +00:00
Achievements : : HasAchievementsOrLeaderboards ( ) ) )
2022-07-11 13:03:29 +00:00
{
// skip second menu and go straight to cheevos if there's no lbs
2023-09-07 10:13:48 +00:00
if ( ! Achievements : : HasLeaderboards ( ) )
2022-07-11 13:03:29 +00:00
OpenAchievementsWindow ( ) ;
else
OpenPauseSubMenu ( PauseSubMenu : : Achievements ) ;
}
2023-08-20 02:38:55 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_CAMERA , " Save Screenshot " ) , false ) )
2022-07-11 13:03:29 +00:00
{
System : : SaveScreenshot ( ) ;
ClosePauseMenu ( ) ;
}
2023-08-20 02:38:55 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_COMPACT_DISC , " Change Disc " ) , false ) )
2022-07-11 13:03:29 +00:00
{
s_current_main_window = MainWindowType : : None ;
DoChangeDisc ( ) ;
}
2023-08-20 02:38:55 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_SLIDERS_H , " Settings " ) , false ) )
2022-07-11 13:03:29 +00:00
SwitchToSettings ( ) ;
2023-08-20 02:38:55 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_POWER_OFF , " Close Game " ) , false ) )
2022-07-11 13:03:29 +00:00
{
// skip submenu when we can't save anyway
2022-10-03 12:18:49 +00:00
if ( ! has_game )
2022-07-11 13:03:29 +00:00
DoShutdown ( false ) ;
else
OpenPauseSubMenu ( PauseSubMenu : : Exit ) ;
}
2021-04-17 04:23:47 +00:00
}
2022-07-11 13:03:29 +00:00
break ;
2021-04-17 04:23:47 +00:00
2022-07-11 13:03:29 +00:00
case PauseSubMenu : : Exit :
{
if ( just_focused )
2023-09-18 12:29:47 +00:00
{
2023-08-20 02:38:55 +00:00
ImGui : : SetFocusID ( ImGui : : GetID ( FSUI_ICONSTR ( ICON_FA_POWER_OFF , " Exit Without Saving " ) ) ,
ImGui : : GetCurrentWindow ( ) ) ;
2023-09-18 12:29:47 +00:00
}
2021-01-30 11:37:49 +00:00
2023-09-18 12:29:47 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_BACKWARD , " Back To Pause Menu " ) , false ) | | WantsToCloseMenu ( ) )
2022-07-11 13:03:29 +00:00
OpenPauseSubMenu ( PauseSubMenu : : None ) ;
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_SYNC , " Reset System " ) , false ) )
2022-07-11 13:03:29 +00:00
{
ClosePauseMenu ( ) ;
DoReset ( ) ;
}
2021-04-17 04:23:47 +00:00
2023-08-20 02:38:55 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_SAVE , " Exit And Save State " ) , false ) )
2022-07-11 13:03:29 +00:00
DoShutdown ( true ) ;
2021-04-17 04:23:47 +00:00
2023-08-20 02:38:55 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_POWER_OFF , " Exit Without Saving " ) , false ) )
2022-07-11 13:03:29 +00:00
DoShutdown ( false ) ;
}
break ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
case PauseSubMenu : : Achievements :
{
2023-09-18 12:29:47 +00:00
if ( just_focused )
{
ImGui : : SetFocusID ( ImGui : : GetID ( FSUI_ICONSTR ( ICON_FA_BACKWARD , " Back To Pause Menu " ) ) ,
ImGui : : GetCurrentWindow ( ) ) ;
}
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_BACKWARD , " Back To Pause Menu " ) , false ) | | WantsToCloseMenu ( ) )
2022-07-11 13:03:29 +00:00
OpenPauseSubMenu ( PauseSubMenu : : None ) ;
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_TROPHY , " Achievements " ) , false ) )
2022-07-11 13:03:29 +00:00
OpenAchievementsWindow ( ) ;
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_STOPWATCH , " Leaderboards " ) , false ) )
2022-07-11 13:03:29 +00:00
OpenLeaderboardsWindow ( ) ;
}
break ;
2021-01-30 11:37:49 +00:00
}
EndMenuButtons ( ) ;
2022-07-11 13:03:29 +00:00
EndFullscreenWindow ( ) ;
}
2022-10-08 10:25:34 +00:00
2023-09-07 10:13:48 +00:00
Achievements : : DrawPauseMenuOverlays ( ) ;
2024-04-09 10:04:45 +00:00
if ( IsGamepadInputSource ( ) )
{
SetFullscreenFooterText ( std : : array { std : : make_pair ( ICON_PF_XBOX_DPAD_UP_DOWN , FSUI_VSTR ( " Change Selection " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_A , FSUI_VSTR ( " Select " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_B , FSUI_VSTR ( " Return To Game " ) ) } ) ;
}
else
{
SetFullscreenFooterText ( std : : array {
std : : make_pair ( ICON_PF_ARROW_UP ICON_PF_ARROW_DOWN , FSUI_VSTR ( " Change Selection " ) ) ,
std : : make_pair ( ICON_PF_ENTER , FSUI_VSTR ( " Select " ) ) , std : : make_pair ( ICON_PF_ESC , FSUI_VSTR ( " Return To Game " ) ) } ) ;
}
2021-01-30 11:37:49 +00:00
}
2024-04-09 10:04:45 +00:00
void FullscreenUI : : InitializePlaceholderSaveStateListEntry ( SaveStateListEntry * li , const std : : string & serial , s32 slot ,
bool global )
2021-01-30 11:37:49 +00:00
{
2023-08-20 02:38:55 +00:00
li - > title = ( global | | slot > 0 ) ? fmt : : format ( global ? FSUI_FSTR ( " Global Slot {0}##global_slot_{0} " ) :
FSUI_FSTR ( " Game Slot {0}##game_slot_{0} " ) ,
slot ) :
FSUI_STR ( " Quick Save " ) ;
li - > summary = FSUI_STR ( " No save present in this slot. " ) ;
2022-07-11 13:03:29 +00:00
li - > path = { } ;
2022-09-17 05:51:05 +00:00
li - > timestamp = 0 ;
2022-07-11 13:03:29 +00:00
li - > slot = slot ;
li - > preview_texture = { } ;
2022-10-23 04:09:54 +00:00
li - > global = global ;
2021-01-30 11:37:49 +00:00
}
2024-04-09 10:04:45 +00:00
bool FullscreenUI : : InitializeSaveStateListEntryFromSerial ( SaveStateListEntry * li , const std : : string & serial , s32 slot ,
bool global )
2021-01-30 11:37:49 +00:00
{
2024-04-09 10:04:45 +00:00
const std : : string path =
( global ? System : : GetGlobalSaveStateFileName ( slot ) : System : : GetGameSaveStateFileName ( serial , slot ) ) ;
if ( ! InitializeSaveStateListEntryFromPath ( li , path . c_str ( ) , slot , global ) )
2022-07-11 13:03:29 +00:00
{
2024-04-09 10:04:45 +00:00
InitializePlaceholderSaveStateListEntry ( li , serial , slot , global ) ;
2022-07-11 13:03:29 +00:00
return false ;
}
2024-04-09 10:04:45 +00:00
return true ;
}
bool FullscreenUI : : InitializeSaveStateListEntryFromPath ( SaveStateListEntry * li , std : : string path , s32 slot , bool global )
{
std : : optional < ExtendedSaveStateInfo > ssi ( System : : GetExtendedSaveStateInfo ( path . c_str ( ) ) ) ;
if ( ! ssi . has_value ( ) )
return false ;
2022-07-11 13:03:29 +00:00
if ( global )
{
2023-08-20 02:38:55 +00:00
li - > title = fmt : : format ( FSUI_FSTR ( " Global Slot {0} - {1}##global_slot_{0} " ) , slot , ssi - > serial ) ;
2022-07-11 13:03:29 +00:00
}
else
{
2023-08-20 02:38:55 +00:00
li - > title = ( slot > 0 ) ? fmt : : format ( FSUI_FSTR ( " Game Slot {0}##game_slot_{0} " ) , slot ) : FSUI_STR ( " Game Quick Save " ) ;
2022-07-11 13:03:29 +00:00
}
2023-08-20 02:38:55 +00:00
li - > summary = fmt : : format ( FSUI_FSTR ( " Saved {:%c} " ) , fmt : : localtime ( ssi - > timestamp ) ) ;
2022-09-17 05:51:05 +00:00
li - > timestamp = ssi - > timestamp ;
2022-07-11 13:03:29 +00:00
li - > slot = slot ;
2024-04-09 10:04:45 +00:00
li - > path = std : : move ( path ) ;
2022-10-23 04:09:54 +00:00
li - > global = global ;
2022-07-11 13:03:29 +00:00
PopulateSaveStateScreenshot ( li , & ssi . value ( ) ) ;
return true ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : PopulateSaveStateScreenshot ( SaveStateListEntry * li , const ExtendedSaveStateInfo * ssi )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
li - > preview_texture . reset ( ) ;
if ( ssi & & ! ssi - > screenshot_data . empty ( ) )
{
2023-12-14 06:07:57 +00:00
li - > preview_texture = g_gpu_device - > FetchTexture ( ssi - > screenshot_width , ssi - > screenshot_height , 1 , 1 , 1 ,
GPUTexture : : Type : : Texture , GPUTexture : : Format : : RGBA8 ,
ssi - > screenshot_data . data ( ) , sizeof ( u32 ) * ssi - > screenshot_width ) ;
2022-07-11 13:03:29 +00:00
}
else
{
2023-12-04 06:04:45 +00:00
li - > preview_texture = g_gpu_device - > FetchTexture (
2023-08-13 03:42:02 +00:00
Resources : : PLACEHOLDER_ICON_WIDTH , Resources : : PLACEHOLDER_ICON_HEIGHT , 1 , 1 , 1 , GPUTexture : : Type : : Texture ,
2023-12-04 06:04:45 +00:00
GPUTexture : : Format : : RGBA8 , Resources : : PLACEHOLDER_ICON_DATA , sizeof ( u32 ) * Resources : : PLACEHOLDER_ICON_WIDTH ) ;
2022-07-11 13:03:29 +00:00
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
if ( ! li - > preview_texture )
Log_ErrorPrintf ( " Failed to upload save state image to GPU " ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : ClearSaveStateEntryList ( )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
for ( SaveStateListEntry & entry : s_save_state_selector_slots )
{
if ( entry . preview_texture )
2023-12-04 06:04:45 +00:00
g_gpu_device - > RecycleTexture ( std : : move ( entry . preview_texture ) ) ;
2022-07-11 13:03:29 +00:00
}
s_save_state_selector_slots . clear ( ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
u32 FullscreenUI : : PopulateSaveStateListEntries ( const std : : string & title , const std : : string & serial )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
ClearSaveStateEntryList ( ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
if ( s_save_state_selector_loading )
{
std : : optional < ExtendedSaveStateInfo > ssi = System : : GetUndoSaveStateInfo ( ) ;
if ( ssi )
{
SaveStateListEntry li ;
PopulateSaveStateScreenshot ( & li , & ssi . value ( ) ) ;
2023-08-20 02:38:55 +00:00
li . title = FSUI_STR ( " Undo Load State " ) ;
li . summary = FSUI_STR ( " Restores the state of the system prior to the last state loaded. " ) ;
2022-07-11 13:03:29 +00:00
s_save_state_selector_slots . push_back ( std : : move ( li ) ) ;
}
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
if ( ! serial . empty ( ) )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
for ( s32 i = 1 ; i < = System : : PER_GAME_SAVE_STATE_SLOTS ; i + + )
{
SaveStateListEntry li ;
2024-04-09 10:04:45 +00:00
if ( InitializeSaveStateListEntryFromSerial ( & li , serial , i , false ) | | ! s_save_state_selector_loading )
2022-07-11 13:03:29 +00:00
s_save_state_selector_slots . push_back ( std : : move ( li ) ) ;
}
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
for ( s32 i = 1 ; i < = System : : GLOBAL_SAVE_STATE_SLOTS ; i + + )
{
SaveStateListEntry li ;
2024-04-09 10:04:45 +00:00
if ( InitializeSaveStateListEntryFromSerial ( & li , serial , i , true ) | | ! s_save_state_selector_loading )
2022-07-11 13:03:29 +00:00
s_save_state_selector_slots . push_back ( std : : move ( li ) ) ;
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
return static_cast < u32 > ( s_save_state_selector_slots . size ( ) ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
bool FullscreenUI : : OpenLoadStateSelectorForGame ( const std : : string & game_path )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
auto lock = GameList : : GetLock ( ) ;
const GameList : : Entry * entry = GameList : : GetEntryForPath ( game_path . c_str ( ) ) ;
if ( entry )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
s_save_state_selector_loading = true ;
if ( PopulateSaveStateListEntries ( entry - > title . c_str ( ) , entry - > serial . c_str ( ) ) > 0 )
{
s_save_state_selector_open = true ;
2022-09-17 05:51:05 +00:00
s_save_state_selector_resuming = false ;
2022-07-11 13:03:29 +00:00
s_save_state_selector_game_path = game_path ;
return true ;
}
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
2023-08-20 02:38:55 +00:00
ShowToast ( { } , FSUI_STR ( " No save states found. " ) , 5.0f ) ;
2022-07-11 13:03:29 +00:00
return false ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
bool FullscreenUI : : OpenSaveStateSelector ( bool is_loading )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
s_save_state_selector_game_path = { } ;
s_save_state_selector_loading = is_loading ;
2022-09-17 05:51:05 +00:00
s_save_state_selector_resuming = false ;
2023-05-15 13:38:37 +00:00
if ( PopulateSaveStateListEntries ( System : : GetGameTitle ( ) . c_str ( ) , System : : GetGameSerial ( ) . c_str ( ) ) > 0 )
2022-07-11 13:03:29 +00:00
{
s_save_state_selector_open = true ;
return true ;
}
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
ShowToast ( { } , FSUI_STR ( " No save states found. " ) , 5.0f ) ;
2022-07-11 13:03:29 +00:00
return false ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : CloseSaveStateSelector ( )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
ClearSaveStateEntryList ( ) ;
s_save_state_selector_open = false ;
s_save_state_selector_loading = false ;
2022-09-17 05:51:05 +00:00
s_save_state_selector_resuming = false ;
2022-07-11 13:03:29 +00:00
s_save_state_selector_game_path = { } ;
2021-01-30 11:37:49 +00:00
}
2022-10-23 04:09:54 +00:00
void FullscreenUI : : DrawSaveStateSelector ( bool is_loading )
2021-01-30 11:37:49 +00:00
{
2022-10-23 04:09:54 +00:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
2021-01-30 11:37:49 +00:00
2022-10-23 04:09:54 +00:00
ImGui : : SetNextWindowPos ( ImVec2 ( 0.0f , 0.0f ) ) ;
2024-04-09 10:04:45 +00:00
ImGui : : SetNextWindowSize ( io . DisplaySize - LayoutScale ( 0.0f , LAYOUT_FOOTER_HEIGHT ) ) ;
2022-10-23 04:09:54 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowPadding , ImVec2 ( 0.0f , 0.0f ) ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowBorderSize , 0.0f ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowRounding , 0.0f ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_ChildRounding , 0.0f ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_ChildBorderSize , 0.0f ) ;
2023-08-20 02:38:55 +00:00
const char * window_title = is_loading ? FSUI_CSTR ( " Load State " ) : FSUI_CSTR ( " Save State " ) ;
2022-10-23 04:09:54 +00:00
ImGui : : OpenPopup ( window_title ) ;
bool is_open = true ;
const bool valid =
ImGui : : BeginPopupModal ( window_title , & is_open ,
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoBackground ) ;
if ( ! valid | | ! is_open )
2021-02-01 15:40:37 +00:00
{
2022-10-23 04:09:54 +00:00
if ( valid )
ImGui : : EndPopup ( ) ;
ImGui : : PopStyleVar ( 5 ) ;
if ( ! is_open )
2023-09-18 12:29:47 +00:00
{
2022-07-11 13:03:29 +00:00
CloseSaveStateSelector ( ) ;
2023-09-18 12:29:47 +00:00
ReturnToPreviousWindow ( ) ;
}
2022-10-23 04:09:54 +00:00
return ;
2021-02-01 15:40:37 +00:00
}
2022-10-23 04:09:54 +00:00
ImVec2 heading_size = ImVec2 (
io . DisplaySize . x , LayoutScale ( LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY + LAYOUT_MENU_BUTTON_Y_PADDING * 2.0f + 2.0f ) ) ;
2021-02-01 15:40:37 +00:00
2022-10-23 04:09:54 +00:00
ImGui : : PushStyleColor ( ImGuiCol_ChildBg , ModAlpha ( UIPrimaryColor , 0.9f ) ) ;
2021-02-01 15:40:37 +00:00
2022-10-31 08:08:26 +00:00
if ( ImGui : : BeginChild ( " state_titlebar " , heading_size , false , ImGuiWindowFlags_NavFlattened ) )
2022-07-11 13:03:29 +00:00
{
2022-10-23 04:09:54 +00:00
BeginNavBar ( ) ;
if ( NavButton ( ICON_FA_BACKWARD , true , true ) )
2023-09-18 12:29:47 +00:00
{
2022-10-23 04:09:54 +00:00
CloseSaveStateSelector ( ) ;
2023-09-18 12:29:47 +00:00
ReturnToPreviousWindow ( ) ;
}
2021-02-01 15:40:37 +00:00
2023-08-20 02:38:55 +00:00
NavTitle ( is_loading ? FSUI_CSTR ( " Load State " ) : FSUI_CSTR ( " Save State " ) ) ;
2022-10-23 04:09:54 +00:00
EndNavBar ( ) ;
ImGui : : EndChild ( ) ;
}
2021-02-01 15:40:37 +00:00
2022-10-23 04:09:54 +00:00
ImGui : : PopStyleColor ( ) ;
ImGui : : PushStyleColor ( ImGuiCol_ChildBg , ModAlpha ( UIBackgroundColor , 0.9f ) ) ;
ImGui : : SetCursorPos ( ImVec2 ( 0.0f , heading_size . y ) ) ;
2021-02-01 15:40:37 +00:00
2023-10-08 03:58:45 +00:00
bool closed = false ;
2022-10-23 04:09:54 +00:00
bool close_handled = false ;
if ( s_save_state_selector_open & &
2024-04-17 14:41:37 +00:00
ImGui : : BeginChild ( " state_list " ,
ImVec2 ( io . DisplaySize . x , io . DisplaySize . y - LayoutScale ( LAYOUT_FOOTER_HEIGHT ) - heading_size . y ) ,
false , ImGuiWindowFlags_NavFlattened ) )
2022-10-23 04:09:54 +00:00
{
BeginMenuButtons ( ) ;
2021-02-01 15:40:37 +00:00
2022-10-23 04:09:54 +00:00
const ImGuiStyle & style = ImGui : : GetStyle ( ) ;
const float title_spacing = LayoutScale ( 10.0f ) ;
const float summary_spacing = LayoutScale ( 4.0f ) ;
const float item_spacing = LayoutScale ( 20.0f ) ;
const float item_width_with_spacing = std : : floor ( LayoutScale ( LAYOUT_SCREEN_WIDTH / 4.0f ) ) ;
const float item_width = item_width_with_spacing - item_spacing ;
const float image_width = item_width - ( style . FramePadding . x * 2.0f ) ;
const float image_height = image_width / 1.33f ;
const ImVec2 image_size ( image_width , image_height ) ;
const float item_height = ( style . FramePadding . y * 2.0f ) + image_height + title_spacing + g_large_font - > FontSize +
summary_spacing + g_medium_font - > FontSize ;
const ImVec2 item_size ( item_width , item_height ) ;
const u32 grid_count_x = static_cast < u32 > ( std : : floor ( ImGui : : GetWindowWidth ( ) / item_width_with_spacing ) ) ;
const float start_x =
( static_cast < float > ( ImGui : : GetWindowWidth ( ) ) - ( item_width_with_spacing * static_cast < float > ( grid_count_x ) ) ) *
0.5f ;
u32 grid_x = 0 ;
ImGui : : SetCursorPos ( ImVec2 ( start_x , 0.0f ) ) ;
2023-10-08 03:58:45 +00:00
for ( u32 i = 0 ; i < s_save_state_selector_slots . size ( ) ; )
2021-02-01 15:40:37 +00:00
{
2022-10-23 04:09:54 +00:00
if ( i = = 0 )
ResetFocusHere ( ) ;
2021-02-01 15:40:37 +00:00
2022-10-23 04:09:54 +00:00
const SaveStateListEntry & entry = s_save_state_selector_slots [ i ] ;
2023-10-08 03:58:45 +00:00
if ( static_cast < s32 > ( i ) = = s_save_state_selector_submenu_index )
{
// can't use a choice dialog here, because we're already in a modal...
ImGuiFullscreen : : PushResetLayout ( ) ;
ImGui : : PushFont ( g_large_font ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowRounding , LayoutScale ( 10.0f ) ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding ,
LayoutScale ( LAYOUT_MENU_BUTTON_X_PADDING , LAYOUT_MENU_BUTTON_Y_PADDING ) ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_FrameBorderSize , 0.0f ) ;
ImGui : : PushStyleColor ( ImGuiCol_Text , UIPrimaryTextColor ) ;
ImGui : : PushStyleColor ( ImGuiCol_TitleBg , UIPrimaryDarkColor ) ;
ImGui : : PushStyleColor ( ImGuiCol_TitleBgActive , UIPrimaryColor ) ;
const float width = LayoutScale ( 600.0f ) ;
const float title_height =
g_large_font - > FontSize + ImGui : : GetStyle ( ) . FramePadding . y * 2.0f + ImGui : : GetStyle ( ) . WindowPadding . y * 2.0f ;
const float height =
title_height +
LayoutScale ( LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY + ( LAYOUT_MENU_BUTTON_Y_PADDING * 2.0f ) ) * 3.0f ;
ImGui : : SetNextWindowSize ( ImVec2 ( width , height ) ) ;
ImGui : : SetNextWindowPos ( ImGui : : GetIO ( ) . DisplaySize * 0.5f , ImGuiCond_Always , ImVec2 ( 0.5f , 0.5f ) ) ;
ImGui : : OpenPopup ( entry . title . c_str ( ) ) ;
bool removed = false ;
if ( ImGui : : BeginPopupModal ( entry . title . c_str ( ) , & is_open ,
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove ) )
{
ImGui : : PushStyleColor ( ImGuiCol_Text , UIBackgroundTextColor ) ;
BeginMenuButtons ( ) ;
if ( ActiveButton ( is_loading ? FSUI_ICONSTR ( ICON_FA_FOLDER_OPEN , " Load State " ) :
FSUI_ICONSTR ( ICON_FA_FOLDER_OPEN , " Save State " ) ,
false , true , LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ) )
{
if ( is_loading )
DoLoadState ( std : : move ( entry . path ) ) ;
else
DoSaveState ( entry . slot , entry . global ) ;
closed = true ;
}
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_FOLDER_MINUS , " Delete Save " ) , false , true ,
LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ) )
{
if ( ! FileSystem : : FileExists ( entry . path . c_str ( ) ) )
{
ShowToast ( { } , fmt : : format ( FSUI_FSTR ( " {} does not exist. " ) , ImGuiFullscreen : : RemoveHash ( entry . title ) ) ) ;
is_open = true ;
}
else if ( FileSystem : : DeleteFile ( entry . path . c_str ( ) ) )
{
ShowToast ( { } , fmt : : format ( FSUI_FSTR ( " {} deleted. " ) , ImGuiFullscreen : : RemoveHash ( entry . title ) ) ) ;
s_save_state_selector_slots . erase ( s_save_state_selector_slots . begin ( ) + i ) ;
removed = true ;
if ( s_save_state_selector_slots . empty ( ) )
closed = true ;
else
is_open = false ;
}
else
{
ShowToast ( { } , fmt : : format ( FSUI_FSTR ( " Failed to delete {}. " ) , ImGuiFullscreen : : RemoveHash ( entry . title ) ) ) ;
is_open = false ;
}
}
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_WINDOW_CLOSE , " Close Menu " ) , false , true ,
LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ) )
{
is_open = false ;
}
EndMenuButtons ( ) ;
ImGui : : PopStyleColor ( ) ;
ImGui : : EndPopup ( ) ;
}
// don't let the back button flow through to the main window
if ( WantsToCloseMenu ( ) )
{
close_handled = true ;
is_open = false ;
}
if ( ! is_open | | closed )
{
s_save_state_selector_submenu_index = - 1 ;
if ( ! closed )
QueueResetFocus ( ) ;
}
2024-04-11 03:50:04 +00:00
ImGui : : PopStyleColor ( 3 ) ;
2023-10-08 03:58:45 +00:00
ImGui : : PopStyleVar ( 3 ) ;
ImGui : : PopFont ( ) ;
ImGuiFullscreen : : PopResetLayout ( ) ;
if ( removed )
continue ;
}
2022-10-23 04:09:54 +00:00
ImGuiWindow * window = ImGui : : GetCurrentWindow ( ) ;
if ( window - > SkipItems )
2023-10-08 03:58:45 +00:00
{
i + + ;
2022-10-23 04:09:54 +00:00
continue ;
2023-10-08 03:58:45 +00:00
}
2022-07-11 13:03:29 +00:00
2022-10-23 04:09:54 +00:00
const ImGuiID id = window - > GetID ( static_cast < int > ( i ) ) ;
const ImVec2 pos ( window - > DC . CursorPos ) ;
ImRect bb ( pos , pos + item_size ) ;
ImGui : : ItemSize ( item_size ) ;
if ( ImGui : : ItemAdd ( bb , id ) )
{
bool held ;
bool hovered ;
bool pressed = ImGui : : ButtonBehavior ( bb , id , & hovered , & held , 0 ) ;
if ( hovered )
{
const ImU32 col = ImGui : : GetColorU32 ( held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered , 1.0f ) ;
2022-07-11 13:03:29 +00:00
2022-10-23 04:09:54 +00:00
const float t = std : : min ( static_cast < float > ( std : : abs ( std : : sin ( ImGui : : GetTime ( ) * 0.75 ) * 1.1 ) ) , 1.0f ) ;
ImGui : : PushStyleColor ( ImGuiCol_Border , ImGui : : GetColorU32 ( ImGuiCol_Border , t ) ) ;
2022-07-11 13:03:29 +00:00
2023-12-12 15:12:55 +00:00
ImGuiFullscreen : : DrawMenuButtonFrame ( bb . Min , bb . Max , col , true , 0.0f ) ;
2022-10-23 04:09:54 +00:00
ImGui : : PopStyleColor ( ) ;
}
bb . Min + = style . FramePadding ;
bb . Max - = style . FramePadding ;
GPUTexture * const screenshot =
entry . preview_texture ? entry . preview_texture . get ( ) : GetPlaceholderTexture ( ) . get ( ) ;
const ImRect image_rect (
CenterImage ( ImRect ( bb . Min , bb . Min + image_size ) ,
ImVec2 ( static_cast < float > ( screenshot - > GetWidth ( ) ) , static_cast < float > ( screenshot - > GetHeight ( ) ) ) ) ) ;
ImGui : : GetWindowDrawList ( ) - > AddImage ( screenshot , image_rect . Min , image_rect . Max , ImVec2 ( 0.0f , 0.0f ) ,
ImVec2 ( 1.0f , 1.0f ) , IM_COL32 ( 255 , 255 , 255 , 255 ) ) ;
const ImVec2 title_pos ( bb . Min . x , bb . Min . y + image_height + title_spacing ) ;
const ImRect title_bb ( title_pos , ImVec2 ( bb . Max . x , title_pos . y + g_large_font - > FontSize ) ) ;
ImGui : : PushFont ( g_large_font ) ;
ImGui : : RenderTextClipped ( title_bb . Min , title_bb . Max , entry . title . c_str ( ) , nullptr , nullptr , ImVec2 ( 0.0f , 0.0f ) ,
& title_bb ) ;
ImGui : : PopFont ( ) ;
if ( ! entry . summary . empty ( ) )
{
const ImVec2 summary_pos ( bb . Min . x , title_pos . y + g_large_font - > FontSize + summary_spacing ) ;
const ImRect summary_bb ( summary_pos , ImVec2 ( bb . Max . x , summary_pos . y + g_medium_font - > FontSize ) ) ;
ImGui : : PushFont ( g_medium_font ) ;
ImGui : : RenderTextClipped ( summary_bb . Min , summary_bb . Max , entry . summary . c_str ( ) , nullptr , nullptr ,
ImVec2 ( 0.0f , 0.0f ) , & summary_bb ) ;
ImGui : : PopFont ( ) ;
}
if ( pressed )
{
if ( is_loading )
DoLoadState ( entry . path ) ;
else
DoSaveState ( entry . slot , entry . global ) ;
2023-10-08 03:58:45 +00:00
closed = true ;
2022-10-23 04:09:54 +00:00
}
2024-04-09 10:04:45 +00:00
else if ( hovered & &
( ImGui : : IsItemClicked ( ImGuiMouseButton_Right ) | | ImGui : : IsKeyPressed ( ImGuiKey_NavGamepadMenu , false ) | |
ImGui : : IsKeyPressed ( ImGuiKey_F1 , false ) ) )
2022-10-23 04:09:54 +00:00
{
s_save_state_selector_submenu_index = static_cast < s32 > ( i ) ;
}
}
grid_x + + ;
if ( grid_x = = grid_count_x )
{
grid_x = 0 ;
ImGui : : SetCursorPosX ( start_x ) ;
ImGui : : SetCursorPosY ( ImGui : : GetCursorPosY ( ) + item_spacing ) ;
}
2022-07-11 13:03:29 +00:00
else
2022-10-23 04:09:54 +00:00
{
ImGui : : SameLine ( start_x + static_cast < float > ( grid_x ) * ( item_width + item_spacing ) ) ;
}
2023-10-08 03:58:45 +00:00
i + + ;
2021-02-01 15:40:37 +00:00
}
2022-10-23 04:09:54 +00:00
EndMenuButtons ( ) ;
ImGui : : EndChild ( ) ;
2022-07-11 13:03:29 +00:00
}
2021-02-01 15:40:37 +00:00
2022-10-23 04:09:54 +00:00
ImGui : : PopStyleColor ( ) ;
2021-02-01 15:40:37 +00:00
2022-10-23 04:09:54 +00:00
ImGui : : EndPopup ( ) ;
ImGui : : PopStyleVar ( 5 ) ;
2023-10-08 03:58:45 +00:00
if ( closed )
{
CloseSaveStateSelector ( ) ;
ReturnToMainWindow ( ) ;
}
else if ( ! close_handled & & WantsToCloseMenu ( ) )
2023-09-18 12:29:47 +00:00
{
2022-10-23 04:09:54 +00:00
CloseSaveStateSelector ( ) ;
2023-09-18 12:29:47 +00:00
ReturnToPreviousWindow ( ) ;
}
2024-04-09 10:04:45 +00:00
else
{
if ( IsGamepadInputSource ( ) )
{
SetFullscreenFooterText ( std : : array { std : : make_pair ( ICON_PF_XBOX_DPAD , FSUI_VSTR ( " Select State " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_Y , FSUI_VSTR ( " Delete State " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_A , FSUI_VSTR ( " Load State " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_B , FSUI_VSTR ( " Cancel " ) ) } ) ;
}
else
{
SetFullscreenFooterText ( std : : array {
std : : make_pair ( ICON_PF_ARROW_UP ICON_PF_ARROW_DOWN ICON_PF_ARROW_LEFT ICON_PF_ARROW_RIGHT ,
FSUI_VSTR ( " Select State " ) ) ,
std : : make_pair ( ICON_PF_F1 , FSUI_VSTR ( " Delete State " ) ) , std : : make_pair ( ICON_PF_ENTER , FSUI_VSTR ( " Load State " ) ) ,
std : : make_pair ( ICON_PF_ESC , FSUI_VSTR ( " Cancel " ) ) } ) ;
}
}
2021-02-01 15:40:37 +00:00
}
2022-09-17 05:51:05 +00:00
bool FullscreenUI : : OpenLoadStateSelectorForGameResume ( const GameList : : Entry * entry )
{
SaveStateListEntry slentry ;
2024-04-09 10:04:45 +00:00
if ( ! InitializeSaveStateListEntryFromSerial ( & slentry , entry - > serial , - 1 , false ) )
2022-09-17 05:51:05 +00:00
return false ;
CloseSaveStateSelector ( ) ;
s_save_state_selector_slots . push_back ( std : : move ( slentry ) ) ;
s_save_state_selector_game_path = entry - > path ;
s_save_state_selector_loading = true ;
s_save_state_selector_open = true ;
s_save_state_selector_resuming = true ;
return true ;
}
void FullscreenUI : : DrawResumeStateSelector ( )
{
ImGui : : SetNextWindowSize ( LayoutScale ( 800.0f , 600.0f ) ) ;
ImGui : : SetNextWindowPos ( ImGui : : GetIO ( ) . DisplaySize * 0.5f , ImGuiCond_Always , ImVec2 ( 0.5f , 0.5f ) ) ;
2023-08-20 02:38:55 +00:00
ImGui : : OpenPopup ( FSUI_CSTR ( " Load Resume State " ) ) ;
2022-09-17 05:51:05 +00:00
ImGui : : PushFont ( g_large_font ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowRounding , LayoutScale ( 10.0f ) ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowPadding , LayoutScale ( 20.0f , 20.0f ) ) ;
bool is_open = true ;
2023-08-20 02:38:55 +00:00
if ( ImGui : : BeginPopupModal ( FSUI_CSTR ( " Load Resume State " ) , & is_open ,
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize ) )
2022-09-17 05:51:05 +00:00
{
const SaveStateListEntry & entry = s_save_state_selector_slots . front ( ) ;
2023-09-07 10:13:48 +00:00
SmallString time ;
TimeToPrintableString ( & time , entry . timestamp ) ;
2023-08-20 02:38:55 +00:00
ImGui : : TextWrapped (
FSUI_CSTR ( " A resume save state created at %s was found. \n \n Do you want to load this save and continue? " ) ,
2023-09-20 13:49:14 +00:00
time . c_str ( ) ) ;
2022-09-17 05:51:05 +00:00
2022-10-03 06:44:34 +00:00
const GPUTexture * image = entry . preview_texture ? entry . preview_texture . get ( ) : GetPlaceholderTexture ( ) . get ( ) ;
2022-09-17 05:51:05 +00:00
const float image_height = LayoutScale ( 250.0f ) ;
const float image_width =
image_height * ( static_cast < float > ( image - > GetWidth ( ) ) / static_cast < float > ( image - > GetHeight ( ) ) ) ;
const ImVec2 pos ( ImGui : : GetCursorScreenPos ( ) +
ImVec2 ( ( ImGui : : GetCurrentWindow ( ) - > WorkRect . GetWidth ( ) - image_width ) * 0.5f , LayoutScale ( 20.0f ) ) ) ;
const ImRect image_bb ( pos , pos + ImVec2 ( image_width , image_height ) ) ;
2022-10-03 06:44:34 +00:00
ImGui : : GetWindowDrawList ( ) - > AddImage (
static_cast < ImTextureID > ( entry . preview_texture ? entry . preview_texture . get ( ) : GetPlaceholderTexture ( ) . get ( ) ) ,
image_bb . Min , image_bb . Max ) ;
2022-09-17 05:51:05 +00:00
ImGui : : SetCursorPosY ( ImGui : : GetCursorPosY ( ) + image_height + LayoutScale ( 40.0f ) ) ;
BeginMenuButtons ( ) ;
2023-08-20 02:38:55 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_PLAY , " Load State " ) , false ) )
2022-09-17 05:51:05 +00:00
{
DoStartPath ( s_save_state_selector_game_path , std : : move ( entry . path ) ) ;
is_open = false ;
}
2023-08-20 02:38:55 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_LIGHTBULB , " Clean Boot " ) , false ) )
2022-09-17 05:51:05 +00:00
{
DoStartPath ( s_save_state_selector_game_path ) ;
is_open = false ;
}
2023-08-20 02:38:55 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_FOLDER_MINUS , " Delete State " ) , false ) )
2022-09-17 05:51:05 +00:00
{
if ( FileSystem : : DeleteFile ( entry . path . c_str ( ) ) )
{
DoStartPath ( s_save_state_selector_game_path ) ;
is_open = false ;
}
else
{
2023-08-20 02:38:55 +00:00
ShowToast ( std : : string ( ) , FSUI_STR ( " Failed to delete save state. " ) ) ;
2022-09-17 05:51:05 +00:00
}
}
2024-04-07 10:43:13 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_WINDOW_CLOSE , " Cancel " ) , false ) | | WantsToCloseMenu ( ) )
2022-09-17 05:51:05 +00:00
{
ImGui : : CloseCurrentPopup ( ) ;
is_open = false ;
}
EndMenuButtons ( ) ;
ImGui : : EndPopup ( ) ;
}
ImGui : : PopStyleVar ( 2 ) ;
ImGui : : PopFont ( ) ;
if ( ! is_open )
{
ClearSaveStateEntryList ( ) ;
s_save_state_selector_open = false ;
s_save_state_selector_loading = false ;
s_save_state_selector_resuming = false ;
s_save_state_selector_game_path = { } ;
}
2024-04-09 10:04:45 +00:00
else
{
SetStandardSelectionFooterText ( false ) ;
}
2022-09-17 05:51:05 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DoLoadState ( std : : string path )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
Host : : RunOnCPUThread ( [ boot_path = s_save_state_selector_game_path , path = std : : move ( path ) ] ( ) {
CloseSaveStateSelector ( ) ;
if ( System : : IsValid ( ) )
{
2024-04-11 03:42:10 +00:00
Error error ;
if ( ! System : : LoadState ( path . c_str ( ) , & error ) )
{
Host : : ReportErrorAsync ( TRANSLATE_SV ( " System " , " Error " ) ,
fmt : : format ( TRANSLATE_FS ( " System " , " Failed to load state: {} " ) , error . GetDescription ( ) ) ) ;
}
2022-07-11 13:03:29 +00:00
}
else
{
2024-04-11 03:42:10 +00:00
DoStartPath ( std : : move ( boot_path ) , std : : move ( path ) ) ;
2022-07-11 13:03:29 +00:00
}
} ) ;
2021-02-24 08:56:41 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DoSaveState ( s32 slot , bool global )
2021-02-24 08:56:41 +00:00
{
2022-07-11 13:03:29 +00:00
Host : : RunOnCPUThread ( [ slot , global ] ( ) {
CloseSaveStateSelector ( ) ;
if ( ! System : : IsValid ( ) )
return ;
std : : string filename ( global ? System : : GetGlobalSaveStateFileName ( slot ) :
2023-05-15 13:38:37 +00:00
System : : GetGameSaveStateFileName ( System : : GetGameSerial ( ) , slot ) ) ;
2024-04-11 03:42:10 +00:00
Error error ;
if ( ! System : : SaveState ( filename . c_str ( ) , & error , g_settings . create_save_state_backups ) )
{
Host : : ReportErrorAsync ( TRANSLATE_SV ( " System " , " Error " ) ,
fmt : : format ( TRANSLATE_FS ( " System " , " Failed to save state: {} " ) , error . GetDescription ( ) ) ) ;
}
2022-07-11 13:03:29 +00:00
} ) ;
2021-02-24 08:56:41 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : PopulateGameListEntryList ( )
2021-02-24 08:56:41 +00:00
{
2022-10-23 04:09:54 +00:00
const s32 sort = Host : : GetBaseIntSettingValue ( " Main " , " FullscreenUIGameSort " , 0 ) ;
const bool reverse = Host : : GetBaseBoolSettingValue ( " Main " , " FullscreenUIGameSortReverse " , false ) ;
2022-07-11 13:03:29 +00:00
const u32 count = GameList : : GetEntryCount ( ) ;
s_game_list_sorted_entries . resize ( count ) ;
for ( u32 i = 0 ; i < count ; i + + )
s_game_list_sorted_entries [ i ] = GameList : : GetEntryByIndex ( i ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
std : : sort ( s_game_list_sorted_entries . begin ( ) , s_game_list_sorted_entries . end ( ) ,
2022-10-23 04:09:54 +00:00
[ sort , reverse ] ( const GameList : : Entry * lhs , const GameList : : Entry * rhs ) {
switch ( sort )
{
case 0 : // Type
{
if ( lhs - > type ! = rhs - > type )
return reverse ? ( lhs - > type > rhs - > type ) : ( lhs - > type < rhs - > type ) ;
}
break ;
case 1 : // Serial
{
if ( lhs - > serial ! = rhs - > serial )
return reverse ? ( lhs - > serial > rhs - > serial ) : ( lhs - > serial < rhs - > serial ) ;
}
break ;
case 2 : // Title
break ;
case 3 : // File Title
{
const std : : string_view lhs_title ( Path : : GetFileTitle ( lhs - > path ) ) ;
const std : : string_view rhs_title ( Path : : GetFileTitle ( rhs - > path ) ) ;
const int res = StringUtil : : Strncasecmp ( lhs_title . data ( ) , rhs_title . data ( ) ,
std : : min ( lhs_title . size ( ) , rhs_title . size ( ) ) ) ;
if ( res ! = 0 )
return reverse ? ( res > 0 ) : ( res < 0 ) ;
}
break ;
case 4 : // Time Played
{
if ( lhs - > total_played_time ! = rhs - > total_played_time )
{
return reverse ? ( lhs - > total_played_time > rhs - > total_played_time ) :
( lhs - > total_played_time < rhs - > total_played_time ) ;
}
}
break ;
case 5 : // Last Played (reversed by default)
{
if ( lhs - > last_played_time ! = rhs - > last_played_time )
{
return reverse ? ( lhs - > last_played_time < rhs - > last_played_time ) :
( lhs - > last_played_time > rhs - > last_played_time ) ;
}
}
break ;
2023-12-20 13:40:24 +00:00
case 6 : // File Size
2022-10-23 04:09:54 +00:00
{
2023-12-20 13:40:24 +00:00
if ( lhs - > file_size ! = rhs - > file_size )
2022-10-23 04:09:54 +00:00
{
2023-12-20 13:40:24 +00:00
return reverse ? ( lhs - > file_size > rhs - > file_size ) : ( lhs - > file_size < rhs - > file_size ) ;
}
}
break ;
case 7 : // Uncompressed Size
{
if ( lhs - > uncompressed_size ! = rhs - > uncompressed_size )
{
return reverse ? ( lhs - > uncompressed_size > rhs - > uncompressed_size ) :
( lhs - > uncompressed_size < rhs - > uncompressed_size ) ;
2022-10-23 04:09:54 +00:00
}
}
break ;
}
// fallback to title when all else is equal
const int res = StringUtil : : Strcasecmp ( lhs - > title . c_str ( ) , rhs - > title . c_str ( ) ) ;
return reverse ? ( res > 0 ) : ( res < 0 ) ;
2022-09-17 05:51:05 +00:00
} ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DrawGameListWindow ( )
2021-01-30 11:37:49 +00:00
{
2022-09-17 05:51:05 +00:00
auto game_list_lock = GameList : : GetLock ( ) ;
PopulateGameListEntryList ( ) ;
ImGuiIO & io = ImGui : : GetIO ( ) ;
ImVec2 heading_size = ImVec2 (
io . DisplaySize . x , LayoutScale ( LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY + LAYOUT_MENU_BUTTON_Y_PADDING * 2.0f + 2.0f ) ) ;
const float bg_alpha = System : : IsValid ( ) ? 0.90f : 1.0f ;
if ( BeginFullscreenWindow ( ImVec2 ( 0.0f , 0.0f ) , heading_size , " gamelist_view " , MulAlpha ( UIPrimaryColor , bg_alpha ) ) )
{
static constexpr float ITEM_WIDTH = 25.0f ;
2024-04-09 10:04:45 +00:00
static constexpr const char * icons [ ] = { ICON_FA_BORDER_ALL , ICON_FA_LIST } ;
static constexpr const char * titles [ ] = { FSUI_NSTR ( " Game Grid " ) , FSUI_NSTR ( " Game List " ) } ;
2022-09-17 05:51:05 +00:00
static constexpr u32 count = static_cast < u32 > ( std : : size ( titles ) ) ;
BeginNavBar ( ) ;
if ( NavButton ( ICON_FA_BACKWARD , true , true ) )
2023-09-18 12:29:47 +00:00
ReturnToPreviousWindow ( ) ;
2022-09-17 05:51:05 +00:00
2024-04-09 10:04:45 +00:00
NavTitle ( Host : : TranslateToCString ( TR_CONTEXT , titles [ static_cast < u32 > ( s_game_list_view ) ] ) ) ;
2022-09-17 05:51:05 +00:00
RightAlignNavButtons ( count , ITEM_WIDTH , LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ) ;
for ( u32 i = 0 ; i < count ; i + + )
{
2024-04-09 10:04:45 +00:00
if ( NavButton ( icons [ i ] , static_cast < GameListView > ( i ) = = s_game_list_view , true , ITEM_WIDTH ,
2022-09-17 05:51:05 +00:00
LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY ) )
{
2024-04-09 10:04:45 +00:00
s_game_list_view = static_cast < GameListView > ( i ) ;
2022-09-17 05:51:05 +00:00
}
}
EndNavBar ( ) ;
}
EndFullscreenWindow ( ) ;
2024-04-09 10:04:45 +00:00
if ( ImGui : : IsKeyPressed ( ImGuiKey_NavGamepadInput , false ) | | ImGui : : IsKeyPressed ( ImGuiKey_F1 , false ) )
2022-09-17 05:51:05 +00:00
{
2024-04-09 10:04:45 +00:00
s_game_list_view = ( s_game_list_view = = GameListView : : Grid ) ? GameListView : : List : GameListView : : Grid ;
}
else if ( ImGui : : IsKeyPressed ( ImGuiKey_GamepadStart , false ) | | ImGui : : IsKeyPressed ( ImGuiKey_F2 ) )
{
s_current_main_window = MainWindowType : : GameListSettings ;
QueueResetFocus ( ) ;
}
switch ( s_game_list_view )
{
case GameListView : : Grid :
2022-09-17 05:51:05 +00:00
DrawGameGrid ( heading_size ) ;
break ;
2024-04-09 10:04:45 +00:00
case GameListView : : List :
2022-09-17 05:51:05 +00:00
DrawGameList ( heading_size ) ;
break ;
default :
break ;
}
2024-04-09 10:04:45 +00:00
if ( IsGamepadInputSource ( ) )
{
SetFullscreenFooterText ( std : : array { std : : make_pair ( ICON_PF_XBOX_DPAD , FSUI_VSTR ( " Select Game " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_X , FSUI_VSTR ( " Change View " ) ) ,
std : : make_pair ( ICON_PF_BURGER_MENU , FSUI_VSTR ( " Settings " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_Y , FSUI_VSTR ( " Launch Options " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_A , FSUI_VSTR ( " Start Game " ) ) ,
std : : make_pair ( ICON_PF_BUTTON_B , FSUI_VSTR ( " Back " ) ) } ) ;
}
else
{
SetFullscreenFooterText ( std : : array {
std : : make_pair ( ICON_PF_ARROW_UP ICON_PF_ARROW_DOWN ICON_PF_ARROW_LEFT ICON_PF_ARROW_RIGHT ,
FSUI_VSTR ( " Select Game " ) ) ,
std : : make_pair ( ICON_PF_F1 , FSUI_VSTR ( " Change View " ) ) , std : : make_pair ( ICON_PF_F2 , FSUI_VSTR ( " Settings " ) ) ,
std : : make_pair ( ICON_PF_F3 , FSUI_VSTR ( " Launch Options " ) ) , std : : make_pair ( ICON_PF_ENTER , FSUI_VSTR ( " Start Game " ) ) ,
std : : make_pair ( ICON_PF_ESC , FSUI_VSTR ( " Back " ) ) } ) ;
}
2022-09-17 05:51:05 +00:00
}
void FullscreenUI : : DrawGameList ( const ImVec2 & heading_size )
{
2024-04-09 10:04:45 +00:00
if ( ! BeginFullscreenColumns ( nullptr , heading_size . y , true , true ) )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
EndFullscreenColumns ( ) ;
return ;
2021-01-30 11:37:49 +00:00
}
2024-04-13 04:41:10 +00:00
if ( ! AreAnyDialogsOpen ( ) & & WantsToCloseMenu ( ) )
ReturnToPreviousWindow ( ) ;
2022-07-11 13:03:29 +00:00
auto game_list_lock = GameList : : GetLock ( ) ;
const GameList : : Entry * selected_entry = nullptr ;
PopulateGameListEntryList ( ) ;
2022-09-17 05:51:05 +00:00
if ( BeginFullscreenColumnWindow ( 0.0f , - 530.0f , " game_list_entries " ) )
2021-01-30 11:37:49 +00:00
{
2022-09-17 05:51:05 +00:00
const ImVec2 image_size ( LayoutScale ( LAYOUT_MENU_BUTTON_HEIGHT , LAYOUT_MENU_BUTTON_HEIGHT ) ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
ResetFocusHere ( ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
BeginMenuButtons ( ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
SmallString summary ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
for ( const GameList : : Entry * entry : s_game_list_sorted_entries )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
ImRect bb ;
bool visible , hovered ;
bool pressed =
MenuButtonFrame ( entry - > path . c_str ( ) , true , LAYOUT_MENU_BUTTON_HEIGHT , & visible , & hovered , & bb . Min , & bb . Max ) ;
if ( ! visible )
continue ;
2021-01-30 11:37:49 +00:00
2022-10-03 06:44:34 +00:00
GPUTexture * cover_texture = GetGameListCover ( entry ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
if ( entry - > serial . empty ( ) )
2023-12-13 11:06:15 +00:00
summary . format ( " {} - " , Settings : : GetDiscRegionDisplayName ( entry - > region ) ) ;
2021-01-30 11:37:49 +00:00
else
2023-12-13 11:06:15 +00:00
summary . format ( " {} - {} - " , entry - > serial , Settings : : GetDiscRegionDisplayName ( entry - > region ) ) ;
2021-01-30 11:37:49 +00:00
2023-09-20 13:49:14 +00:00
summary . append ( Path : : GetFileName ( entry - > path ) ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
const ImRect image_rect (
CenterImage ( ImRect ( bb . Min , bb . Min + image_size ) , ImVec2 ( static_cast < float > ( cover_texture - > GetWidth ( ) ) ,
static_cast < float > ( cover_texture - > GetHeight ( ) ) ) ) ) ;
2021-01-30 11:37:49 +00:00
2022-10-03 06:44:34 +00:00
ImGui : : GetWindowDrawList ( ) - > AddImage ( cover_texture , image_rect . Min , image_rect . Max , ImVec2 ( 0.0f , 0.0f ) ,
ImVec2 ( 1.0f , 1.0f ) , IM_COL32 ( 255 , 255 , 255 , 255 ) ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
const float midpoint = bb . Min . y + g_large_font - > FontSize + LayoutScale ( 4.0f ) ;
const float text_start_x = bb . Min . x + image_size . x + LayoutScale ( 15.0f ) ;
const ImRect title_bb ( ImVec2 ( text_start_x , bb . Min . y ) , ImVec2 ( bb . Max . x , midpoint ) ) ;
const ImRect summary_bb ( ImVec2 ( text_start_x , midpoint ) , bb . Max ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
ImGui : : PushFont ( g_large_font ) ;
ImGui : : RenderTextClipped ( title_bb . Min , title_bb . Max , entry - > title . c_str ( ) ,
entry - > title . c_str ( ) + entry - > title . size ( ) , nullptr , ImVec2 ( 0.0f , 0.0f ) , & title_bb ) ;
ImGui : : PopFont ( ) ;
2021-01-30 11:37:49 +00:00
2023-09-20 13:49:14 +00:00
if ( ! summary . empty ( ) )
2022-07-11 13:03:29 +00:00
{
ImGui : : PushFont ( g_medium_font ) ;
2023-09-20 13:49:14 +00:00
ImGui : : RenderTextClipped ( summary_bb . Min , summary_bb . Max , summary . c_str ( ) , summary . end_ptr ( ) , nullptr ,
ImVec2 ( 0.0f , 0.0f ) , & summary_bb ) ;
2022-07-11 13:03:29 +00:00
ImGui : : PopFont ( ) ;
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
if ( pressed )
2024-04-07 10:43:13 +00:00
{
2022-09-17 05:51:05 +00:00
HandleGameListActivate ( entry ) ;
2024-04-07 10:43:13 +00:00
}
else
2022-07-11 13:03:29 +00:00
{
2024-04-07 10:43:13 +00:00
if ( hovered )
selected_entry = entry ;
if ( selected_entry & &
2024-04-09 10:04:45 +00:00
( ImGui : : IsItemClicked ( ImGuiMouseButton_Right ) | | ImGui : : IsKeyPressed ( ImGuiKey_NavGamepadMenu , false ) | |
ImGui : : IsKeyPressed ( ImGuiKey_F3 , false ) ) )
2024-04-07 10:43:13 +00:00
{
HandleGameListOptions ( selected_entry ) ;
}
2022-07-11 13:03:29 +00:00
}
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
EndMenuButtons ( ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
EndFullscreenColumnWindow ( ) ;
2021-01-30 11:37:49 +00:00
2022-09-17 05:51:05 +00:00
if ( BeginFullscreenColumnWindow ( - 530.0f , 0.0f , " game_list_info " , UIPrimaryDarkColor ) )
2021-01-30 11:37:49 +00:00
{
2022-10-03 06:44:34 +00:00
const GPUTexture * cover_texture =
2022-07-11 13:03:29 +00:00
selected_entry ? GetGameListCover ( selected_entry ) : GetTextureForGameListEntryType ( GameList : : EntryType : : Count ) ;
if ( cover_texture )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
const ImRect image_rect (
2022-09-17 05:51:05 +00:00
CenterImage ( LayoutScale ( ImVec2 ( 350.0f , 350.0f ) ) , ImVec2 ( static_cast < float > ( cover_texture - > GetWidth ( ) ) ,
2022-07-11 13:03:29 +00:00
static_cast < float > ( cover_texture - > GetHeight ( ) ) ) ) ) ;
2024-04-09 10:04:45 +00:00
ImGui : : SetCursorPos ( LayoutScale ( ImVec2 ( 90.0f , 0.0f ) ) + image_rect . Min ) ;
2022-10-03 06:44:34 +00:00
ImGui : : Image ( selected_entry ? GetGameListCover ( selected_entry ) :
GetTextureForGameListEntryType ( GameList : : EntryType : : Count ) ,
2022-07-11 13:03:29 +00:00
image_rect . GetSize ( ) ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
const float work_width = ImGui : : GetCurrentWindow ( ) - > WorkRect . GetWidth ( ) ;
constexpr float field_margin_y = 10.0f ;
constexpr float start_x = 50.0f ;
2024-04-09 10:04:45 +00:00
float text_y = 400.0f ;
2022-07-11 13:03:29 +00:00
float text_width ;
2022-09-17 05:51:05 +00:00
PushPrimaryColor ( ) ;
2022-07-11 13:03:29 +00:00
ImGui : : SetCursorPos ( LayoutScale ( start_x , text_y ) ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_ItemSpacing , ImVec2 ( 0.0f , field_margin_y ) ) ;
ImGui : : BeginGroup ( ) ;
if ( selected_entry )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
// title
ImGui : : PushFont ( g_large_font ) ;
text_width = ImGui : : CalcTextSize ( selected_entry - > title . c_str ( ) , nullptr , false , work_width ) . x ;
ImGui : : SetCursorPosX ( ( work_width - text_width ) / 2.0f ) ;
ImGui : : TextWrapped ( " %s " , selected_entry - > title . c_str ( ) ) ;
ImGui : : PopFont ( ) ;
ImGui : : PushFont ( g_medium_font ) ;
// developer
if ( ! selected_entry - > developer . empty ( ) )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
text_width =
ImGui : : CalcTextSize ( selected_entry - > developer . c_str ( ) ,
selected_entry - > developer . c_str ( ) + selected_entry - > developer . length ( ) , false , work_width )
. x ;
ImGui : : SetCursorPosX ( ( work_width - text_width ) / 2.0f ) ;
2022-10-21 11:02:19 +00:00
ImGui : : TextWrapped ( " %s " , selected_entry - > developer . c_str ( ) ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
// code
text_width = ImGui : : CalcTextSize ( selected_entry - > serial . c_str ( ) , nullptr , false , work_width ) . x ;
ImGui : : SetCursorPosX ( ( work_width - text_width ) / 2.0f ) ;
ImGui : : TextWrapped ( " %s " , selected_entry - > serial . c_str ( ) ) ;
ImGui : : SetCursorPosY ( ImGui : : GetCursorPosY ( ) + 15.0f ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
// region
2021-01-30 11:37:49 +00:00
{
2023-12-06 10:12:08 +00:00
const TinyString flag_texture =
2023-12-13 11:06:15 +00:00
TinyString : : from_format ( " fullscreenui/{}.png " , Settings : : GetDiscRegionName ( selected_entry - > region ) ) ;
2023-08-20 02:38:55 +00:00
ImGui : : TextUnformatted ( FSUI_CSTR ( " Region: " ) ) ;
2022-07-11 13:03:29 +00:00
ImGui : : SameLine ( ) ;
2022-10-03 06:44:34 +00:00
ImGui : : Image ( GetCachedTextureAsync ( flag_texture . c_str ( ) ) , LayoutScale ( 23.0f , 16.0f ) ) ;
2022-07-11 13:03:29 +00:00
ImGui : : SameLine ( ) ;
ImGui : : Text ( " (%s) " , Settings : : GetDiscRegionDisplayName ( selected_entry - > region ) ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
// genre
2023-08-20 02:38:55 +00:00
ImGui : : Text ( FSUI_CSTR ( " Genre: %s " ) , selected_entry - > genre . c_str ( ) ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
// release date
char release_date_str [ 64 ] ;
selected_entry - > GetReleaseDateString ( release_date_str , sizeof ( release_date_str ) ) ;
2023-08-20 02:38:55 +00:00
ImGui : : Text ( FSUI_CSTR ( " Release Date: %s " ) , release_date_str ) ;
2022-07-11 13:03:29 +00:00
// compatibility
2023-08-20 02:38:55 +00:00
ImGui : : TextUnformatted ( FSUI_CSTR ( " Compatibility: " ) ) ;
2022-07-11 13:03:29 +00:00
ImGui : : SameLine ( ) ;
if ( selected_entry - > compatibility ! = GameDatabase : : CompatibilityRating : : Unknown )
2021-01-30 11:37:49 +00:00
{
2022-10-03 06:44:34 +00:00
ImGui : : Image ( s_game_compatibility_textures [ static_cast < u32 > ( selected_entry - > compatibility ) ] . get ( ) ,
2022-07-11 13:03:29 +00:00
LayoutScale ( 64.0f , 16.0f ) ) ;
ImGui : : SameLine ( ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
ImGui : : Text ( " (%s) " , GameDatabase : : GetCompatibilityRatingDisplayName ( selected_entry - > compatibility ) ) ;
2021-01-30 11:37:49 +00:00
2022-10-21 11:02:19 +00:00
// play time
2023-09-20 13:49:14 +00:00
ImGui : : Text ( FSUI_CSTR ( " Time Played: %s " ) , GameList : : FormatTimespan ( selected_entry - > total_played_time ) . c_str ( ) ) ;
ImGui : : Text ( FSUI_CSTR ( " Last Played: %s " ) , GameList : : FormatTimestamp ( selected_entry - > last_played_time ) . c_str ( ) ) ;
2022-10-21 11:02:19 +00:00
2022-07-11 13:03:29 +00:00
// size
2023-12-20 13:40:24 +00:00
if ( selected_entry - > file_size > = 0 )
ImGui : : Text ( FSUI_CSTR ( " File Size: %.2f MB " ) , static_cast < float > ( selected_entry - > file_size ) / 1048576.0f ) ;
else
ImGui : : TextUnformatted ( FSUI_CSTR ( " Unknown File Size " ) ) ;
ImGui : : Text ( FSUI_CSTR ( " Uncompressed Size: %.2f MB " ) ,
static_cast < float > ( selected_entry - > uncompressed_size ) / 1048576.0f ) ;
2022-07-11 13:03:29 +00:00
ImGui : : PopFont ( ) ;
}
else
{
// title
2023-08-20 02:38:55 +00:00
const char * title = FSUI_CSTR ( " No Game Selected " ) ;
2022-07-11 13:03:29 +00:00
ImGui : : PushFont ( g_large_font ) ;
text_width = ImGui : : CalcTextSize ( title , nullptr , false , work_width ) . x ;
ImGui : : SetCursorPosX ( ( work_width - text_width ) / 2.0f ) ;
ImGui : : TextWrapped ( " %s " , title ) ;
ImGui : : PopFont ( ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
ImGui : : EndGroup ( ) ;
ImGui : : PopStyleVar ( ) ;
2022-09-17 05:51:05 +00:00
PopPrimaryColor ( ) ;
}
EndFullscreenColumnWindow ( ) ;
2022-07-11 13:03:29 +00:00
2022-09-17 05:51:05 +00:00
EndFullscreenColumns ( ) ;
}
void FullscreenUI : : DrawGameGrid ( const ImVec2 & heading_size )
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
2024-04-09 10:04:45 +00:00
if ( ! BeginFullscreenWindow (
ImVec2 ( 0.0f , heading_size . y ) ,
ImVec2 ( io . DisplaySize . x , io . DisplaySize . y - heading_size . y - LayoutScale ( LAYOUT_FOOTER_HEIGHT ) ) , " game_grid " ,
UIBackgroundColor ) )
2022-09-17 05:51:05 +00:00
{
EndFullscreenWindow ( ) ;
return ;
}
2024-04-13 04:41:10 +00:00
if ( ImGui : : IsWindowFocused ( ) & & WantsToCloseMenu ( ) )
ReturnToPreviousWindow ( ) ;
2022-09-17 05:51:05 +00:00
ResetFocusHere ( ) ;
BeginMenuButtons ( ) ;
const ImGuiStyle & style = ImGui : : GetStyle ( ) ;
const float title_spacing = LayoutScale ( 10.0f ) ;
const float item_spacing = LayoutScale ( 20.0f ) ;
const float item_width_with_spacing = std : : floor ( LayoutScale ( LAYOUT_SCREEN_WIDTH / 5.0f ) ) ;
const float item_width = item_width_with_spacing - item_spacing ;
const float image_width = item_width - ( style . FramePadding . x * 2.0f ) ;
const float image_height = image_width ;
const ImVec2 image_size ( image_width , image_height ) ;
const float item_height = ( style . FramePadding . y * 2.0f ) + image_height + title_spacing + g_medium_font - > FontSize ;
const ImVec2 item_size ( item_width , item_height ) ;
const u32 grid_count_x = static_cast < u32 > ( std : : floor ( ImGui : : GetWindowWidth ( ) / item_width_with_spacing ) ) ;
const float start_x =
( static_cast < float > ( ImGui : : GetWindowWidth ( ) ) - ( item_width_with_spacing * static_cast < float > ( grid_count_x ) ) ) * 0.5f ;
SmallString draw_title ;
u32 grid_x = 0 ;
ImGui : : SetCursorPos ( ImVec2 ( start_x , 0.0f ) ) ;
for ( const GameList : : Entry * entry : s_game_list_sorted_entries )
{
ImGuiWindow * window = ImGui : : GetCurrentWindow ( ) ;
if ( window - > SkipItems )
continue ;
const ImGuiID id = window - > GetID ( entry - > path . c_str ( ) , entry - > path . c_str ( ) + entry - > path . length ( ) ) ;
const ImVec2 pos ( window - > DC . CursorPos ) ;
ImRect bb ( pos , pos + item_size ) ;
ImGui : : ItemSize ( item_size ) ;
if ( ImGui : : ItemAdd ( bb , id ) )
{
bool held ;
bool hovered ;
bool pressed = ImGui : : ButtonBehavior ( bb , id , & hovered , & held , 0 ) ;
if ( hovered )
{
const ImU32 col = ImGui : : GetColorU32 ( held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered , 1.0f ) ;
const float t = static_cast < float > ( std : : min ( std : : abs ( std : : sin ( ImGui : : GetTime ( ) * 0.75 ) * 1.1 ) , 1.0 ) ) ;
ImGui : : PushStyleColor ( ImGuiCol_Border , ImGui : : GetColorU32 ( ImGuiCol_Border , t ) ) ;
2023-12-12 15:12:55 +00:00
ImGuiFullscreen : : DrawMenuButtonFrame ( bb . Min , bb . Max , col , true , 0.0f ) ;
2022-09-17 05:51:05 +00:00
ImGui : : PopStyleColor ( ) ;
}
bb . Min + = style . FramePadding ;
bb . Max - = style . FramePadding ;
2022-10-03 06:44:34 +00:00
GPUTexture * const cover_texture = GetGameListCover ( entry ) ;
2022-09-17 05:51:05 +00:00
const ImRect image_rect (
CenterImage ( ImRect ( bb . Min , bb . Min + image_size ) , ImVec2 ( static_cast < float > ( cover_texture - > GetWidth ( ) ) ,
static_cast < float > ( cover_texture - > GetHeight ( ) ) ) ) ) ;
2022-10-03 06:44:34 +00:00
ImGui : : GetWindowDrawList ( ) - > AddImage ( cover_texture , image_rect . Min , image_rect . Max , ImVec2 ( 0.0f , 0.0f ) ,
ImVec2 ( 1.0f , 1.0f ) , IM_COL32 ( 255 , 255 , 255 , 255 ) ) ;
2022-09-17 05:51:05 +00:00
const ImRect title_bb ( ImVec2 ( bb . Min . x , bb . Min . y + image_height + title_spacing ) , bb . Max ) ;
const std : : string_view title (
std : : string_view ( entry - > title ) . substr ( 0 , ( entry - > title . length ( ) > 31 ) ? 31 : std : : string_view : : npos ) ) ;
2023-12-13 11:06:15 +00:00
draw_title . format ( " {}{} " , title , ( title . length ( ) = = entry - > title . length ( ) ) ? " " : " ... " ) ;
2022-09-17 05:51:05 +00:00
ImGui : : PushFont ( g_medium_font ) ;
2023-09-20 13:49:14 +00:00
ImGui : : RenderTextClipped ( title_bb . Min , title_bb . Max , draw_title . c_str ( ) , draw_title . end_ptr ( ) , nullptr ,
ImVec2 ( 0.5f , 0.0f ) , & title_bb ) ;
2022-09-17 05:51:05 +00:00
ImGui : : PopFont ( ) ;
if ( pressed )
2024-04-07 10:43:13 +00:00
{
2022-09-17 05:51:05 +00:00
HandleGameListActivate ( entry ) ;
2024-04-07 10:43:13 +00:00
}
else if ( hovered & &
2024-04-09 10:04:45 +00:00
( ImGui : : IsItemClicked ( ImGuiMouseButton_Right ) | | ImGui : : IsKeyPressed ( ImGuiKey_NavGamepadMenu , false ) | |
ImGui : : IsKeyPressed ( ImGuiKey_F3 , false ) ) )
2022-09-17 05:51:05 +00:00
{
HandleGameListOptions ( entry ) ;
}
}
grid_x + + ;
if ( grid_x = = grid_count_x )
{
grid_x = 0 ;
ImGui : : SetCursorPosX ( start_x ) ;
ImGui : : SetCursorPosY ( ImGui : : GetCursorPosY ( ) + item_spacing ) ;
}
else
{
ImGui : : SameLine ( start_x + static_cast < float > ( grid_x ) * ( item_width + item_spacing ) ) ;
}
}
EndMenuButtons ( ) ;
EndFullscreenWindow ( ) ;
}
void FullscreenUI : : HandleGameListActivate ( const GameList : : Entry * entry )
{
// launch game
if ( ! OpenLoadStateSelectorForGameResume ( entry ) )
DoStartPath ( entry - > path ) ;
}
void FullscreenUI : : HandleGameListOptions ( const GameList : : Entry * entry )
{
ImGuiFullscreen : : ChoiceDialogOptions options = {
2023-08-20 02:38:55 +00:00
{ FSUI_ICONSTR ( ICON_FA_WRENCH , " Game Properties " ) , false } ,
2024-04-16 02:43:23 +00:00
{ FSUI_ICONSTR ( ICON_FA_FOLDER_OPEN , " Open Containing Directory " ) , false } ,
2023-08-20 02:38:55 +00:00
{ FSUI_ICONSTR ( ICON_FA_PLAY , " Resume Game " ) , false } ,
{ FSUI_ICONSTR ( ICON_FA_UNDO , " Load State " ) , false } ,
{ FSUI_ICONSTR ( ICON_FA_COMPACT_DISC , " Default Boot " ) , false } ,
{ FSUI_ICONSTR ( ICON_FA_LIGHTBULB , " Fast Boot " ) , false } ,
{ FSUI_ICONSTR ( ICON_FA_MAGIC , " Slow Boot " ) , false } ,
{ FSUI_ICONSTR ( ICON_FA_FOLDER_MINUS , " Reset Play Time " ) , false } ,
{ FSUI_ICONSTR ( ICON_FA_WINDOW_CLOSE , " Close Menu " ) , false } ,
2022-09-17 05:51:05 +00:00
} ;
OpenChoiceDialog (
entry - > title . c_str ( ) , false , std : : move ( options ) ,
[ entry_path = entry - > path , entry_serial = entry - > serial ] ( s32 index , const std : : string & title , bool checked ) {
switch ( index )
{
case 0 : // Open Game Properties
SwitchToGameSettingsForPath ( entry_path ) ;
break ;
2024-04-16 02:43:23 +00:00
case 1 : // Open Containing Directory
ExitFullscreenAndOpenURL ( Path : : CreateFileURL ( Path : : GetDirectory ( entry_path ) ) ) ;
break ;
case 2 : // Resume Game
2022-09-17 05:51:05 +00:00
DoStartPath ( entry_path , System : : GetGameSaveStateFileName ( entry_serial , - 1 ) ) ;
break ;
2024-04-16 02:43:23 +00:00
case 3 : // Load State
2022-09-17 05:51:05 +00:00
OpenLoadStateSelectorForGame ( entry_path ) ;
break ;
2024-04-16 02:43:23 +00:00
case 4 : // Default Boot
2022-09-17 05:51:05 +00:00
DoStartPath ( entry_path ) ;
break ;
2024-04-16 02:43:23 +00:00
case 5 : // Fast Boot
2022-09-17 05:51:05 +00:00
DoStartPath ( entry_path , { } , true ) ;
break ;
2024-04-16 02:43:23 +00:00
case 6 : // Slow Boot
2022-09-17 05:51:05 +00:00
DoStartPath ( entry_path , { } , false ) ;
break ;
2024-04-16 02:43:23 +00:00
case 7 : // Reset Play Time
2023-01-11 10:21:27 +00:00
GameList : : ClearPlayedTimeForSerial ( entry_serial ) ;
break ;
2022-09-17 05:51:05 +00:00
default :
break ;
}
CloseChoiceDialog ( ) ;
} ) ;
}
2024-04-09 10:04:45 +00:00
void FullscreenUI : : DrawGameListSettingsWindow ( )
2022-09-17 05:51:05 +00:00
{
2024-04-09 10:04:45 +00:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
ImVec2 heading_size = ImVec2 (
io . DisplaySize . x , LayoutScale ( LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY + LAYOUT_MENU_BUTTON_Y_PADDING * 2.0f + 2.0f ) ) ;
const float bg_alpha = System : : IsValid ( ) ? 0.90f : 1.0f ;
if ( BeginFullscreenWindow ( ImVec2 ( 0.0f , 0.0f ) , heading_size , " gamelist_view " , MulAlpha ( UIPrimaryColor , bg_alpha ) ) )
{
BeginNavBar ( ) ;
if ( NavButton ( ICON_FA_BACKWARD , true , true ) )
{
s_current_main_window = MainWindowType : : GameList ;
QueueResetFocus ( ) ;
}
NavTitle ( FSUI_CSTR ( " Game List Settings " ) ) ;
EndNavBar ( ) ;
}
EndFullscreenWindow ( ) ;
if ( ! BeginFullscreenWindow (
ImVec2 ( 0.0f , heading_size . y ) ,
ImVec2 ( io . DisplaySize . x , io . DisplaySize . y - heading_size . y - LayoutScale ( LAYOUT_FOOTER_HEIGHT ) ) ,
" settings_parent " , UIBackgroundColor ) )
2022-09-17 05:51:05 +00:00
{
EndFullscreenWindow ( ) ;
return ;
}
2024-04-13 04:41:10 +00:00
if ( ImGui : : IsWindowFocused ( ) & & WantsToCloseMenu ( ) )
2022-09-17 05:51:05 +00:00
{
2024-04-13 04:41:10 +00:00
s_current_main_window = MainWindowType : : GameList ;
QueueResetFocus ( ) ;
2022-09-17 05:51:05 +00:00
}
auto lock = Host : : GetSettingsLock ( ) ;
SettingsInterface * bsi = GetEditingSettingsInterface ( false ) ;
BeginMenuButtons ( ) ;
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " Search Directories " ) ) ;
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_FOLDER_PLUS , " Add Search Directory " ) ,
FSUI_CSTR ( " Adds a new directory to the game search list. " ) ) )
2022-09-17 05:51:05 +00:00
{
2023-08-20 02:38:55 +00:00
OpenFileSelector ( FSUI_ICONSTR ( ICON_FA_FOLDER_PLUS , " Add Search Directory " ) , true , [ ] ( const std : : string & dir ) {
2022-09-17 05:51:05 +00:00
if ( ! dir . empty ( ) )
{
auto lock = Host : : GetSettingsLock ( ) ;
SettingsInterface * bsi = Host : : Internal : : GetBaseSettingsLayer ( ) ;
bsi - > AddToStringList ( " GameList " , " RecursivePaths " , dir . c_str ( ) ) ;
bsi - > RemoveFromStringList ( " GameList " , " Paths " , dir . c_str ( ) ) ;
SetSettingsChanged ( bsi ) ;
PopulateGameListDirectoryCache ( bsi ) ;
Host : : RefreshGameListAsync ( false ) ;
}
CloseFileSelector ( ) ;
} ) ;
}
for ( const auto & it : s_game_list_directories_cache )
{
2023-12-13 11:06:15 +00:00
if ( MenuButton ( SmallString : : from_format ( ICON_FA_FOLDER " {} " , it . first ) ,
2023-08-20 02:38:55 +00:00
it . second ? FSUI_CSTR ( " Scanning Subdirectories " ) : FSUI_CSTR ( " Not Scanning Subdirectories " ) ) )
2022-09-17 05:51:05 +00:00
{
ImGuiFullscreen : : ChoiceDialogOptions options = {
2023-08-20 02:38:55 +00:00
{ FSUI_ICONSTR ( ICON_FA_FOLDER_OPEN , " Open in File Browser " ) , false } ,
{ it . second ? ( FSUI_ICONSTR ( ICON_FA_FOLDER_MINUS , " Disable Subdirectory Scanning " ) ) :
( FSUI_ICONSTR ( ICON_FA_FOLDER_PLUS , " Enable Subdirectory Scanning " ) ) ,
2022-09-17 05:51:05 +00:00
false } ,
2023-08-20 02:38:55 +00:00
{ FSUI_ICONSTR ( ICON_FA_TIMES , " Remove From List " ) , false } ,
{ FSUI_ICONSTR ( ICON_FA_WINDOW_CLOSE , " Close Menu " ) , false } ,
2022-09-17 05:51:05 +00:00
} ;
OpenChoiceDialog ( it . first . c_str ( ) , false , std : : move ( options ) ,
[ dir = it . first , recursive = it . second ] ( s32 index , const std : : string & title , bool checked ) {
if ( index < 0 )
return ;
if ( index = = 0 )
{
2024-04-16 02:29:26 +00:00
// Open in file browser
2024-04-16 02:36:33 +00:00
ExitFullscreenAndOpenURL ( Path : : CreateFileURL ( dir ) ) ;
2022-09-17 05:51:05 +00:00
}
else if ( index = = 1 )
{
// toggle subdirectory scanning
{
auto lock = Host : : GetSettingsLock ( ) ;
SettingsInterface * bsi = Host : : Internal : : GetBaseSettingsLayer ( ) ;
if ( ! recursive )
{
bsi - > RemoveFromStringList ( " GameList " , " Paths " , dir . c_str ( ) ) ;
bsi - > AddToStringList ( " GameList " , " RecursivePaths " , dir . c_str ( ) ) ;
}
else
{
bsi - > RemoveFromStringList ( " GameList " , " RecursivePaths " , dir . c_str ( ) ) ;
bsi - > AddToStringList ( " GameList " , " Paths " , dir . c_str ( ) ) ;
}
SetSettingsChanged ( bsi ) ;
PopulateGameListDirectoryCache ( bsi ) ;
}
Host : : RefreshGameListAsync ( false ) ;
}
else if ( index = = 2 )
{
// remove from list
auto lock = Host : : GetSettingsLock ( ) ;
SettingsInterface * bsi = Host : : Internal : : GetBaseSettingsLayer ( ) ;
bsi - > RemoveFromStringList ( " GameList " , " Paths " , dir . c_str ( ) ) ;
bsi - > RemoveFromStringList ( " GameList " , " RecursivePaths " , dir . c_str ( ) ) ;
SetSettingsChanged ( bsi ) ;
PopulateGameListDirectoryCache ( bsi ) ;
Host : : RefreshGameListAsync ( false ) ;
}
CloseChoiceDialog ( ) ;
} ) ;
}
}
2024-01-26 04:30:41 +00:00
MenuHeading ( FSUI_CSTR ( " List Settings " ) ) ;
2022-10-23 04:09:54 +00:00
{
2023-08-20 02:38:55 +00:00
static constexpr const char * view_types [ ] = { FSUI_NSTR ( " Game Grid " ) , FSUI_NSTR ( " Game List " ) } ;
static constexpr const char * sort_types [ ] = {
2023-12-20 13:40:24 +00:00
FSUI_NSTR ( " Type " ) , FSUI_NSTR ( " Serial " ) , FSUI_NSTR ( " Title " ) , FSUI_NSTR ( " File Title " ) ,
FSUI_NSTR ( " Time Played " ) , FSUI_NSTR ( " Last Played " ) , FSUI_NSTR ( " File Size " ) , FSUI_NSTR ( " Uncompressed Size " ) } ;
2023-08-20 02:38:55 +00:00
DrawIntListSetting ( bsi , FSUI_ICONSTR ( ICON_FA_BORDER_ALL , " Default View " ) ,
2023-11-30 04:21:44 +00:00
FSUI_CSTR ( " Selects the view that the game list will open to. " ) , " Main " ,
" DefaultFullscreenUIGameView " , 0 , view_types , std : : size ( view_types ) , true ) ;
2023-08-20 02:38:55 +00:00
DrawIntListSetting ( bsi , FSUI_ICONSTR ( ICON_FA_SORT , " Sort By " ) ,
2023-11-30 04:21:44 +00:00
FSUI_CSTR ( " Determines that field that the game list will be sorted by. " ) , " Main " ,
" FullscreenUIGameSort " , 0 , sort_types , std : : size ( sort_types ) , true ) ;
DrawToggleSetting (
bsi , FSUI_ICONSTR ( ICON_FA_SORT_ALPHA_DOWN , " Sort Reversed " ) ,
FSUI_CSTR ( " Reverses the game list sort order from the default (usually ascending to descending). " ) , " Main " ,
" FullscreenUIGameSortReverse " , false ) ;
2022-10-23 04:09:54 +00:00
}
2022-09-17 05:51:05 +00:00
2023-08-20 02:38:55 +00:00
MenuHeading ( FSUI_CSTR ( " Cover Settings " ) ) ;
2022-10-23 04:09:54 +00:00
{
2023-08-20 02:38:55 +00:00
DrawFolderSetting ( bsi , FSUI_ICONSTR ( ICON_FA_FOLDER , " Covers Directory " ) , " Folders " , " Covers " , EmuFolders : : Covers ) ;
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_DOWNLOAD , " Download Covers " ) ,
FSUI_CSTR ( " Downloads covers from a user-specified URL template. " ) ) )
2024-01-20 10:09:32 +00:00
{
Host : : OnCoverDownloaderOpenRequested ( ) ;
}
2022-10-23 04:09:54 +00:00
}
2022-09-17 05:51:05 +00:00
2024-01-26 04:30:41 +00:00
MenuHeading ( FSUI_CSTR ( " Operations " ) ) ;
2022-10-23 04:09:54 +00:00
{
2023-08-20 02:38:55 +00:00
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_SEARCH , " Scan For New Games " ) ,
FSUI_CSTR ( " Identifies any new files added to the game directories. " ) ) )
2024-01-26 04:30:41 +00:00
{
2022-10-23 04:09:54 +00:00
Host : : RefreshGameListAsync ( false ) ;
2024-01-26 04:30:41 +00:00
}
2023-08-20 02:38:55 +00:00
if ( MenuButton ( FSUI_ICONSTR ( ICON_FA_SEARCH_PLUS , " Rescan All Games " ) ,
FSUI_CSTR ( " Forces a full rescan of all games previously identified. " ) ) )
2024-01-26 04:30:41 +00:00
{
2022-10-23 04:09:54 +00:00
Host : : RefreshGameListAsync ( true ) ;
2024-01-26 04:30:41 +00:00
}
2022-10-23 04:09:54 +00:00
}
2022-09-17 05:51:05 +00:00
EndMenuButtons ( ) ;
EndFullscreenWindow ( ) ;
2024-04-09 10:04:45 +00:00
SetStandardSelectionFooterText ( true ) ;
2022-09-17 05:51:05 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : SwitchToGameList ( )
{
s_current_main_window = MainWindowType : : GameList ;
2024-04-09 10:04:45 +00:00
s_game_list_view = static_cast < GameListView > ( Host : : GetBaseIntSettingValue ( " Main " , " DefaultFullscreenUIGameView " , 0 ) ) ;
2022-09-17 05:51:05 +00:00
{
auto lock = Host : : GetSettingsLock ( ) ;
PopulateGameListDirectoryCache ( Host : : Internal : : GetBaseSettingsLayer ( ) ) ;
}
2022-07-11 13:03:29 +00:00
QueueResetFocus ( ) ;
2021-01-30 11:37:49 +00:00
}
2022-10-03 06:44:34 +00:00
GPUTexture * FullscreenUI : : GetGameListCover ( const GameList : : Entry * entry )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
// lookup and grab cover image
auto cover_it = s_cover_image_map . find ( entry - > path ) ;
if ( cover_it = = s_cover_image_map . end ( ) )
{
std : : string cover_path ( GameList : : GetCoverImagePathForEntry ( entry ) ) ;
cover_it = s_cover_image_map . emplace ( entry - > path , std : : move ( cover_path ) ) . first ;
}
2021-01-30 11:37:49 +00:00
2022-10-03 06:44:34 +00:00
GPUTexture * tex = ( ! cover_it - > second . empty ( ) ) ? GetCachedTextureAsync ( cover_it - > second . c_str ( ) ) : nullptr ;
2022-07-11 13:03:29 +00:00
return tex ? tex : GetTextureForGameListEntryType ( entry - > type ) ;
}
2022-10-03 06:44:34 +00:00
GPUTexture * FullscreenUI : : GetTextureForGameListEntryType ( GameList : : EntryType type )
2022-07-11 13:03:29 +00:00
{
switch ( type )
2021-01-30 11:37:49 +00:00
{
2022-07-11 13:03:29 +00:00
case GameList : : EntryType : : PSExe :
return s_fallback_exe_texture . get ( ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
case GameList : : EntryType : : Playlist :
return s_fallback_playlist_texture . get ( ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
case GameList : : EntryType : : PSF :
return s_fallback_psf_texture . get ( ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
case GameList : : EntryType : : Disc :
default :
return s_fallback_disc_texture . get ( ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
}
2021-01-30 11:37:49 +00:00
2022-10-03 06:44:34 +00:00
GPUTexture * FullscreenUI : : GetCoverForCurrentGame ( )
2022-07-11 13:03:29 +00:00
{
auto lock = GameList : : GetLock ( ) ;
2021-01-30 11:37:49 +00:00
2023-05-15 13:38:37 +00:00
const GameList : : Entry * entry = GameList : : GetEntryForPath ( System : : GetDiscPath ( ) . c_str ( ) ) ;
2022-07-11 13:03:29 +00:00
if ( ! entry )
return s_fallback_disc_texture . get ( ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
return GetGameListCover ( entry ) ;
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
//////////////////////////////////////////////////////////////////////////
// Overlays
//////////////////////////////////////////////////////////////////////////
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
void FullscreenUI : : OpenAboutWindow ( )
{
s_about_window_open = true ;
}
2021-01-30 11:37:49 +00:00
2022-08-25 15:26:55 +00:00
void FullscreenUI : : ExitFullscreenAndOpenURL ( const std : : string_view & url )
{
Host : : RunOnCPUThread ( [ url = std : : string ( url ) ] ( ) {
if ( Host : : IsFullscreen ( ) )
Host : : SetFullscreen ( false ) ;
Host : : OpenURL ( url ) ;
} ) ;
}
void FullscreenUI : : CopyTextToClipboard ( std : : string title , const std : : string_view & text )
{
if ( Host : : CopyTextToClipboard ( text ) )
ShowToast ( std : : string ( ) , std : : move ( title ) ) ;
else
2023-08-20 02:38:55 +00:00
ShowToast ( std : : string ( ) , FSUI_STR ( " Failed to copy text to clipboard. " ) ) ;
2022-08-25 15:26:55 +00:00
}
2022-07-11 13:03:29 +00:00
void FullscreenUI : : DrawAboutWindow ( )
{
2024-04-09 10:04:45 +00:00
ImGui : : SetNextWindowSize ( LayoutScale ( 1000.0f , 540.0f ) ) ;
2022-07-11 13:03:29 +00:00
ImGui : : SetNextWindowPos ( ImGui : : GetIO ( ) . DisplaySize * 0.5f , ImGuiCond_Always , ImVec2 ( 0.5f , 0.5f ) ) ;
2023-08-20 02:38:55 +00:00
ImGui : : OpenPopup ( FSUI_CSTR ( " About DuckStation " ) ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
ImGui : : PushFont ( g_large_font ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowRounding , LayoutScale ( 10.0f ) ) ;
2024-04-09 10:04:45 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowPadding , LayoutScale ( 30.0f , 30.0f ) ) ;
2021-01-30 11:37:49 +00:00
2023-08-20 02:38:55 +00:00
if ( ImGui : : BeginPopupModal ( FSUI_CSTR ( " About DuckStation " ) , & s_about_window_open ,
2022-07-11 13:03:29 +00:00
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize ) )
2021-01-30 11:37:49 +00:00
{
2023-09-03 04:30:26 +00:00
ImGui : : TextWrapped ( " %s " ,
FSUI_CSTR ( " DuckStation is a free and open-source simulator/emulator of the Sony PlayStation(TM) "
2023-08-20 02:38:55 +00:00
" console, focusing on playability, speed, and long-term maintainability. " ) ) ;
2022-07-11 13:03:29 +00:00
ImGui : : NewLine ( ) ;
2024-04-09 10:04:45 +00:00
ImGui : : TextWrapped ( " Version: %s " , g_scm_tag_str ) ;
2022-07-11 13:03:29 +00:00
ImGui : : NewLine ( ) ;
2023-08-20 02:38:55 +00:00
ImGui : : TextWrapped (
2023-09-03 04:30:26 +00:00
" %s " , FSUI_CSTR ( " Duck icon by icons8 (https://icons8.com/icon/74847/platforms.undefined.short-title) " ) ) ;
2022-07-11 13:03:29 +00:00
ImGui : : NewLine ( ) ;
2023-08-20 02:38:55 +00:00
ImGui : : TextWrapped (
2023-09-03 04:30:26 +00:00
" %s " , FSUI_CSTR ( " \" PlayStation \" and \" PSX \" are registered trademarks of Sony Interactive Entertainment Europe "
" Limited. This software is not affiliated in any way with Sony Interactive Entertainment. " ) ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
ImGui : : NewLine ( ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
BeginMenuButtons ( ) ;
2023-08-20 02:38:55 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_GLOBE , " GitHub Repository " ) , false ) )
2022-08-25 15:26:55 +00:00
ExitFullscreenAndOpenURL ( " https://github.com/stenzek/duckstation/ " ) ;
2023-08-20 02:38:55 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_COMMENT , " Discord Server " ) , false ) )
2024-04-09 10:04:45 +00:00
ExitFullscreenAndOpenURL ( " https://www.duckstation.org/discord.html " ) ;
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_PEOPLE_CARRY , " Contributor List " ) , false ) )
ExitFullscreenAndOpenURL ( " https://github.com/stenzek/duckstation/blob/master/CONTRIBUTORS.md " ) ;
2021-01-30 11:37:49 +00:00
2024-04-09 10:04:45 +00:00
if ( ActiveButton ( FSUI_ICONSTR ( ICON_FA_WINDOW_CLOSE , " Close " ) , false ) | | WantsToCloseMenu ( ) )
2022-07-11 13:03:29 +00:00
{
ImGui : : CloseCurrentPopup ( ) ;
s_about_window_open = false ;
2021-01-30 11:37:49 +00:00
}
2024-04-09 10:04:45 +00:00
else
{
SetStandardSelectionFooterText ( true ) ;
}
2022-07-11 13:03:29 +00:00
EndMenuButtons ( ) ;
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
ImGui : : EndPopup ( ) ;
2021-01-30 11:37:49 +00:00
}
2022-07-11 13:03:29 +00:00
ImGui : : PopStyleVar ( 2 ) ;
ImGui : : PopFont ( ) ;
}
2021-01-30 11:37:49 +00:00
2023-09-18 12:29:47 +00:00
void FullscreenUI : : OpenAchievementsWindow ( )
2022-07-11 13:03:29 +00:00
{
2023-09-18 12:29:47 +00:00
if ( ! Achievements : : IsActive ( ) )
2023-09-07 10:13:48 +00:00
{
2023-09-18 12:29:47 +00:00
Host : : AddKeyedOSDMessage ( " achievements_disabled " , FSUI_STR ( " Achievements are not enabled. " ) ,
Host : : OSD_INFO_DURATION ) ;
return ;
}
if ( ! System : : IsValid ( ) | | ! Initialize ( ) )
return ;
if ( ! Achievements : : HasAchievements ( ) | | ! Achievements : : PrepareAchievementsWindow ( ) )
{
ShowToast ( std : : string ( ) , FSUI_STR ( " This game has no achievements. " ) ) ;
return ;
2023-09-07 10:13:48 +00:00
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
if ( s_current_main_window ! = MainWindowType : : PauseMenu )
2024-04-09 10:04:45 +00:00
{
2023-09-18 12:29:47 +00:00
PauseForMenuOpen ( false ) ;
2024-04-09 10:04:45 +00:00
ForceKeyNavEnabled ( ) ;
}
2021-01-30 11:37:49 +00:00
2022-07-11 13:03:29 +00:00
s_current_main_window = MainWindowType : : Achievements ;
QueueResetFocus ( ) ;
2023-12-14 06:07:57 +00:00
FixStateIfPaused ( ) ;
2021-01-30 11:37:49 +00:00
}
2023-09-07 10:13:48 +00:00
bool FullscreenUI : : IsAchievementsWindowOpen ( )
2021-02-26 14:44:53 +00:00
{
2023-09-07 10:13:48 +00:00
return ( s_current_main_window = = MainWindowType : : Achievements ) ;
2022-10-08 10:25:34 +00:00
}
2023-09-18 12:29:47 +00:00
void FullscreenUI : : OpenLeaderboardsWindow ( )
2022-07-11 13:03:29 +00:00
{
2023-09-18 12:29:47 +00:00
if ( ! Achievements : : IsActive ( ) )
{
Host : : AddKeyedOSDMessage ( " achievements_disabled " , FSUI_STR ( " Leaderboards are not enabled. " ) ,
Host : : OSD_INFO_DURATION ) ;
return ;
}
if ( ! System : : IsValid ( ) | | ! Initialize ( ) )
return ;
if ( ! Achievements : : HasLeaderboards ( ) | | ! Achievements : : PrepareLeaderboardsWindow ( ) )
{
ShowToast ( std : : string ( ) , FSUI_STR ( " This game has no leaderboards. " ) ) ;
return ;
}
2022-07-11 13:03:29 +00:00
if ( s_current_main_window ! = MainWindowType : : PauseMenu )
2024-04-09 10:04:45 +00:00
{
2023-09-18 12:29:47 +00:00
PauseForMenuOpen ( false ) ;
2024-04-09 10:04:45 +00:00
ForceKeyNavEnabled ( ) ;
}
2022-07-11 13:03:29 +00:00
s_current_main_window = MainWindowType : : Leaderboards ;
QueueResetFocus ( ) ;
2023-12-14 06:07:57 +00:00
FixStateIfPaused ( ) ;
2022-07-11 13:03:29 +00:00
}
2023-09-07 10:13:48 +00:00
bool FullscreenUI : : IsLeaderboardsWindowOpen ( )
2021-06-18 21:40:11 +00:00
{
2023-09-07 10:13:48 +00:00
return ( s_current_main_window = = MainWindowType : : Leaderboards ) ;
2021-06-18 21:40:11 +00:00
}
2022-08-25 15:26:55 +00:00
# endif // __ANDROID__
2023-08-20 02:38:55 +00:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Translation String Area
// To avoid having to type T_RANSLATE("FullscreenUI", ...) everywhere, we use the shorter macros at the top
// of the file, then preprocess and generate a bunch of noops here to define the strings. Sadly that means
// the view in Linguist is gonna suck, but you can search the file for the string for more context.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
#if 0
// TRANSLATION-STRING-AREA-BEGIN
2024-03-20 12:48:23 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " %.2f Seconds " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " %d Frames " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " %d sectors " ) ;
2023-11-26 11:34:00 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " - " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " 1 Frame " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 10 Frames " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 100% [60 FPS (NTSC) / 50 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 1000% [600 FPS (NTSC) / 500 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 10x " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 10x (20x Speed) " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 11x " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 125% [75 FPS (NTSC) / 62 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 12x " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 13x " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 14x " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 150% [90 FPS (NTSC) / 75 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 15x " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 16x " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 175% [105 FPS (NTSC) / 87 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 1x " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 2 Frames " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 20% [12 FPS (NTSC) / 10 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 200% [120 FPS (NTSC) / 100 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 250% [150 FPS (NTSC) / 125 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 2x " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 2x (Quad Speed) " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 3 Frames " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 30% [18 FPS (NTSC) / 15 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 300% [180 FPS (NTSC) / 150 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 350% [210 FPS (NTSC) / 175 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 3x " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 3x (6x Speed) " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 3x (for 720p) " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 4 Frames " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 40% [24 FPS (NTSC) / 20 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 400% [240 FPS (NTSC) / 200 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 450% [270 FPS (NTSC) / 225 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 4x " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 4x (8x Speed) " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 5 Frames " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 50% [30 FPS (NTSC) / 25 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 500% [300 FPS (NTSC) / 250 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 5x " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 5x (10x Speed) " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 5x (for 1080p) " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 6 Frames " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 60% [36 FPS (NTSC) / 30 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 600% [360 FPS (NTSC) / 300 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 6x " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 6x (12x Speed) " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 6x (for 1440p) " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 7 Frames " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 70% [42 FPS (NTSC) / 35 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 700% [420 FPS (NTSC) / 350 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 7x " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 7x (14x Speed) " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 8 Frames " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 80% [48 FPS (NTSC) / 40 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 800% [480 FPS (NTSC) / 400 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 8x " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 8x (16x Speed) " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 9 Frames " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 90% [54 FPS (NTSC) / 45 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 900% [540 FPS (NTSC) / 450 FPS (PAL)] " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 9x " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 9x (18x Speed) " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " 9x (for 4K) " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " A resume save state created at %s was found. \n \n Do you want to load this save and continue? " ) ;
2024-04-09 10:04:45 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " About " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " About DuckStation " ) ;
2023-09-16 09:06:59 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Account " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Achievement Notifications " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Achievements " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Achievements Settings " ) ;
2023-09-18 12:42:28 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Achievements are not enabled. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Add Search Directory " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Add Shader " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Adds a new directory to the game search list. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Adds a new shader to the chain. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Adds additional precision to PGXP data post-projection. May improve visuals in some games. " ) ;
2024-04-13 09:56:08 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Adjusts the emulation speed so the console's refresh rate matches the host when VSync is enabled. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Advanced Settings " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " All Time: {} " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Allow Booting Without SBI File " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Allows loading protected games without subchannel information. " ) ;
2024-01-20 10:09:32 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Applies modern dithering techniques to further smooth out gradients when true color is enabled. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Apply Image Patches " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Apply Per-Game Settings " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Are you sure you want to clear the current post-processing chain? All configuration will be lost. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Aspect Ratio " ) ;
2024-03-02 05:50:46 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Attempts to detect one pixel high/wide lines that rely on non-upscaled rasterization behavior, filling in gaps introduced by upscaling. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Attempts to map the selected port to a chosen controller. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Audio Backend " ) ;
2023-11-28 16:08:19 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Audio Control " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Audio Settings " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Auto-Detect " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Automatic Mapping " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Automatic based on window size " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Automatic mapping completed for {}. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Automatic mapping failed for {}. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Automatic mapping failed, no devices are available. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Automatically applies patches to disc images when they are present, currently only PPF is supported. " ) ;
2024-03-03 03:43:04 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Automatically loads and applies cheats on game start. Cheats can break games and saves. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Automatically saves the emulator state when powering down or exiting. You can then resume directly from where you left off next time. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Automatically switches to fullscreen mode when the program is started. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Avoids calls to C++ code, significantly speeding up the recompiler. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " BIOS Directory " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " BIOS Selection " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " BIOS Settings " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " BIOS for {} " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " BIOS to use when emulating {} consoles. " ) ;
2024-04-09 10:04:45 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Back " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Back To Pause Menu " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Backend Settings " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Behavior " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Borderless Fullscreen " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Buffer Size " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " CD-ROM Emulation " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " CPU Emulation " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " CPU Mode " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Cancel " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Change Disc " ) ;
2024-04-09 10:04:45 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Change Page " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Change Selection " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Change View " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Changes settings for the application. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Changes the aspect ratio used to display the console's output to the screen. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Cheat List " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Chooses the backend to use for rendering the console/game visuals. " ) ;
2023-11-29 10:26:36 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Chooses the language used for UI elements. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Chroma Smoothing For 24-Bit Display " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Clean Boot " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Clear Settings " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Clear Shaders " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Clears a shader from the chain. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Clears all settings set for this game. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Clears the mask/transparency bit in VRAM write dumps. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Close " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Close Game " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Close Menu " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Compatibility Rating " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Compatibility: " ) ;
2024-04-09 10:04:45 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Completely exits the application, returning you to your desktop. " ) ;
2023-11-28 16:08:19 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Configuration " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Confirm Power Off " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Console Settings " ) ;
2024-04-09 14:04:51 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Contributor List " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Controller Port {} " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Controller Port {} Macros " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Controller Port {} Settings " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Controller Port {}{} " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Controller Port {}{} Macros " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Controller Port {}{} Settings " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Controller Settings " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Controller Type " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Controller settings reset to default. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Controls " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Controls the volume of the audio played on the host when fast forwarding. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Controls the volume of the audio played on the host. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Copies the current global settings to this game. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Copies the global controller configuration to this game. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Copy Global Settings " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Copy Settings " ) ;
2024-04-09 10:04:45 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Could not find any CD/DVD-ROM devices. Please ensure you have a drive connected and sufficient permissions to access it. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Cover Settings " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Covers Directory " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Create " ) ;
2024-04-07 10:43:13 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Create New... " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Create Save State Backups " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Crop Mode " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Culling Correction " ) ;
2023-09-16 09:06:59 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Current Game " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Debugging Settings " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Default " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Default Boot " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Default View " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Default: Disabled " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Default: Enabled " ) ;
2024-03-20 12:48:23 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Deinterlacing Mode " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Delete Save " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Delete State " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Depth Buffer " ) ;
2024-04-09 10:04:45 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Desktop Mode " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Details " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Details unavailable for game not scanned in game list. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Determines how large the on-screen messages and monitor are. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Determines how much latency there is between the audio being picked up by the host API, and played through speakers. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Determines how much of the area typically not visible on a consumer TV set to crop/hide. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Determines how the emulated CPU executes instructions. " ) ;
2023-09-04 12:45:44 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Determines how the emulated console's output is upscaled or downscaled to your monitor's resolution. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Determines quality of audio when not running at 100% speed. " ) ;
2023-11-30 04:21:44 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Determines that field that the game list will be sorted by. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Determines the amount of audio buffered before being pulled by the host API. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Determines the emulated hardware type. " ) ;
2024-03-02 09:08:38 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Determines the format that screenshots will be saved/compressed with. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Determines the position on the screen when black borders must be added. " ) ;
2024-03-02 09:08:38 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Determines the size of screenshots created by DuckStation. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Determines whether a prompt will be displayed to confirm shutting down the emulator/game when the hotkey is pressed. " ) ;
2024-03-20 12:48:23 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Determines which algorithm is used to convert interlaced frames to progressive for display on your system. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Device Settings " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Disable All Enhancements " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Disable Interlacing " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Disable Subdirectory Scanning " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Disabled " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Disables dithering and uses the full 8 bits per channel of color information. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Disables interlaced rendering and display in the GPU. Some games can render in 480p this way, but others will break. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Discord Server " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Display FPS Limit " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Display Settings " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Displays popup messages on events such as achievement unlocks and leaderboard submissions. " ) ;
2023-09-16 09:06:59 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Displays popup messages when starting, submitting, or failing a leaderboard challenge. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Double-Click Toggles Fullscreen " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Download Covers " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Downloads covers from a user-specified URL template. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Downsamples the rendered image prior to displaying it. Can improve overall image quality in mixed 2D/3D games. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Downsampling " ) ;
2023-09-04 12:45:44 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Downsampling Display Scale " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Duck icon by icons8 (https://icons8.com/icon/74847/platforms.undefined.short-title) " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " DuckStation is a free and open-source simulator/emulator of the Sony PlayStation(TM) console, focusing on playability, speed, and long-term maintainability. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Dump Replaceable VRAM Writes " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Emulation Settings " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Emulation Speed " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Enable 8MB RAM " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Enable Achievements " ) ;
2024-03-03 03:43:04 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Enable Cheats " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Enable Discord Presence " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Enable Fast Boot " ) ;
2023-09-16 09:06:59 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Enable In-Game Overlays " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Enable Overclocking " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Enable PGXP Vertex Cache " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Enable Post Processing " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Enable Recompiler Block Linking " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Enable Recompiler ICache " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Enable Recompiler Memory Exceptions " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Enable Region Check " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Enable Rewinding " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Enable SDL Input Source " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Enable Subdirectory Scanning " ) ;
2023-09-04 12:45:44 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Enable TTY Logging " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Enable VRAM Write Texture Replacement " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Enable XInput Input Source " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Enable debugging when supported by the host's renderer API. Only for developer use. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Enables alignment and bus exceptions. Not needed for any known games. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Enables an additional 6MB of RAM to obtain a total of 2+6 = 8MB, usually present on dev consoles. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Enables an additional three controller slots on each port. Not supported in all games. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Enables more precise frame pacing at the cost of battery life. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Enables the replacement of background textures in supported games. " ) ;
2023-09-16 09:06:59 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Encore Mode " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Enhancements " ) ;
2024-04-13 04:41:10 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Ensures every frame generated is displayed for optimal pacing. Enable for variable refresh displays, such as GSync/FreeSync. Disable if you are having speed or sound issues. " ) ;
2024-04-09 10:04:45 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Enter Value " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Enter the name of the input profile you wish to create. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Execution Mode " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Exit " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Exit And Save State " ) ;
2024-04-09 10:04:45 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Exit DuckStation " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Exit Without Saving " ) ;
2024-04-09 10:04:45 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Exits Big Picture mode, returning to the desktop interface. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Failed to copy text to clipboard. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Failed to delete save state. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Failed to delete {}. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Failed to load '{}'. " ) ;
2023-09-04 12:45:44 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Failed to load shader {}. It may be invalid. \n Error was: " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Failed to save input profile '{}'. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Fast Boot " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Fast Forward Speed " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Fast Forward Volume " ) ;
2023-12-20 13:40:24 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " File Size " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " File Size: %.2f MB " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " File Title " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Force 4:3 For 24-Bit Display " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Force NTSC Timings " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Forces PAL games to run at NTSC timings, i.e. 60hz. Some PAL games will run at their \" normal \" speeds, while others will break. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Forces a full rescan of all games previously identified. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Forcibly mutes both CD-DA and XA audio from the CD-ROM. Can be used to disable background music in some games. " ) ;
2024-04-13 09:56:08 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Frame Time Buffer " ) ;
2023-09-04 12:45:44 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " From File... " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Fullscreen Resolution " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " GPU Adapter " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " GPU Renderer " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " GPU adapter will be applied after restarting. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Game Grid " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Game List " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Game List Settings " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Game Properties " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Game Quick Save " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Game Slot {0}##game_slot_{0} " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Game compatibility rating copied to clipboard. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Game not loaded or no RetroAchievements available. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Game path copied to clipboard. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Game region copied to clipboard. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Game serial copied to clipboard. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Game settings have been cleared for '{}'. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Game settings initialized with global settings for '{}'. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Game title copied to clipboard. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Game type copied to clipboard. " ) ;
2023-09-16 09:06:59 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Game: {} ({}) " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Genre: %s " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " GitHub Repository " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Global Slot {0} - {1}##global_slot_{0} " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Global Slot {0}##global_slot_{0} " ) ;
2024-03-02 09:08:38 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Graphics Settings " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Hardcore Mode " ) ;
2023-09-16 09:06:59 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Hardcore mode will be enabled on next game restart. " ) ;
2023-09-04 12:45:44 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Hide Cursor In Fullscreen " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Hides the mouse pointer/cursor when the emulator is in fullscreen mode. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Hotkey Settings " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " How many saves will be kept for rewinding. Higher values have greater memory requirements. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " How often a rewind state will be created. Higher frequencies have greater system requirements. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Identifies any new files added to the game directories. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " If not enabled, the current post processing chain will be ignored. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Increase Timer Resolution " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Increases the field of view from 4:3 to the chosen display aspect ratio in 3D games. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Increases the precision of polygon culling, reducing the number of holes in geometry. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Infinite/Instantaneous " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Inhibit Screensaver " ) ;
2023-09-16 09:06:59 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Input Sources " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Input profile '{}' loaded. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Input profile '{}' saved. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Integration " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Interface Settings " ) ;
2024-03-02 09:08:38 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Internal Resolution " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Last Played " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Last Played: %s " ) ;
2024-04-13 09:56:08 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Latency Control " ) ;
2024-04-09 10:04:45 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Launch Options " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Launch a game by selecting a file/disc image. " ) ;
2024-04-09 10:04:45 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Launch a game from a file, disc, or starts the console without any disc inserted. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Launch a game from images scanned from your game directories. " ) ;
2023-09-16 09:06:59 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Leaderboard Notifications " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Leaderboards " ) ;
2023-09-18 12:42:28 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Leaderboards are not enabled. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Limits how many frames are displayed to the screen. These frames are still rendered. " ) ;
2024-03-02 05:50:46 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Line Detection " ) ;
2024-01-26 04:30:41 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " List Settings " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Load Devices From Save States " ) ;
2024-04-09 10:04:45 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Load Global State " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Load Profile " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Load Resume State " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Load State " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Loads all replacement texture to RAM, reducing stuttering at runtime. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Loads the game image into RAM. Useful for network paths that may become unreliable during gameplay. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Log Level " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Log To Debug Console " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Log To File " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Log To System Console " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Logging " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Logging Settings " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Login " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Login token generated on {} " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Logout " ) ;
2023-09-04 12:45:44 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Logs BIOS calls to printf(). Not all games contain debugging messages. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Logs in to RetroAchievements. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Logs messages to duckstation.log in the user directory. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Logs messages to the console window. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Logs messages to the debug console where supported. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Logs out of RetroAchievements. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Macro {} Buttons " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Macro {} Frequency " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Macro {} Trigger " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Makes games run closer to their console framerate, at a small cost to performance. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Memory Card Directory " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Memory Card Port {} " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Memory Card Settings " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Memory Card {} Type " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Minimal Output Latency " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Move Down " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Move Up " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Moves this shader higher in the chain, applying it earlier. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Moves this shader lower in the chain, applying it later. " ) ;
2023-11-28 16:08:19 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Multitap " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Multitap Mode " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Mute All Sound " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Mute CD Audio " ) ;
2024-04-09 10:04:45 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Navigate " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " No Binding " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " No Game Selected " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " No cheats found for {}. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " No input profiles available. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " No resume save state found. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " No save present in this slot. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " No save states found. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " None (Double Speed) " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " None (Normal Speed) " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Not Logged In " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Not Scanning Subdirectories " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " OK " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " OSD Scale " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " On-Screen Display " ) ;
2024-04-16 02:43:23 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Open Containing Directory " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Open in File Browser " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Operations " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Optimal Frame Pacing " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Options " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Output Latency " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Output Volume " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Overclocking Percentage " ) ;
2023-09-04 12:45:44 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Overlays or replaces normal triangle drawing with a wireframe/line view. " ) ;
2023-09-16 09:06:59 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " PGXP (Precision Geometry Transform Pipeline) " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " PGXP Depth Clear Threshold " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " PGXP Geometry Correction " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " PGXP Geometry Tolerance " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " PGXP Settings " ) ;
2024-04-09 14:04:51 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Parent Directory " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Patches " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Patches the BIOS to skip the boot animation. Safe to enable. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Path " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Pause On Focus Loss " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Pause On Start " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Pauses the emulator when a game is started. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Pauses the emulator when you minimize the window or switch to another application, and unpauses when you switch back. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Per-Game Configuration " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Per-game controller configuration initialized with global settings. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Performance enhancement - jumps directly between blocks instead of returning to the dispatcher. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Perspective Correct Colors " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Perspective Correct Textures " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Plays sound effects for events such as achievement unlocks and leaderboard submissions. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Port {} Controller Type " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Position " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Post-Processing Settings " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Post-processing chain cleared. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Post-processing shaders reloaded. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Preload Images to RAM " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Preload Replacement Textures " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Presents frames on a background thread when fast forwarding or vsync is disabled. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Preserve Projection Precision " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Prevents the emulator from producing any audible sound. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Prevents the screen saver from activating and the host from sleeping while emulation is running. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Provides vibration and LED control support over Bluetooth. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Push a controller button or axis now. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Quick Save " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " RAIntegration is being used instead of the built-in achievements implementation. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Read Speedup " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Readahead Sectors " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Recompiler Fast Memory Access " ) ;
2024-04-13 09:56:08 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Reduce Input Latency " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Reduces \" wobbly \" polygons by attempting to preserve the fractional component through memory transfers. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Reduces hitches in emulation by reading/decompressing CD data asynchronously on a worker thread. " ) ;
2024-04-13 09:56:08 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Reduces input latency by delaying the start of frame until closer to the presentation time. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Reduces polygon Z-fighting through depth testing. Low compatibility with games. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Region " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Region: " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Release Date: %s " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Reload Shaders " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Reloads the shaders from disk, applying any changes. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Remove From Chain " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Remove From List " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Removed stage {} ({}). " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Removes this shader from the chain. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Renames existing save states when saving to a backup file. " ) ;
2023-09-16 09:06:59 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Rendering " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Replaces these settings with a previously saved input profile. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Rescan All Games " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Reset Memory Card Directory " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Reset Play Time " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Reset Settings " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Reset System " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Resets all configuration to defaults (including bindings). " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Resets memory card directory to default (user directory). " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Resolution change will be applied after restarting. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Restores the state of the system prior to the last state loaded. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Resume Game " ) ;
2024-04-09 10:04:45 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Resume Last Session " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Return To Game " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Return to desktop mode, or exit the application. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Return to the previous menu. " ) ;
2023-11-30 04:21:44 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Reverses the game list sort order from the default (usually ascending to descending). " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Rewind Save Frequency " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Rewind Save Slots " ) ;
2023-11-28 16:08:19 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Rewind for {0} frames, lasting {1:.2f} seconds will require up to {2} MB of RAM and {3} MB of VRAM. " ) ;
2023-11-29 13:11:28 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Rewind is disabled because runahead is enabled. Runahead will significantly increase system requirements. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Rewind is not enabled. Please note that enabling rewind may significantly increase system requirements. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Rich presence inactive or unsupported. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Runahead " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Runahead/Rewind " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Runs the software renderer in parallel for VRAM readbacks. On some systems, this may result in greater performance. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " SDL DualShock 4 / DualSense Enhanced Mode " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Save Profile " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Save Screenshot " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Save State " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Save State On Exit " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Saved {:%c} " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Saves state periodically so you can rewind any mistakes while playing. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Scaled Dithering " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Scales internal VRAM resolution by the specified multiplier. Some games require 1x VRAM resolution. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Scales the dithering pattern with the internal rendering resolution, making it less noticeable. Usually safe to enable. " ) ;
2023-09-04 12:45:44 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Scaling " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Scan For New Games " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Scanning Subdirectories " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Screen Display " ) ;
2024-03-02 09:08:38 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Screenshot Format " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Screenshot Quality " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Screenshot Size " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Search Directories " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Seek Speedup " ) ;
2024-04-09 10:04:45 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Select " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Select Device " ) ;
2024-04-09 10:04:45 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Select Disc Drive " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Select Disc Image " ) ;
2024-04-09 10:04:45 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Select Game " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Select Macro {} Binds " ) ;
2024-04-09 10:04:45 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Select State " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Selects the GPU to use for rendering. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Selects the percentage of the normal clock speed the emulated hardware will run at. " ) ;
2024-03-02 09:08:38 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Selects the quality at which screenshots will be compressed. " ) ;
2023-09-04 12:45:44 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Selects the resolution scale that will be applied to the final image. 1x will downsample to the original console resolution. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Selects the resolution to use in fullscreen modes. " ) ;
2023-11-30 04:21:44 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Selects the view that the game list will open to. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Serial " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Session: {} " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Set Input Binding " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Set VRAM Write Dump Alpha Channel " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Sets a threshold for discarding precise values when exceeded. May help with glitches in some games. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Sets a threshold for discarding the emulated depth buffer. May help in some games. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Sets the fast forward speed. It is not guaranteed that this speed will be reached on all systems. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Sets the target emulation speed. It is not guaranteed that this speed will be reached on all systems. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Sets the turbo speed. It is not guaranteed that this speed will be reached on all systems. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Sets the verbosity of messages logged. Higher levels will log more messages. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Sets which sort of memory card image will be used for slot {}. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Setting {} binding {}. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Settings " ) ;
2023-09-16 09:06:59 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Settings and Operations " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Shader {} added as stage {}. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Shared Card Name " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Show CPU Usage " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Show Controller Input " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Show Enhancement Settings " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Show FPS " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Show Frame Times " ) ;
2024-01-24 03:56:22 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Show GPU Statistics " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Show GPU Usage " ) ;
2024-04-14 04:53:53 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Show Latency Statistics " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Show OSD Messages " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Show Resolution " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Show Speed " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Show Status Indicators " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Shows a visual history of frame times in the upper-left corner of the display. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Shows enhancement settings in the bottom-right corner of the screen. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Shows icons in the lower-right corner of the screen when a challenge/primed achievement is active. " ) ;
2024-04-14 04:53:53 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Shows information about input and audio latency in the top-right corner of the display. " ) ;
2024-01-24 03:56:22 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Shows information about the emulated GPU in the top-right corner of the display. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Shows on-screen-display messages when events occur. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Shows persistent icons when turbo is active or when paused. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Shows the current controller state of the system in the bottom-left corner of the display. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Shows the current emulation speed of the system in the top-right corner of the display as a percentage. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Shows the current rendering resolution of the system in the top-right corner of the display. " ) ;
2023-11-29 05:41:29 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Shows the game you are currently playing as part of your profile in Discord. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Shows the host's CPU usage based on threads in the top-right corner of the display. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Shows the host's GPU usage in the top-right corner of the display. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Shows the number of frames (or v-syncs) displayed per second by the system in the top-right corner of the display. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Simulates the CPU's instruction cache in the recompiler. Can help with games running too fast. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Simulates the region check present in original, unmodified consoles. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Simulates the system ahead of time and rolls back/replays to reduce input lag. Very high system requirements. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Slow Boot " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Smooths out blockyness between colour transitions in 24-bit content, usually FMVs. Only applies to the hardware renderers. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Smooths out the blockiness of magnified textures on 3D objects. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Sort By " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Sort Reversed " ) ;
2023-09-16 09:06:59 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Sound Effects " ) ;
2024-04-13 09:56:08 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Specifies the amount of buffer time added, which reduces the additional sleep time introduced. " ) ;
2023-09-16 09:06:59 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Spectator Mode " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Speed Control " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Speeds up CD-ROM reads by the specified factor. May improve loading speeds in some games, and break others. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Speeds up CD-ROM seeks by the specified factor. May improve loading speeds in some games, and break others. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Stage {}: {} " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Start BIOS " ) ;
2024-04-09 10:04:45 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Start Disc " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Start File " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Start Fullscreen " ) ;
2024-04-09 10:04:45 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Start Game " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Start a game from a disc in your PC's DVD drive. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Start the console without any disc inserted. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Stores the current settings to an input profile. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Stretch Display Vertically " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Stretch Mode " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Stretches the display to match the aspect ratio by multiplying vertically instead of horizontally. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Summary " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Switches back to 4:3 display aspect ratio when displaying 24-bit content, usually FMVs. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Switches between full screen and windowed when the window is double-clicked. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Sync To Host Refresh Rate " ) ;
2024-04-13 04:41:10 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Synchronizes presentation of the console's frames to the host. GSync/FreeSync users should enable Optimal Frame Pacing instead. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Temporarily disables all enhancements, useful when testing. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Test Unofficial Achievements " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Texture Dumping " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Texture Filtering " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Texture Replacements " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " The SDL input source supports most controllers. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " The XInput source provides support for XBox 360/XBox One/XBox Series controllers. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " The audio backend determines how frames produced by the emulator are submitted to the host. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " The selected memory card image will be used in shared mode for this slot. " ) ;
2023-09-18 12:42:28 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " This game has no achievements. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " This game has no leaderboards. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Threaded Presentation " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Threaded Rendering " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Time Played " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Time Played: %s " ) ;
2023-09-04 12:45:44 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Timing out in {:.0f} seconds... " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Title " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Toggle Analog " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Toggle Fast Forward " ) ;
2024-04-09 10:04:45 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Toggle Fullscreen " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Toggle every %d frames " ) ;
2024-01-20 10:09:32 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " True Color Debanding " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " True Color Rendering " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Turbo Speed " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Type " ) ;
2023-11-29 10:26:36 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " UI Language " ) ;
2023-12-20 13:40:24 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Uncompressed Size " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Uncompressed Size: %.2f MB " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Undo Load State " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Unknown " ) ;
2023-12-20 13:40:24 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Unknown File Size " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Unlimited " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Use Blit Swap Chain " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Use Debug GPU Device " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Use Global Setting " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Use Light Theme " ) ;
2023-09-04 12:45:44 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Use Single Card For Multi-Disc Games " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Use Software Renderer For Readbacks " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Username: {} " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Uses PGXP for all instructions, not just memory operations. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Uses a blit presentation model instead of flipping. This may be needed on some systems. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Uses a light coloured theme instead of the default dark theme. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Uses a second thread for drawing graphics. Speed boost, and safe to use. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Uses game-specific settings for controllers for this game. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Uses perspective-correct interpolation for colors, which can improve visuals in some games. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Uses perspective-correct interpolation for texture coordinates, straightening out warped textures. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Uses screen positions to resolve PGXP data. May improve visuals in some games. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " Value: {} | Default: {} | Minimum: {} | Maximum: {} " ) ;
2024-04-13 09:56:08 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Vertical Sync (VSync) " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " When enabled and logged in, DuckStation will scan for achievements on startup. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " When enabled, DuckStation will assume all achievements are locked and not send any unlock notifications to the server. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " When enabled, DuckStation will list achievements from unofficial sets. These achievements are not tracked by RetroAchievements. " ) ;
2023-09-16 09:06:59 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " When enabled, each session will behave as if no achievements have been unlocked. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " When enabled, memory cards and controllers will be overwritten when save states are loaded. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " When enabled, per-game settings will be applied, and incompatible enhancements will be disabled. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " When enabled, the minimum supported output latency will be used for the host API. " ) ;
2023-09-04 12:45:44 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " When playing a multi-disc game and using per-game (title) memory cards, use a single memory card for all discs. " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " When this option is chosen, the clock speed set below will be used. " ) ;
2023-11-28 16:08:19 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Widescreen Hack " ) ;
2023-09-04 12:45:44 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Wireframe Rendering " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " Writes textures which can be replaced to the dump directory. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " \" Challenge \" mode for achievements, including leaderboard tracking. Disables save state, cheats, and slowdown functions. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " \" PlayStation \" and \" PSX \" are registered trademarks of Sony Interactive Entertainment Europe Limited. This software is not affiliated in any way with Sony Interactive Entertainment. " ) ;
2024-04-09 10:04:45 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " {:%H:%M} " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " {:%Y-%m-%d %H:%M:%S} " ) ;
2023-11-26 11:34:00 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " {} Frames " ) ;
2023-08-20 02:38:55 +00:00
TRANSLATE_NOOP ( " FullscreenUI " , " {} deleted. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " {} does not exist. " ) ;
TRANSLATE_NOOP ( " FullscreenUI " , " {} is not a valid disc image. " ) ;
// TRANSLATION-STRING-AREA-END
# endif