semi-usable
|
@ -2,29 +2,30 @@
|
|||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Label="UserMacros">
|
||||
<BinaryOutputDir>$(SolutionDir)bin\$(Platform)\</BinaryOutputDir>
|
||||
<QTDIRDefault Condition="'$(Platform)'=='x64'">$(SolutionDir)dep\msvc\qt\6.1.0\msvc2019_64\</QTDIRDefault>
|
||||
<QTDIRDefault Condition="'$(Platform)'=='ARM64'">$(SolutionDir)dep\msvc\qt\6.1.0\msvc2019_arm64\</QTDIRDefault>
|
||||
<QTDIR Condition="Exists('$(QTDIRDefault)') And ('$(QTDIR)'=='' Or !Exists('$(QTDIR)'))">$(QTDIRDefault)</QTDIR>
|
||||
<QTDIR Condition="Exists('$(QTDIR)') And !HasTrailingSlash('$(QTDIR)')">$(QTDIR)\</QTDIR>
|
||||
<QTDIRHost>$(SolutionDir)dep\msvc\qt\6.1.0\msvc2019_64\</QTDIRHost>
|
||||
<QtDirValid>false</QtDirValid>
|
||||
<QtDirValid Condition="Exists('$(QTDIR)')">true</QtDirValid>
|
||||
<QtIncludeDir>$(QTDIR)include\</QtIncludeDir>
|
||||
<QtLibDir>$(QTDIR)lib\</QtLibDir>
|
||||
<QtBinDir>$(QTDIR)bin\</QtBinDir>
|
||||
<QtHostBinDir>$(QTDIRHost)bin\</QtHostBinDir>
|
||||
<QtPluginsDir>$(QTDIR)plugins\</QtPluginsDir>
|
||||
<QtTranslationsDir>$(QTDIR)translations\</QtTranslationsDir>
|
||||
<QtToolOutDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</QtToolOutDir>
|
||||
<DSQTDIRDefault Condition="'$(Platform)'=='x64'">$(SolutionDir)dep\msvc\qt\6.1.0\msvc2019_64\</DSQTDIRDefault>
|
||||
<DSQTDIRDefault Condition="'$(Platform)'=='ARM64'">$(SolutionDir)dep\msvc\qt\6.1.0\msvc2019_arm64\</DSQTDIRDefault>
|
||||
<DSQTDIR Condition="Exists('$(DSQTDIRDefault)') And ('$(DSQTDIR)'=='' Or !Exists('$(DSQTDIR)'))">$(DSQTDIRDefault)</DSQTDIR>
|
||||
<DSQTDIR Condition="Exists('$(DSQTDIR)') And !HasTrailingSlash('$(DSQTDIR)')">$(DSQTDIR)\</DSQTDIR>
|
||||
<DSQTDIRHost>$(SolutionDir)dep\msvc\qt\6.1.0\msvc2019_64\</DSQTDIRHost>
|
||||
<DSQTDIRValid>false</DSQTDIRValid>
|
||||
<DSQTDIRValid Condition="Exists('$(DSQTDIR)')">true</DSQTDIRValid>
|
||||
<QtIncludeDir>$(DSQTDIR)include\</QtIncludeDir>
|
||||
<QtLibDir>$(DSQTDIR)lib\</QtLibDir>
|
||||
<QtBinDir>$(DSQTDIR)bin\</QtBinDir>
|
||||
<QtHostBinDir>$(DSQTDIRHost)bin\</QtHostBinDir>
|
||||
<QtPluginsDir>$(DSQTDIR)plugins\</QtPluginsDir>
|
||||
<QtTranslationsDir>$(DSQTDIR)translations\</QtTranslationsDir>
|
||||
<QtToolOutDir>$(IntDir)</QtToolOutDir>
|
||||
<QtMocOutPrefix>$(QtToolOutDir)moc_</QtMocOutPrefix>
|
||||
<QtTsOutDir>$(BinaryOutputDir)translations\</QtTsOutDir>
|
||||
<QtDebugSuffix>d</QtDebugSuffix>
|
||||
<QtLibSuffix Condition="'$(Configuration)'=='Debug' Or '$(Configuration)'=='DebugFast'">$(QtDebugSuffix)</QtLibSuffix>
|
||||
<QtLibSuffix Condition="$(Configuration.Contains(Debug))">$(QtDebugSuffix)</QtLibSuffix>
|
||||
<QtPluginFolder>QtPlugins</QtPluginFolder>
|
||||
<QtEntryPointLib>$(QtLibDir)Qt6EntryPoint$(QtLibSuffix).lib</QtEntryPointLib>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions Condition="'$(Configuration)'=='Release' Or '$(Configuration)'=='ReleaseLTCG'">QT_NO_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions Condition="!$(Configuration.Contains(Debug))">QT_NO_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(QtToolOutDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(QtIncludeDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
|
@ -45,7 +46,7 @@
|
|||
Condition="'@(QtResource)'!=''"
|
||||
Outputs="@(ResFiles->'$(QtToolOutDir)qrc_%(Filename).cpp')">
|
||||
<Message Text="rcc %(ResFiles.Filename)" Importance="High" />
|
||||
<Error Condition="!$(QtDirValid)" Text="QTDIR not set or non-existent (pull the submodule?)" />
|
||||
<Error Condition="!$(DSQTDIRValid)" Text="Qt directory non-existent (pull the submodule?)" />
|
||||
<MakeDir Directories="$(QtToolOutDir)" />
|
||||
<Exec Command=""$(QtHostBinDir)rcc.exe" "%(ResFiles.FullPath)" -o "$(QtToolOutDir)qrc_%(ResFiles.Filename).cpp"" />
|
||||
</Target>
|
||||
|
@ -64,7 +65,7 @@
|
|||
Condition="'@(QtUi)'!=''"
|
||||
Outputs="@(UiFiles->'$(QtToolOutDir)ui_%(Filename).h')">
|
||||
<Message Text="uic %(UiFiles.Filename)" Importance="High" />
|
||||
<Error Condition="!$(QtDirValid)" Text="QTDIR not set or non-existent (pull the submodule?)" />
|
||||
<Error Condition="!$(DSQTDIRValid)" Text="Qt directory non-existent (pull the submodule?)" />
|
||||
<MakeDir Directories="$(QtToolOutDir)" />
|
||||
<Exec Command=""$(QtHostBinDir)uic.exe" "%(UiFiles.FullPath)" -o "$(QtToolOutDir)ui_%(UiFiles.Filename).h"" />
|
||||
</Target>
|
||||
|
@ -77,26 +78,18 @@
|
|||
<!--TODO find a way to autocreate from ClCompile settings-->
|
||||
<PropertyGroup>
|
||||
<MocDefines></MocDefines>
|
||||
<MocDefines Condition="'$(Configuration)'=='Release' Or '$(Configuration)'=='ReleaseLTCG'">-DQT_NO_DEBUG -DNDEBUG $(MocDefines)</MocDefines>
|
||||
<!-- !!!HOLY UGLY BATMAN!!!
|
||||
Be very careful here when adding include directories. Each path must have the whole arg surrounded by doublequotes - HOWEVER,
|
||||
the ending doublequote cannot be directly preceeded by a directory seperator. In other words, you must use:
|
||||
"-I$(SomeDir) "
|
||||
instead of
|
||||
"-I$(SomeDir)"
|
||||
in order to prevent the trailing slash from escaping the doublequote after value replacement.
|
||||
-->
|
||||
<MocIncludes>"-I$(QtIncludeDir)" "-I$(SolutionDir)src" -I.</MocIncludes>
|
||||
<MocDefines Condition="!$(Configuration.Contains(Debug))">-DQT_NO_DEBUG -DNDEBUG $(MocDefines)</MocDefines>
|
||||
<MocIncludes>-I"$(QtIncludeDir)." -I"$(SolutionDir)pcsx2" "-I$(SolutionDir)." -I.</MocIncludes>
|
||||
</PropertyGroup>
|
||||
<Target Name="QtMoc"
|
||||
BeforeTargets="ClCompile"
|
||||
Condition="'@(QtMoc)'!=''"
|
||||
Inputs="%(QtMoc.Identity);%(QtMoc.AdditionalDependencies);$(MSBuildProjectFile)"
|
||||
Outputs="$(QtToolOutDir)moc_%(QtMoc.Filename).cpp">
|
||||
<Message Text="moc %(QtMoc.Filename) $(QtToolOutDir)moc_%(QtMoc.Filename).cpp" Importance="High" />
|
||||
<Error Condition="!$(QtDirValid)" Text="QTDIR not set or non-existent (pull the submodule?)" />
|
||||
Outputs="$(QtToolOutDir)%(QtMoc.RelativeDir)moc_%(QtMoc.Filename).cpp">
|
||||
<Message Text="moc %(QtMoc.Filename) $(QtToolOutDir)%(QtMoc.RelativeDir)moc_%(QtMoc.Filename).cpp" Importance="High" />
|
||||
<Error Condition="!$(DSQTDIRValid)" Text="Qt directory non-existent (pull the submodule?)" />
|
||||
<MakeDir Directories="$(QtToolOutDir)" />
|
||||
<Exec Command=""$(QtHostBinDir)moc.exe" "%(QtMoc.FullPath)" -o "$(QtToolOutDir)moc_%(QtMoc.Filename).cpp" -f%(QtMoc.Filename)%(QtMoc.Extension) $(MocDefines) $(MocIncludes)" />
|
||||
<Exec Command=""$(QtHostBinDir)moc.exe" "%(QtMoc.FullPath)" -o "$(QtToolOutDir)%(QtMoc.RelativeDir)moc_%(QtMoc.Filename).cpp" -f%(QtMoc.Filename)%(QtMoc.Extension) $(MocDefines) $(MocIncludes)" />
|
||||
</Target>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -129,17 +122,20 @@
|
|||
<QtDlls Include="@(QtLibNames -> '$(QtBinDir)%(Identity).dll')" />
|
||||
<!--Filter plugins to copy based on the observation that all debug versions end in "d"-->
|
||||
<QtAllPlugins Include="$(QtPluginsDir)**\*$(QtLibSuffix).dll" />
|
||||
<QtPlugins Condition="'$(Configuration)'=='Debug' Or '$(Configuration)'=='DebugFast'" Include="@(QtAllPlugins)" />
|
||||
<QtPlugins Condition="'$(Configuration)'=='Release' Or '$(Configuration)'=='ReleaseLTCG'" Exclude="$(QtPluginsDir)**\*$(QtDebugSuffix).dll" Include="@(QtAllPlugins)" />
|
||||
<QtPlugins Condition="$(Configuration.Contains(Debug))" Include="@(QtAllPlugins)" />
|
||||
<QtPlugins Condition="!$(Configuration.Contains(Debug))" Exclude="$(QtPluginsDir)**\*$(QtDebugSuffix).dll" Include="@(QtAllPlugins)" />
|
||||
<QtPluginsDest Include="@(QtPlugins -> '$(BinaryOutputDir)$(QtPluginFolder)\%(RecursiveDir)%(Filename)%(Extension)')" />
|
||||
<!--Our normal *d filter fails for the TLS DLLs, because backend ends in d. -->
|
||||
<!--<QtTLSDlls Include="$(QtPluginsDir)tls\qcertonlybackend$(QtLibSuffix).dll;$(QtPluginsDir)tls\qschannelbackend$(QtLibSuffix).dll" />-->
|
||||
<QtTLSDllsDest Include="@(QtTLSDlls -> '$(BinaryOutputDir)$(QtPluginFolder)\tls\%(Filename)%(Extension)')" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<QtConfFile>$(BinaryOutputDir)qt.conf</QtConfFile>
|
||||
</PropertyGroup>
|
||||
<Target Name="QtCopyBinaries"
|
||||
AfterTargets="Build"
|
||||
Inputs="@(QtDlls);@(QtPlugins)"
|
||||
Outputs="@(QtDlls -> '$(BinaryOutputDir)%(RecursiveDir)%(Filename)%(Extension)');@(QtPlugins -> '$(BinaryOutputDir)$(QtPluginFolder)\%(RecursiveDir)%(Filename)%(Extension)')">
|
||||
Inputs="@(QtDlls);@(QtPlugins);@(QtTLSDlls)"
|
||||
Outputs="@(QtDlls -> '$(BinaryOutputDir)%(RecursiveDir)%(Filename)%(Extension)');@(QtPluginsDest);@(QtTLSDllsDest)">
|
||||
<Message Text="Copying Qt .dlls" Importance="High" />
|
||||
<Copy
|
||||
SourceFiles="@(QtDlls)"
|
||||
|
@ -151,6 +147,11 @@
|
|||
DestinationFiles="@(QtPluginsDest)"
|
||||
SkipUnchangedFiles="true"
|
||||
/>
|
||||
<Copy
|
||||
SourceFiles="@(QtTLSDlls)"
|
||||
DestinationFiles="@(QtTLSDllsDest)"
|
||||
SkipUnchangedFiles="true"
|
||||
/>
|
||||
</Target>
|
||||
<Target Name="QtCreateConf"
|
||||
BeforeTargets="QtCopyBinaries"
|
||||
|
@ -192,7 +193,7 @@
|
|||
Condition="'@(QtTs)'!=''"
|
||||
Outputs="@(TsFiles->'$(QtTsOutDir)%(Filename).qm')">
|
||||
<Message Text="lrelease %(TsFiles.Filename)" Importance="High" />
|
||||
<Error Condition="!$(QtDirValid)" Text="QTDIR not set or non-existent (pull the submodule?)" />
|
||||
<Error Condition="!$(DSQTDIRValid)" Text="Qt directory non-existent (pull the submodule?)" />
|
||||
<MakeDir Directories="$(QtTsOutDir)" />
|
||||
<Exec Command=""$(QtHostBinDir)lrelease.exe" "%(TsFiles.FullPath)" -qm "$(QtTsOutDir)%(TsFiles.Filename).qm"" />
|
||||
</Target>
|
||||
|
|
|
@ -827,7 +827,6 @@ Global
|
|||
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|x64.ActiveCfg = Release|x64
|
||||
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|x64.Build.0 = Release|x64
|
||||
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|x86.ActiveCfg = Release|Win32
|
||||
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|x86.Build.0 = Release|Win32
|
||||
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseLTCG|ARM64.ActiveCfg = ReleaseLTCG|ARM64
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
bool HasMedia() const { return m_reader.HasMedia(); }
|
||||
const std::string& GetMediaFileName() const { return m_reader.GetMediaFileName(); }
|
||||
const CDImage* GetMedia() const { return m_reader.GetMedia(); }
|
||||
DiscRegion GetDiscRegion() const { return m_disc_region; }
|
||||
bool IsMediaPS1Disc() const;
|
||||
bool DoesMediaRegionMatchConsole() const;
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "common/string.h"
|
||||
#include "common/types.h"
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
@ -104,4 +105,7 @@ void SetPadVibrationIntensity(u32 pad_index, float large_or_single_motor_intensi
|
|||
|
||||
/// Enables "relative" mouse mode, locking the cursor position and returning relative coordinates.
|
||||
void SetMouseMode(bool relative, bool hide_cursor);
|
||||
|
||||
/// Safely executes a function on the VM thread.
|
||||
void RunOnCPUThread(std::function<void()> function, bool block = false);
|
||||
} // namespace Host
|
||||
|
|
|
@ -165,6 +165,7 @@ void Settings::Load(SettingsInterface& si)
|
|||
pause_on_focus_loss = si.GetBoolValue("Main", "PauseOnFocusLoss", false);
|
||||
pause_on_menu = si.GetBoolValue("Main", "PauseOnMenu", true);
|
||||
save_state_on_exit = si.GetBoolValue("Main", "SaveStateOnExit", true);
|
||||
create_save_state_backups = si.GetBoolValue("Main", "CreateSaveStateBackups", true);
|
||||
confim_power_off = si.GetBoolValue("Main", "ConfirmPowerOff", true);
|
||||
load_devices_from_save_states = si.GetBoolValue("Main", "LoadDevicesFromSaveStates", false);
|
||||
apply_game_settings = si.GetBoolValue("Main", "ApplyGameSettings", true);
|
||||
|
@ -363,6 +364,7 @@ void Settings::Save(SettingsInterface& si) const
|
|||
si.SetBoolValue("Main", "PauseOnFocusLoss", pause_on_focus_loss);
|
||||
si.SetBoolValue("Main", "PauseOnMenu", pause_on_menu);
|
||||
si.SetBoolValue("Main", "SaveStateOnExit", save_state_on_exit);
|
||||
si.SetBoolValue("Main", "CreateSaveStateBackups", create_save_state_backups);
|
||||
si.SetBoolValue("Main", "ConfirmPowerOff", confim_power_off);
|
||||
si.SetBoolValue("Main", "LoadDevicesFromSaveStates", load_devices_from_save_states);
|
||||
si.SetBoolValue("Main", "ApplyGameSettings", apply_game_settings);
|
||||
|
@ -1058,12 +1060,17 @@ const char* Settings::GetMemoryCardTypeDisplayName(MemoryCardType type)
|
|||
return s_memory_card_type_display_names[static_cast<int>(type)];
|
||||
}
|
||||
|
||||
std::string Settings::GetDefaultSharedMemoryCardName(u32 slot)
|
||||
{
|
||||
return fmt::format("shared_card_{}.mcd", slot + 1);
|
||||
}
|
||||
|
||||
std::string Settings::GetSharedMemoryCardPath(u32 slot) const
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
if (memory_card_paths[slot].empty())
|
||||
ret = Path::Combine(EmuFolders::MemoryCards, fmt::format("shared_card_{}.mcd", slot + 1));
|
||||
ret = Path::Combine(EmuFolders::MemoryCards, GetDefaultSharedMemoryCardName(slot));
|
||||
else if (!Path::IsAbsolute(memory_card_paths[slot]))
|
||||
ret = Path::Combine(EmuFolders::MemoryCards, memory_card_paths[slot]);
|
||||
else
|
||||
|
|
|
@ -67,6 +67,7 @@ struct Settings
|
|||
bool pause_on_focus_loss = false;
|
||||
bool pause_on_menu = true;
|
||||
bool save_state_on_exit = true;
|
||||
bool create_save_state_backups = false;
|
||||
bool confim_power_off = true;
|
||||
bool load_devices_from_save_states = false;
|
||||
bool apply_game_settings = true;
|
||||
|
@ -249,6 +250,7 @@ struct Settings
|
|||
bool HasAnyPerGameMemoryCards() const;
|
||||
|
||||
/// Returns the default path to a memory card.
|
||||
static std::string GetDefaultSharedMemoryCardName(u32 slot);
|
||||
std::string GetSharedMemoryCardPath(u32 slot) const;
|
||||
|
||||
/// Returns the default path to a memory card for a specific game.
|
||||
|
|
|
@ -76,7 +76,6 @@ struct MemorySaveState
|
|||
};
|
||||
|
||||
namespace System {
|
||||
static bool InternalLoadState(ByteStream* state, bool update_display = true);
|
||||
static bool InternalSaveState(ByteStream* state, u32 screenshot_size = 256);
|
||||
static bool SaveMemoryState(MemorySaveState* mss);
|
||||
static bool LoadMemoryState(const MemorySaveState& mss);
|
||||
|
@ -97,6 +96,7 @@ static void StallCPU(TickCount ticks);
|
|||
static bool InternalBoot(const SystemBootParameters& params);
|
||||
static void InternalReset();
|
||||
static void InternalShutdown();
|
||||
static void DestroySystem();
|
||||
static bool DoLoadState(ByteStream* stream, bool force_software_renderer, bool update_display);
|
||||
static bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display, bool is_memory_state);
|
||||
static void DoRunFrame();
|
||||
|
@ -245,6 +245,11 @@ ConsoleRegion System::GetRegion()
|
|||
return s_region;
|
||||
}
|
||||
|
||||
DiscRegion System::GetDiscRegion()
|
||||
{
|
||||
return g_cdrom.GetDiscRegion();
|
||||
}
|
||||
|
||||
bool System::IsPALRegion()
|
||||
{
|
||||
return s_region == ConsoleRegion::PAL;
|
||||
|
@ -825,7 +830,7 @@ void System::ApplySettings(bool display_osd_messages)
|
|||
|
||||
bool System::ReloadGameSettings(bool display_osd_messages)
|
||||
{
|
||||
if (!UpdateGameSettingsLayer())
|
||||
if (!IsValid() || !UpdateGameSettingsLayer())
|
||||
return false;
|
||||
|
||||
ApplySettings(display_osd_messages);
|
||||
|
@ -971,6 +976,9 @@ bool System::BootSystem(std::shared_ptr<SystemBootParameters> parameters)
|
|||
|
||||
void System::ResetSystem()
|
||||
{
|
||||
if (!IsValid())
|
||||
return;
|
||||
|
||||
InternalReset();
|
||||
ResetPerformanceCounters();
|
||||
ResetThrottler();
|
||||
|
@ -1030,7 +1038,7 @@ bool System::LoadState(const char* filename)
|
|||
|
||||
SaveUndoLoadState();
|
||||
|
||||
if (!InternalLoadState(stream.get()))
|
||||
if (!DoLoadState(stream.get(), false, true))
|
||||
{
|
||||
Host::ReportFormattedErrorAsync(
|
||||
"Load State Error", Host::TranslateString("OSDMessage", "Loading state from '%s' failed. Resetting."), filename);
|
||||
|
@ -1047,8 +1055,15 @@ bool System::LoadState(const char* filename)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool System::SaveState(const char* filename)
|
||||
bool System::SaveState(const char* filename, bool backup_existing_save)
|
||||
{
|
||||
if (backup_existing_save && FileSystem::FileExists(filename))
|
||||
{
|
||||
const std::string backup_filename(Path::ReplaceExtension(filename, "bak"));
|
||||
if (!FileSystem::RenamePath(filename, backup_filename.c_str()))
|
||||
Log_ErrorPrintf("Failed to rename save state backup '%s'", backup_filename.c_str());
|
||||
}
|
||||
|
||||
std::unique_ptr<ByteStream> stream =
|
||||
ByteStream::OpenFile(filename, BYTESTREAM_OPEN_CREATE | BYTESTREAM_OPEN_WRITE | BYTESTREAM_OPEN_TRUNCATE |
|
||||
BYTESTREAM_OPEN_ATOMIC_UPDATE | BYTESTREAM_OPEN_STREAMED);
|
||||
|
@ -1137,19 +1152,6 @@ bool System::InternalBoot(const SystemBootParameters& params)
|
|||
|
||||
Log_InfoPrintf("Console Region: %s", Settings::GetConsoleRegionDisplayName(s_region));
|
||||
|
||||
// Load BIOS image.
|
||||
std::optional<BIOS::Image> bios_image(BIOS::GetBIOSImage(s_region));
|
||||
if (!bios_image)
|
||||
{
|
||||
Host::ReportFormattedErrorAsync("Error", Host::TranslateString("System", "Failed to load %s BIOS."),
|
||||
Settings::GetConsoleRegionName(s_region));
|
||||
InternalShutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Notify change of disc.
|
||||
UpdateRunningGame(media ? media->GetFileName().c_str() : params.filename.c_str(), media.get(), true);
|
||||
|
||||
// Check for SBI.
|
||||
if (!CheckForSBIFile(media.get()))
|
||||
{
|
||||
|
@ -1166,6 +1168,19 @@ bool System::InternalBoot(const SystemBootParameters& params)
|
|||
return false;
|
||||
}
|
||||
|
||||
// Notify change of disc.
|
||||
UpdateRunningGame(media ? media->GetFileName().c_str() : params.filename.c_str(), media.get(), true);
|
||||
|
||||
// Load BIOS image.
|
||||
std::optional<BIOS::Image> bios_image(BIOS::GetBIOSImage(s_region));
|
||||
if (!bios_image)
|
||||
{
|
||||
Host::ReportFormattedErrorAsync("Error", Host::TranslateString("System", "Failed to load %s BIOS."),
|
||||
Settings::GetConsoleRegionName(s_region));
|
||||
InternalShutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Component setup.
|
||||
if (!Initialize(params.force_software_renderer))
|
||||
{
|
||||
|
@ -1618,14 +1633,6 @@ void System::InternalReset()
|
|||
g_gpu->ResetGraphicsAPIState();
|
||||
}
|
||||
|
||||
bool System::InternalLoadState(ByteStream* state, bool update_display)
|
||||
{
|
||||
if (IsShutdown())
|
||||
return false;
|
||||
|
||||
return DoLoadState(state, false, update_display);
|
||||
}
|
||||
|
||||
bool System::DoLoadState(ByteStream* state, bool force_software_renderer, bool update_display)
|
||||
{
|
||||
SAVE_STATE_HEADER header;
|
||||
|
@ -1762,6 +1769,8 @@ bool System::DoLoadState(ByteStream* state, bool force_software_renderer, bool u
|
|||
s_state = State::Running;
|
||||
|
||||
g_spu.GetOutputStream()->EmptyBuffers();
|
||||
ResetPerformanceCounters();
|
||||
ResetThrottler();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3412,22 +3421,16 @@ void System::SetRunaheadReplayFlag()
|
|||
s_runahead_replay_pending = true;
|
||||
}
|
||||
|
||||
bool System::SaveResumeSaveState()
|
||||
{
|
||||
if (System::IsShutdown())
|
||||
return false;
|
||||
|
||||
const bool global = System::GetRunningCode().empty();
|
||||
return SaveStateToSlot(global, -1);
|
||||
}
|
||||
|
||||
void System::PowerOffSystem(bool save_resume_state)
|
||||
void System::ShutdownSystem(bool save_resume_state)
|
||||
{
|
||||
if (!IsValid())
|
||||
return;
|
||||
|
||||
if (save_resume_state)
|
||||
SaveResumeSaveState();
|
||||
if (save_resume_state && !s_running_game_code.empty())
|
||||
{
|
||||
std::string path(GetGameSaveStateFileName(s_running_game_code, -1));
|
||||
SaveState(path.c_str(), false);
|
||||
}
|
||||
|
||||
DestroySystem();
|
||||
}
|
||||
|
@ -3465,7 +3468,7 @@ bool System::UndoLoadState()
|
|||
Assert(IsValid());
|
||||
|
||||
m_undo_load_state->SeekAbsolute(0);
|
||||
if (!InternalLoadState(m_undo_load_state.get()))
|
||||
if (!DoLoadState(m_undo_load_state.get(), false, true))
|
||||
{
|
||||
Host::ReportErrorAsync("Error", "Failed to load undo state, resetting system.");
|
||||
m_undo_load_state.reset();
|
||||
|
@ -3473,9 +3476,6 @@ bool System::UndoLoadState()
|
|||
return false;
|
||||
}
|
||||
|
||||
ResetPerformanceCounters();
|
||||
ResetThrottler();
|
||||
|
||||
Log_InfoPrintf("Loaded undo save state.");
|
||||
m_undo_load_state.reset();
|
||||
return true;
|
||||
|
@ -3498,33 +3498,6 @@ bool System::SaveUndoLoadState()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool System::LoadStateFromSlot(bool global, s32 slot)
|
||||
{
|
||||
if (!global && (System::IsShutdown() || System::GetRunningCode().empty()))
|
||||
{
|
||||
Host::ReportErrorAsync("Error", "Can't save per-game state without a running game code.");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string save_path =
|
||||
global ? GetGlobalSaveStateFileName(slot) : GetGameSaveStateFileName(System::GetRunningCode().c_str(), slot);
|
||||
return LoadState(save_path.c_str());
|
||||
}
|
||||
|
||||
bool System::SaveStateToSlot(bool global, s32 slot)
|
||||
{
|
||||
const std::string& code = System::GetRunningCode();
|
||||
if (!global && code.empty())
|
||||
{
|
||||
Host::ReportErrorAsync("Error", "Can't save per-game state without a running game code.");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string save_path = global ? GetGlobalSaveStateFileName(slot) : GetGameSaveStateFileName(code.c_str(), slot);
|
||||
RenameCurrentSaveStateToBackup(save_path.c_str());
|
||||
return SaveState(save_path.c_str());
|
||||
}
|
||||
|
||||
bool System::ResumeSystemFromMostRecentState()
|
||||
{
|
||||
const std::string path = GetMostRecentResumeSaveStatePath();
|
||||
|
@ -3537,11 +3510,6 @@ bool System::ResumeSystemFromMostRecentState()
|
|||
return LoadState(path.c_str());
|
||||
}
|
||||
|
||||
bool System::ShouldSaveResumeState()
|
||||
{
|
||||
return g_settings.save_state_on_exit;
|
||||
}
|
||||
|
||||
bool System::IsRunningAtNonStandardSpeed()
|
||||
{
|
||||
if (!IsValid())
|
||||
|
@ -3662,7 +3630,7 @@ bool System::SaveScreenshot(const char* filename /* = nullptr */, bool full_reso
|
|||
return true;
|
||||
}
|
||||
|
||||
std::string System::GetGameSaveStateFileName(const char* game_code, s32 slot)
|
||||
std::string System::GetGameSaveStateFileName(const std::string_view& game_code, s32 slot)
|
||||
{
|
||||
if (slot < 0)
|
||||
return Path::Combine(EmuFolders::SaveStates, fmt::format("{}_resume.sav", game_code));
|
||||
|
@ -3678,24 +3646,6 @@ std::string System::GetGlobalSaveStateFileName(s32 slot)
|
|||
return Path::Combine(EmuFolders::SaveStates, fmt::format("savestate_{}.sav", slot));
|
||||
}
|
||||
|
||||
void System::RenameCurrentSaveStateToBackup(const char* filename)
|
||||
{
|
||||
if (!Host::GetBaseBoolSettingValue("General", "CreateSaveStateBackups", false))
|
||||
return;
|
||||
|
||||
if (!FileSystem::FileExists(filename))
|
||||
return;
|
||||
|
||||
const std::string backup_filename(Path::ReplaceExtension(filename, "bak"));
|
||||
if (!FileSystem::RenamePath(filename, backup_filename.c_str()))
|
||||
{
|
||||
Log_ErrorPrintf("Failed to rename save state backup '%s'", backup_filename.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
Log_InfoPrintf("Renamed save state '%s' to '%s'", filename, backup_filename.c_str());
|
||||
}
|
||||
|
||||
std::vector<SaveStateInfo> System::GetAvailableSaveStates(const char* game_code)
|
||||
{
|
||||
std::vector<SaveStateInfo> si;
|
||||
|
|
|
@ -121,6 +121,7 @@ bool IsStartupCancelled();
|
|||
void CancelPendingStartup();
|
||||
|
||||
ConsoleRegion GetRegion();
|
||||
DiscRegion GetDiscRegion();
|
||||
bool IsPALRegion();
|
||||
|
||||
ALWAYS_INLINE TickCount GetTicksPerSecond()
|
||||
|
@ -188,17 +189,10 @@ bool ReloadGameSettings(bool display_osd_messages);
|
|||
bool BootSystem(std::shared_ptr<SystemBootParameters> parameters);
|
||||
void PauseSystem(bool paused);
|
||||
void ResetSystem();
|
||||
void DestroySystem();
|
||||
|
||||
/// Loads state from the specified filename.
|
||||
bool LoadState(const char* filename);
|
||||
bool SaveState(const char* filename);
|
||||
|
||||
/// Loads the current emulation state from file. Specifying a slot of -1 loads the "resume" game state.
|
||||
bool LoadStateFromSlot(bool global, s32 slot);
|
||||
|
||||
/// Saves the current emulation state to a file. Specifying a slot of -1 saves the "resume" save state.
|
||||
bool SaveStateToSlot(bool global, s32 slot);
|
||||
bool SaveState(const char* filename, bool backup_existing_save);
|
||||
|
||||
/// Runs the VM until the CPU execution is canceled.
|
||||
void Execute();
|
||||
|
@ -309,7 +303,7 @@ void DoFrameStep();
|
|||
void DoToggleCheats();
|
||||
|
||||
/// Returns the path to a save state file. Specifying an index of -1 is the "resume" save state.
|
||||
std::string GetGameSaveStateFileName(const char* game_code, s32 slot);
|
||||
std::string GetGameSaveStateFileName(const std::string_view& game_code, s32 slot);
|
||||
|
||||
/// Returns the path to a save state file. Specifying an index of -1 is the "resume" save state.
|
||||
std::string GetGlobalSaveStateFileName(s32 slot);
|
||||
|
@ -324,7 +318,7 @@ std::string GetMostRecentResumeSaveStatePath();
|
|||
std::string GetCheatFileName();
|
||||
|
||||
/// Powers off the system, optionally saving the resume state.
|
||||
void PowerOffSystem(bool save_resume_state);
|
||||
void ShutdownSystem(bool save_resume_state);
|
||||
|
||||
/// Returns true if an undo load state exists.
|
||||
bool CanUndoLoadState();
|
||||
|
@ -338,9 +332,6 @@ bool UndoLoadState();
|
|||
/// Loads the most recent resume save state. This may be global or per-game.
|
||||
bool ResumeSystemFromMostRecentState();
|
||||
|
||||
/// Saves the resume save state, call when shutting down.
|
||||
bool SaveResumeSaveState();
|
||||
|
||||
/// Returns a list of save states for the specified game code.
|
||||
std::vector<SaveStateInfo> GetAvailableSaveStates(const char* game_code);
|
||||
|
||||
|
@ -409,9 +400,6 @@ void ReloadPostProcessingShaders();
|
|||
/// Toggle Widescreen Hack and Aspect Ratio
|
||||
void ToggleWidescreen();
|
||||
|
||||
/// Returns true if the state should be saved on shutdown.
|
||||
bool ShouldSaveResumeState();
|
||||
|
||||
/// Returns true if fast forwarding or slow motion is currently active.
|
||||
bool IsRunningAtNonStandardSpeed();
|
||||
|
||||
|
@ -489,9 +477,6 @@ void PumpMessagesOnCPUThread();
|
|||
/// Requests a specific display window size.
|
||||
void RequestResizeHostDisplay(s32 width, s32 height);
|
||||
|
||||
/// Safely executes a function on the VM thread.
|
||||
// void RunOnCPUThread(std::function<void()> function, bool block = false);
|
||||
|
||||
/// Asynchronously starts refreshing the game list.
|
||||
// void RefreshGameListAsync(bool invalidate_cache);
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ void AchievementLoginDialog::loginClicked()
|
|||
m_ui.status->setText(tr("Logging in..."));
|
||||
enableUI(false);
|
||||
|
||||
g_emu_thread->executeOnEmulationThread([this, username, password]() {
|
||||
Host::RunOnCPUThread([this, username, password]() {
|
||||
const bool result = Cheevos::Login(username.toStdString().c_str(), password.toStdString().c_str());
|
||||
QMetaObject::invokeMethod(this, "processLoginResult", Qt::QueuedConnection, Q_ARG(bool, result));
|
||||
});
|
||||
|
|
|
@ -50,7 +50,7 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsDialog* dialog, QWi
|
|||
connect(m_ui.loginButton, &QPushButton::clicked, this, &AchievementSettingsWidget::onLoginLogoutPressed);
|
||||
connect(m_ui.viewProfile, &QPushButton::clicked, this, &AchievementSettingsWidget::onViewProfilePressed);
|
||||
connect(m_ui.challengeMode, &QCheckBox::toggled, this, &AchievementSettingsWidget::onChallengeModeToggled);
|
||||
connect(g_emu_thread, &QtHostInterface::achievementsLoaded, this, &AchievementSettingsWidget::onAchievementsLoaded);
|
||||
connect(g_emu_thread, &EmuThread::achievementsLoaded, this, &AchievementSettingsWidget::onAchievementsLoaded);
|
||||
|
||||
updateEnableState();
|
||||
updateLoginState();
|
||||
|
@ -98,7 +98,7 @@ void AchievementSettingsWidget::onLoginLogoutPressed()
|
|||
{
|
||||
if (!Host::GetBaseStringSettingValue("Cheevos", "Username").empty())
|
||||
{
|
||||
g_emu_thread->executeOnEmulationThread([]() { Cheevos::Logout(); }, true);
|
||||
Host::RunOnCPUThread([]() { Cheevos::Logout(); }, true);
|
||||
updateLoginState();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "common/log.h"
|
||||
#include "common/minizip_helpers.h"
|
||||
#include "common/string_util.h"
|
||||
#include "mainwindow.h"
|
||||
#include "qthost.h"
|
||||
#include "qtutils.h"
|
||||
#include "scmversion/scmversion.h"
|
||||
|
@ -45,7 +46,7 @@ static const char* THIS_RELEASE_TAG = SCM_RELEASE_TAG;
|
|||
|
||||
#endif
|
||||
|
||||
AutoUpdaterDialog::AutoUpdaterDialog(QtHostInterface* host_interface, QWidget* parent /* = nullptr */)
|
||||
AutoUpdaterDialog::AutoUpdaterDialog(EmuThread* host_interface, QWidget* parent /* = nullptr */)
|
||||
: QDialog(parent), m_host_interface(host_interface)
|
||||
{
|
||||
m_network_access_mgr = new QNetworkAccessManager(this);
|
||||
|
@ -375,7 +376,7 @@ void AutoUpdaterDialog::downloadUpdateClicked()
|
|||
progress.setValue(static_cast<int>(received));
|
||||
});
|
||||
|
||||
connect(m_network_access_mgr, &QNetworkAccessManager::finished, [this, &progress](QNetworkReply* reply) {
|
||||
connect(m_network_access_mgr, &QNetworkAccessManager::finished, this, [this, &progress](QNetworkReply* reply) {
|
||||
m_network_access_mgr->disconnect();
|
||||
|
||||
if (reply->error() != QNetworkReply::NoError)
|
||||
|
@ -408,7 +409,7 @@ void AutoUpdaterDialog::downloadUpdateClicked()
|
|||
else if (result == 1)
|
||||
{
|
||||
// updater started
|
||||
m_host_interface->requestExit();
|
||||
g_main_window->requestExit();
|
||||
done(0);
|
||||
}
|
||||
|
||||
|
@ -417,8 +418,7 @@ void AutoUpdaterDialog::downloadUpdateClicked()
|
|||
|
||||
bool AutoUpdaterDialog::updateNeeded() const
|
||||
{
|
||||
QString last_checked_sha =
|
||||
QString::fromStdString(Host::GetBaseStringSettingValue("AutoUpdater", "LastVersion"));
|
||||
QString last_checked_sha = QString::fromStdString(Host::GetBaseStringSettingValue("AutoUpdater", "LastVersion"));
|
||||
|
||||
Log_InfoPrintf("Current SHA: %s", g_scm_hash_str);
|
||||
Log_InfoPrintf("Latest SHA: %s", m_latest_sha.toUtf8().constData());
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
class QNetworkAccessManager;
|
||||
class QNetworkReply;
|
||||
|
||||
class QtHostInterface;
|
||||
class EmuThread;
|
||||
|
||||
class AutoUpdaterDialog final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AutoUpdaterDialog(QtHostInterface* host_interface, QWidget* parent = nullptr);
|
||||
explicit AutoUpdaterDialog(EmuThread* host_interface, QWidget* parent = nullptr);
|
||||
~AutoUpdaterDialog();
|
||||
|
||||
static bool isSupported();
|
||||
|
@ -54,7 +54,7 @@ private:
|
|||
|
||||
Ui::AutoUpdaterDialog m_ui;
|
||||
|
||||
QtHostInterface* m_host_interface;
|
||||
EmuThread* m_host_interface;
|
||||
QNetworkAccessManager* m_network_access_mgr = nullptr;
|
||||
QString m_latest_sha;
|
||||
QString m_download_url;
|
||||
|
|
|
@ -7,13 +7,90 @@
|
|||
#include <QtWidgets/QFileDialog>
|
||||
#include <algorithm>
|
||||
|
||||
static void populateDropDownForRegion(ConsoleRegion region, QComboBox* cb,
|
||||
std::vector<std::pair<std::string, const BIOS::ImageInfo*>>& images)
|
||||
BIOSSettingsWidget::BIOSSettingsWidget(SettingsDialog* dialog, QWidget* parent) : QWidget(parent), m_dialog(dialog)
|
||||
{
|
||||
SettingsInterface* sif = dialog->getSettingsInterface();
|
||||
|
||||
m_ui.setupUi(this);
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableTTYOutput, "BIOS", "PatchTTYEnable", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.fastBoot, "BIOS", "PatchFastBoot", false);
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.fastBoot, tr("Fast Boot"), tr("Unchecked"),
|
||||
tr("Patches the BIOS to skip the console's boot animation. Does not work with all games, "
|
||||
"but usually safe to enable."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.enableTTYOutput, tr("Enable TTY Output"), tr("Unchecked"),
|
||||
tr("Patches the BIOS to log calls to printf(). Only use when debugging, can break games."));
|
||||
|
||||
connect(m_ui.imageNTSCJ, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) {
|
||||
if (m_dialog->isPerGameSettings() && index == 0)
|
||||
{
|
||||
m_dialog->removeSettingValue("BIOS", "PathNTSCJ");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dialog->setStringSettingValue("BIOS", "PathNTSCJ",
|
||||
m_ui.imageNTSCJ->itemData(index).toString().toStdString().c_str());
|
||||
}
|
||||
});
|
||||
connect(m_ui.imageNTSCU, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) {
|
||||
if (m_dialog->isPerGameSettings() && index == 0)
|
||||
{
|
||||
m_dialog->removeSettingValue("BIOS", "PathNTSCU");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dialog->setStringSettingValue("BIOS", "PathNTSCU",
|
||||
m_ui.imageNTSCU->itemData(index).toString().toStdString().c_str());
|
||||
}
|
||||
});
|
||||
connect(m_ui.imagePAL, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) {
|
||||
if (m_dialog->isPerGameSettings() && index == 0)
|
||||
{
|
||||
m_dialog->removeSettingValue("BIOS", "PathPAL");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dialog->setStringSettingValue("BIOS", "PathPAL",
|
||||
m_ui.imagePAL->itemData(index).toString().toStdString().c_str());
|
||||
}
|
||||
});
|
||||
|
||||
connect(m_ui.refresh, &QPushButton::clicked, this, &BIOSSettingsWidget::refreshList);
|
||||
|
||||
m_ui.searchDirectory->setText(QString::fromStdString(EmuFolders::Bios));
|
||||
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.searchDirectory, m_ui.browseSearchDirectory,
|
||||
m_ui.openSearchDirectory, nullptr, "BIOS", "SearchDirectory",
|
||||
Path::Combine(EmuFolders::DataRoot, "bios"));
|
||||
connect(m_ui.searchDirectory, &QLineEdit::textChanged, this, &BIOSSettingsWidget::refreshList);
|
||||
refreshList();
|
||||
}
|
||||
|
||||
BIOSSettingsWidget::~BIOSSettingsWidget() = default;
|
||||
|
||||
void BIOSSettingsWidget::refreshList()
|
||||
{
|
||||
auto images = BIOS::FindBIOSImagesInDirectory(m_ui.searchDirectory->text().toUtf8().constData());
|
||||
populateDropDownForRegion(ConsoleRegion::NTSC_J, m_ui.imageNTSCJ, images);
|
||||
populateDropDownForRegion(ConsoleRegion::NTSC_U, m_ui.imageNTSCU, images);
|
||||
populateDropDownForRegion(ConsoleRegion::PAL, m_ui.imagePAL, images);
|
||||
|
||||
setDropDownValue(m_ui.imageNTSCJ, m_dialog->getStringValue("BIOS", "PathNTSCJ", std::nullopt));
|
||||
setDropDownValue(m_ui.imageNTSCU, m_dialog->getStringValue("BIOS", "PathNTSCU", std::nullopt));
|
||||
setDropDownValue(m_ui.imagePAL, m_dialog->getStringValue("BIOS", "PathPAL", std::nullopt));
|
||||
}
|
||||
|
||||
void BIOSSettingsWidget::populateDropDownForRegion(ConsoleRegion region, QComboBox* cb,
|
||||
std::vector<std::pair<std::string, const BIOS::ImageInfo*>>& images)
|
||||
{
|
||||
QSignalBlocker sb(cb);
|
||||
cb->clear();
|
||||
|
||||
cb->addItem(QIcon(QStringLiteral(":/icons/system-search.png")), qApp->translate("BIOSSettingsWidget", "Auto-Detect"));
|
||||
if (m_dialog->isPerGameSettings())
|
||||
cb->addItem(QIcon(QStringLiteral(":/icons/system-search.png")), tr("Use Global Setting"));
|
||||
|
||||
cb->addItem(QIcon(QStringLiteral(":/icons/system-search.png")), tr("Auto-Detect"));
|
||||
|
||||
std::sort(images.begin(), images.end(), [region](const auto& left, const auto& right) {
|
||||
const bool left_region_match = (left.second && left.second->region == region);
|
||||
|
@ -28,32 +105,8 @@ static void populateDropDownForRegion(ConsoleRegion region, QComboBox* cb,
|
|||
|
||||
for (const auto& [name, info] : images)
|
||||
{
|
||||
QIcon icon;
|
||||
if (info)
|
||||
{
|
||||
switch (info->region)
|
||||
{
|
||||
case ConsoleRegion::NTSC_J:
|
||||
icon = QIcon(QStringLiteral(":/icons/flag-jp.png"));
|
||||
break;
|
||||
case ConsoleRegion::PAL:
|
||||
icon = QIcon(QStringLiteral(":/icons/flag-eu.png"));
|
||||
break;
|
||||
case ConsoleRegion::NTSC_U:
|
||||
icon = QIcon(QStringLiteral(":/icons/flag-uc.png"));
|
||||
break;
|
||||
default:
|
||||
icon = QIcon(QStringLiteral(":/icons/applications-other.png"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
icon = QIcon(QStringLiteral(":/icons/applications-other.png"));
|
||||
}
|
||||
|
||||
QString name_str(QString::fromStdString(name));
|
||||
cb->addItem(icon,
|
||||
cb->addItem(QtUtils::GetIconForRegion(info ? info->region : ConsoleRegion::Count),
|
||||
QStringLiteral("%1 (%2)")
|
||||
.arg(info ? QString(info->description) : qApp->translate("BIOSSettingsWidget", "Unknown"))
|
||||
.arg(name_str),
|
||||
|
@ -61,17 +114,17 @@ static void populateDropDownForRegion(ConsoleRegion region, QComboBox* cb,
|
|||
}
|
||||
}
|
||||
|
||||
static void setDropDownValue(QComboBox* cb, const std::string& name)
|
||||
void BIOSSettingsWidget::setDropDownValue(QComboBox* cb, const std::optional<std::string>& name)
|
||||
{
|
||||
QSignalBlocker sb(cb);
|
||||
|
||||
if (name.empty())
|
||||
if (!name.has_value() || name->empty())
|
||||
{
|
||||
cb->setCurrentIndex(0);
|
||||
cb->setCurrentIndex((m_dialog->isPerGameSettings() && name.has_value()) ? 1 : 0);
|
||||
return;
|
||||
}
|
||||
|
||||
QString qname(QString::fromStdString(name));
|
||||
QString qname(QString::fromStdString(name.value()));
|
||||
for (int i = 1; i < cb->count(); i++)
|
||||
{
|
||||
if (cb->itemData(i) == qname)
|
||||
|
@ -84,55 +137,3 @@ static void setDropDownValue(QComboBox* cb, const std::string& name)
|
|||
cb->addItem(qname, QVariant(qname));
|
||||
cb->setCurrentIndex(cb->count() - 1);
|
||||
}
|
||||
|
||||
BIOSSettingsWidget::BIOSSettingsWidget(SettingsDialog* dialog, QWidget* parent)
|
||||
: QWidget(parent), m_dialog(dialog)
|
||||
{
|
||||
SettingsInterface* sif = dialog->getSettingsInterface();
|
||||
|
||||
m_ui.setupUi(this);
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableTTYOutput, "BIOS", "PatchTTYEnable", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.fastBoot, "BIOS", "PatchFastBoot", false);
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.fastBoot, tr("Fast Boot"), tr("Unchecked"),
|
||||
tr("Patches the BIOS to skip the console's boot animation. Does not work with all games, "
|
||||
"but usually safe to enable."));
|
||||
dialog->registerWidgetHelp(m_ui.enableTTYOutput, tr("Enable TTY Output"), tr("Unchecked"),
|
||||
tr("Patches the BIOS to log calls to printf(). Only use when debugging, can break games."));
|
||||
|
||||
refreshList();
|
||||
|
||||
connect(m_ui.imageNTSCJ, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) {
|
||||
m_dialog->setStringSettingValue("BIOS", "PathNTSCJ",
|
||||
m_ui.imageNTSCJ->itemData(index).toString().toStdString().c_str());
|
||||
});
|
||||
connect(m_ui.imageNTSCU, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) {
|
||||
m_dialog->setStringSettingValue("BIOS", "PathNTSCU",
|
||||
m_ui.imageNTSCU->itemData(index).toString().toStdString().c_str());
|
||||
});
|
||||
connect(m_ui.imagePAL, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) {
|
||||
m_dialog->setStringSettingValue("BIOS", "PathPAL",
|
||||
m_ui.imagePAL->itemData(index).toString().toStdString().c_str());
|
||||
});
|
||||
|
||||
connect(m_ui.refresh, &QPushButton::clicked, this, &BIOSSettingsWidget::refreshList);
|
||||
|
||||
m_ui.searchDirectory->setText(QString::fromStdString(EmuFolders::Bios));
|
||||
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.searchDirectory, m_ui.browseSearchDirectory, m_ui.openSearchDirectory, nullptr, "BIOS", "SearchDirectory", Path::Combine(EmuFolders::DataRoot, "bios"));
|
||||
connect(m_ui.searchDirectory, &QLineEdit::textChanged, this, &BIOSSettingsWidget::refreshList);
|
||||
}
|
||||
|
||||
BIOSSettingsWidget::~BIOSSettingsWidget() = default;
|
||||
|
||||
void BIOSSettingsWidget::refreshList()
|
||||
{
|
||||
auto images = BIOS::FindBIOSImagesInDirectory(m_ui.searchDirectory->text().toUtf8().constData());
|
||||
populateDropDownForRegion(ConsoleRegion::NTSC_J, m_ui.imageNTSCJ, images);
|
||||
populateDropDownForRegion(ConsoleRegion::NTSC_U, m_ui.imageNTSCU, images);
|
||||
populateDropDownForRegion(ConsoleRegion::PAL, m_ui.imagePAL, images);
|
||||
|
||||
setDropDownValue(m_ui.imageNTSCJ, m_dialog->getEffectiveStringValue("BIOS", "PathNTSCJ", ""));
|
||||
setDropDownValue(m_ui.imageNTSCU, m_dialog->getEffectiveStringValue("BIOS", "PathNTSCU", ""));
|
||||
setDropDownValue(m_ui.imagePAL, m_dialog->getEffectiveStringValue("BIOS", "PathPAL", ""));
|
||||
}
|
||||
|
|
|
@ -6,6 +6,11 @@
|
|||
|
||||
class SettingsDialog;
|
||||
|
||||
enum class ConsoleRegion;
|
||||
namespace BIOS {
|
||||
struct ImageInfo;
|
||||
}
|
||||
|
||||
class BIOSSettingsWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -18,6 +23,10 @@ private Q_SLOTS:
|
|||
void refreshList();
|
||||
|
||||
private:
|
||||
void populateDropDownForRegion(ConsoleRegion region, QComboBox* cb,
|
||||
std::vector<std::pair<std::string, const BIOS::ImageInfo*>>& images);
|
||||
void setDropDownValue(QComboBox* cb, const std::optional<std::string>& name);
|
||||
|
||||
Ui::BIOSSettingsWidget m_ui;
|
||||
|
||||
SettingsDialog* m_dialog;
|
||||
|
|
|
@ -188,7 +188,7 @@ void CheatManagerDialog::connectUi()
|
|||
connect(m_ui.scanTable, &QTableWidget::itemChanged, this, &CheatManagerDialog::scanItemChanged);
|
||||
connect(m_ui.watchTable, &QTableWidget::itemChanged, this, &CheatManagerDialog::watchItemChanged);
|
||||
|
||||
connect(g_emu_thread, &QtHostInterface::cheatEnabled, this,
|
||||
connect(g_emu_thread, &EmuThread::cheatEnabled, this,
|
||||
&CheatManagerDialog::setCheatCheckState);
|
||||
}
|
||||
|
||||
|
@ -351,7 +351,7 @@ CheatList* CheatManagerDialog::getCheatList() const
|
|||
}
|
||||
if (!list)
|
||||
{
|
||||
g_emu_thread->executeOnEmulationThread(
|
||||
Host::RunOnCPUThread(
|
||||
[]() { System::SetCheatList(std::make_unique<CheatList>()); }, true);
|
||||
list = System::GetCheatList();
|
||||
}
|
||||
|
@ -417,7 +417,7 @@ void CheatManagerDialog::fillItemForCheatCode(QTreeWidgetItem* item, u32 index,
|
|||
|
||||
void CheatManagerDialog::saveCheatList()
|
||||
{
|
||||
g_emu_thread->executeOnEmulationThread([]() { System::SaveCheatList(); });
|
||||
Host::RunOnCPUThread([]() { System::SaveCheatList(); });
|
||||
}
|
||||
|
||||
void CheatManagerDialog::cheatListCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous)
|
||||
|
@ -479,7 +479,7 @@ void CheatManagerDialog::cheatListItemChanged(QTreeWidgetItem* item, int column)
|
|||
if (cc.enabled == new_enabled)
|
||||
return;
|
||||
|
||||
g_emu_thread->executeOnEmulationThread([index, new_enabled]() {
|
||||
Host::RunOnCPUThread([index, new_enabled]() {
|
||||
System::GetCheatList()->SetCodeEnabled(static_cast<u32>(index), new_enabled);
|
||||
System::SaveCheatList();
|
||||
});
|
||||
|
@ -501,7 +501,7 @@ void CheatManagerDialog::activateCheat(u32 index)
|
|||
const bool new_enabled = !cc.enabled;
|
||||
setCheatCheckState(index, new_enabled);
|
||||
|
||||
g_emu_thread->executeOnEmulationThread([index, new_enabled]() {
|
||||
Host::RunOnCPUThread([index, new_enabled]() {
|
||||
System::GetCheatList()->SetCodeEnabled(index, new_enabled);
|
||||
System::SaveCheatList();
|
||||
});
|
||||
|
@ -551,7 +551,7 @@ void CheatManagerDialog::addCodeClicked()
|
|||
fillItemForCheatCode(item, list->GetCodeCount(), new_code);
|
||||
group_item->setExpanded(true);
|
||||
|
||||
g_emu_thread->executeOnEmulationThread(
|
||||
Host::RunOnCPUThread(
|
||||
[this, &new_code]() {
|
||||
System::GetCheatList()->AddCode(std::move(new_code));
|
||||
System::SaveCheatList();
|
||||
|
@ -597,7 +597,7 @@ void CheatManagerDialog::editCodeClicked()
|
|||
updateCheatList();
|
||||
}
|
||||
|
||||
g_emu_thread->executeOnEmulationThread(
|
||||
Host::RunOnCPUThread(
|
||||
[index, &new_code]() {
|
||||
System::GetCheatList()->SetCode(static_cast<u32>(index), std::move(new_code));
|
||||
System::SaveCheatList();
|
||||
|
@ -623,7 +623,7 @@ void CheatManagerDialog::deleteCodeClicked()
|
|||
return;
|
||||
}
|
||||
|
||||
g_emu_thread->executeOnEmulationThread(
|
||||
Host::RunOnCPUThread(
|
||||
[index]() {
|
||||
System::GetCheatList()->RemoveCode(static_cast<u32>(index));
|
||||
System::SaveCheatList();
|
||||
|
@ -663,7 +663,7 @@ void CheatManagerDialog::importFromFileTriggered()
|
|||
return;
|
||||
}
|
||||
|
||||
g_emu_thread->executeOnEmulationThread(
|
||||
Host::RunOnCPUThread(
|
||||
[&new_cheats]() {
|
||||
DebugAssert(System::HasCheatList());
|
||||
System::GetCheatList()->MergeList(new_cheats);
|
||||
|
@ -686,7 +686,7 @@ void CheatManagerDialog::importFromTextTriggered()
|
|||
return;
|
||||
}
|
||||
|
||||
g_emu_thread->executeOnEmulationThread(
|
||||
Host::RunOnCPUThread(
|
||||
[&new_cheats]() {
|
||||
DebugAssert(System::HasCheatList());
|
||||
System::GetCheatList()->MergeList(new_cheats);
|
||||
|
@ -716,7 +716,7 @@ void CheatManagerDialog::clearClicked()
|
|||
return;
|
||||
}
|
||||
|
||||
g_emu_thread->executeOnEmulationThread([] { System::ClearCheatList(true); }, true);
|
||||
Host::RunOnCPUThread([] { System::ClearCheatList(true); }, true);
|
||||
updateCheatList();
|
||||
}
|
||||
|
||||
|
@ -731,7 +731,7 @@ void CheatManagerDialog::resetClicked()
|
|||
return;
|
||||
}
|
||||
|
||||
g_emu_thread->executeOnEmulationThread([] { System::DeleteCheatList(); }, true);
|
||||
Host::RunOnCPUThread([] { System::DeleteCheatList(); }, true);
|
||||
updateCheatList();
|
||||
}
|
||||
|
||||
|
|
|
@ -25,12 +25,6 @@ ConsoleSettingsWidget::ConsoleSettingsWidget(SettingsDialog* dialog, QWidget* pa
|
|||
qApp->translate("CPUExecutionMode", Settings::GetCPUExecutionModeDisplayName(static_cast<CPUExecutionMode>(i))));
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < static_cast<u32>(MultitapMode::Count); i++)
|
||||
{
|
||||
m_ui.multitapMode->addItem(
|
||||
qApp->translate("MultitapMode", Settings::GetMultitapModeDisplayName(static_cast<MultitapMode>(i))));
|
||||
}
|
||||
|
||||
static constexpr float TIME_PER_SECTOR_DOUBLE_SPEED = 1000.0f / 150.0f;
|
||||
m_ui.cdromReadaheadSectors->addItem(tr("Disabled (Synchronous)"));
|
||||
for (u32 i = 1; i <= 32; i++)
|
||||
|
@ -55,9 +49,7 @@ ConsoleSettingsWidget::ConsoleSettingsWidget(SettingsDialog* dialog, QWidget* pa
|
|||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.cdromLoadImageToRAM, "CDROM", "LoadImageToRAM", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.cdromLoadImagePatches, "CDROM", "LoadImagePatches", false);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cdromSeekSpeedup, "CDROM", "SeekSpeedup", 1);
|
||||
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.multitapMode, "ControllerPorts", "MultitapMode",
|
||||
&Settings::ParseMultitapModeName, &Settings::GetMultitapModeName,
|
||||
Settings::DEFAULT_MULTITAP_MODE);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cdromReadSpeedup, "CDROM", "ReadSpeedup", 1, 1);
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.region, tr("Region"), tr("Auto-Detect"),
|
||||
tr("Determines the emulated hardware type."));
|
||||
|
@ -99,21 +91,12 @@ ConsoleSettingsWidget::ConsoleSettingsWidget(SettingsDialog* dialog, QWidget* pa
|
|||
dialog->registerWidgetHelp(m_ui.cdromLoadImagePatches, tr("Apply Image Patches"), tr("Unchecked"),
|
||||
tr("Automatically applies patches to disc images when they are present in the same "
|
||||
"directory. Currently only PPF patches are supported with this option."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.multitapMode, tr("Multitap"), tr("Disabled"),
|
||||
tr("Enables multitap support on specified controller ports. Leave disabled for games that do "
|
||||
"not support multitap input."));
|
||||
|
||||
m_ui.cpuClockSpeed->setEnabled(m_ui.enableCPUClockSpeedControl->checkState() == Qt::Checked);
|
||||
m_ui.cdromReadSpeedup->setCurrentIndex(m_dialog->getEffectiveIntValue("CDROM", "ReadSpeedup", 1) - 1);
|
||||
|
||||
connect(m_ui.enableCPUClockSpeedControl, &QCheckBox::stateChanged, this,
|
||||
&ConsoleSettingsWidget::onEnableCPUClockSpeedControlChecked);
|
||||
connect(m_ui.cpuClockSpeed, &QSlider::valueChanged, this, &ConsoleSettingsWidget::onCPUClockSpeedValueChanged);
|
||||
connect(m_ui.cdromReadSpeedup, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
&ConsoleSettingsWidget::onCDROMReadSpeedupValueChanged);
|
||||
connect(m_ui.multitapMode, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
[this](int index) { emit multitapModeChanged(); });
|
||||
|
||||
calculateCPUClockValue();
|
||||
}
|
||||
|
@ -164,11 +147,6 @@ void ConsoleSettingsWidget::updateCPUClockSpeedLabel()
|
|||
m_ui.cpuClockSpeedLabel->setText(tr("%1% (%2MHz)").arg(percent).arg(frequency / 1000000.0, 0, 'f', 2));
|
||||
}
|
||||
|
||||
void ConsoleSettingsWidget::onCDROMReadSpeedupValueChanged(int value)
|
||||
{
|
||||
m_dialog->setIntSettingValue("CDROM", "ReadSpeedup", value + 1);
|
||||
}
|
||||
|
||||
void ConsoleSettingsWidget::calculateCPUClockValue()
|
||||
{
|
||||
const u32 numerator = static_cast<u32>(m_dialog->getEffectiveIntValue("CPU", "OverclockNumerator", 1));
|
||||
|
|
|
@ -14,14 +14,10 @@ public:
|
|||
explicit ConsoleSettingsWidget(SettingsDialog* dialog, QWidget* parent);
|
||||
~ConsoleSettingsWidget();
|
||||
|
||||
Q_SIGNALS:
|
||||
void multitapModeChanged();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onEnableCPUClockSpeedControlChecked(int state);
|
||||
void onCPUClockSpeedValueChanged(int value);
|
||||
void updateCPUClockSpeedLabel();
|
||||
void onCDROMReadSpeedupValueChanged(int value);
|
||||
|
||||
private:
|
||||
void calculateCPUClockValue();
|
||||
|
|
|
@ -305,25 +305,6 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>Controller Ports</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Multitap:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="multitapMode"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
<string>Automatic binding</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="gamepad-line">
|
||||
<iconset theme="ControllerSettings">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
|
@ -67,7 +67,7 @@
|
|||
<string>Clear Bindings</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="file-reduce-line">
|
||||
<iconset theme="Clear">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
|
|
|
@ -22,7 +22,7 @@ ControllerBindingWidget::ControllerBindingWidget(QWidget* parent, ControllerSett
|
|||
{
|
||||
m_ui.setupUi(this);
|
||||
populateControllerTypes();
|
||||
onTypeChanged();
|
||||
populateBindingWidget();
|
||||
|
||||
connect(m_ui.controllerType, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
&ControllerBindingWidget::onTypeChanged);
|
||||
|
@ -96,12 +96,15 @@ void ControllerBindingWidget::onTypeChanged()
|
|||
|
||||
SettingsInterface* sif = m_dialog->getProfileSettingsInterface();
|
||||
if (sif)
|
||||
{
|
||||
sif->SetStringValue(m_config_section.c_str(), "Type", Settings::GetControllerTypeName(m_controller_type));
|
||||
g_emu_thread->reloadGameSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
Host::SetBaseStringSettingValue(m_config_section.c_str(), "Type", Settings::GetControllerTypeName(m_controller_type));
|
||||
|
||||
// TODO: reloadInputProfile() ?
|
||||
g_emu_thread->applySettings();
|
||||
g_emu_thread->applySettings();
|
||||
}
|
||||
|
||||
populateBindingWidget();
|
||||
}
|
||||
|
@ -197,7 +200,7 @@ ControllerBindingWidget_Base::~ControllerBindingWidget_Base() {}
|
|||
|
||||
QIcon ControllerBindingWidget_Base::getIcon() const
|
||||
{
|
||||
return QIcon::fromTheme("artboard-2-line");
|
||||
return QIcon::fromTheme("BIOSSettings");
|
||||
}
|
||||
|
||||
void ControllerBindingWidget_Base::initBindingWidgets()
|
||||
|
@ -304,7 +307,7 @@ ControllerBindingWidget_DigitalController::~ControllerBindingWidget_DigitalContr
|
|||
|
||||
QIcon ControllerBindingWidget_DigitalController::getIcon() const
|
||||
{
|
||||
return QIcon::fromTheme("gamepad-line");
|
||||
return QIcon::fromTheme("ControllerSettings");
|
||||
}
|
||||
|
||||
ControllerBindingWidget_Base* ControllerBindingWidget_DigitalController::createInstance(ControllerBindingWidget* parent)
|
||||
|
@ -325,7 +328,7 @@ ControllerBindingWidget_AnalogController::~ControllerBindingWidget_AnalogControl
|
|||
|
||||
QIcon ControllerBindingWidget_AnalogController::getIcon() const
|
||||
{
|
||||
return QIcon::fromTheme("gamepad-line");
|
||||
return QIcon::fromTheme("ControllerSettings");
|
||||
}
|
||||
|
||||
ControllerBindingWidget_Base* ControllerBindingWidget_AnalogController::createInstance(ControllerBindingWidget* parent)
|
||||
|
|
|
@ -21,18 +21,24 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
|
|||
#else
|
||||
m_ui.enableRawInput->setEnabled(false);
|
||||
#endif
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.multitapPort1, "Pad", "MultitapPort1", false);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.multitapPort2, "Pad", "MultitapPort2", false);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.pointerXInvert, "Pad", "PointerXInvert", false);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.pointerYInvert, "Pad", "PointerYInvert", false);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, m_ui.pointerXScale, "Pad", "PointerXScale", 8.0f);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, m_ui.pointerYScale, "Pad", "PointerYScale", 8.0f);
|
||||
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.multitapMode, "ControllerPorts", "MultitapMode",
|
||||
&Settings::ParseMultitapModeName, &Settings::GetMultitapModeName,
|
||||
Settings::DEFAULT_MULTITAP_MODE);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.pointerXInvert, "ControllerPorts",
|
||||
"PointerXInvert", false);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.pointerYInvert, "ControllerPorts",
|
||||
"PointerYInvert", false);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, m_ui.pointerXScale, "ControllerPorts",
|
||||
"PointerXScale", 8.0f);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, m_ui.pointerYScale, "ControllerPorts",
|
||||
"PointerYScale", 8.0f);
|
||||
|
||||
if (dialog->isEditingProfile())
|
||||
{
|
||||
m_ui.useProfileHotkeyBindings->setChecked(m_dialog->getBoolValue("Pad", "UseProfileHotkeyBindings", false));
|
||||
m_ui.useProfileHotkeyBindings->setChecked(
|
||||
m_dialog->getBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false));
|
||||
connect(m_ui.useProfileHotkeyBindings, &QCheckBox::stateChanged, this, [this](int new_state) {
|
||||
m_dialog->setBoolValue("Pad", "UseProfileHotkeyBindings", (new_state == Qt::Checked));
|
||||
m_dialog->setBoolValue("ControllerPorts", "UseProfileHotkeyBindings", (new_state == Qt::Checked));
|
||||
emit bindingSetupChanged();
|
||||
});
|
||||
}
|
||||
|
@ -46,8 +52,7 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
|
|||
|
||||
connect(m_ui.enableSDLSource, &QCheckBox::stateChanged, this,
|
||||
&ControllerGlobalSettingsWidget::updateSDLOptionsEnabled);
|
||||
for (QCheckBox* cb : {m_ui.multitapPort1, m_ui.multitapPort2})
|
||||
connect(cb, &QCheckBox::stateChanged, this, [this]() { emit bindingSetupChanged(); });
|
||||
connect(m_ui.multitapMode, &QComboBox::currentIndexChanged, this, [this]() { emit bindingSetupChanged(); });
|
||||
|
||||
connect(m_ui.pointerXScale, &QSlider::valueChanged, this,
|
||||
[this](int value) { m_ui.pointerXScaleLabel->setText(QStringLiteral("%1").arg(value)); });
|
||||
|
|
|
@ -239,7 +239,7 @@
|
|||
<property name="title">
|
||||
<string>Controller Multitap</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
|
@ -251,17 +251,34 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="multitapPort1">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Multitap on Console Port 1</string>
|
||||
<string>Multitap Mode:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="multitapPort2">
|
||||
<property name="text">
|
||||
<string>Multitap on Console Port 2</string>
|
||||
</property>
|
||||
<widget class="QComboBox" name="multitapMode">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Disabled</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Enable on Port 1 Only</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Enable on Port 2 Only</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Enable on Ports 1 and 2</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
#include "controllerglobalsettingswidget.h"
|
||||
#include "core/controller.h"
|
||||
#include "core/host_settings.h"
|
||||
#include "util/ini_settings_interface.h"
|
||||
#include "frontend-common/input_manager.h"
|
||||
#include "hotkeysettingswidget.h"
|
||||
#include "qthost.h"
|
||||
#include "util/ini_settings_interface.h"
|
||||
|
||||
#include <QtWidgets/QInputDialog>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
|
@ -37,13 +37,12 @@ ControllerSettingsDialog::ControllerSettingsDialog(QWidget* parent /* = nullptr
|
|||
connect(m_ui.deleteProfile, &QPushButton::clicked, this, &ControllerSettingsDialog::onDeleteProfileClicked);
|
||||
connect(m_ui.restoreDefaults, &QPushButton::clicked, this, &ControllerSettingsDialog::onRestoreDefaultsClicked);
|
||||
|
||||
connect(g_emu_thread, &QtHostInterface::onInputDevicesEnumerated, this,
|
||||
connect(g_emu_thread, &EmuThread::onInputDevicesEnumerated, this,
|
||||
&ControllerSettingsDialog::onInputDevicesEnumerated);
|
||||
connect(g_emu_thread, &QtHostInterface::onInputDeviceConnected, this,
|
||||
&ControllerSettingsDialog::onInputDeviceConnected);
|
||||
connect(g_emu_thread, &QtHostInterface::onInputDeviceDisconnected, this,
|
||||
connect(g_emu_thread, &EmuThread::onInputDeviceConnected, this, &ControllerSettingsDialog::onInputDeviceConnected);
|
||||
connect(g_emu_thread, &EmuThread::onInputDeviceDisconnected, this,
|
||||
&ControllerSettingsDialog::onInputDeviceDisconnected);
|
||||
connect(g_emu_thread, &QtHostInterface::onVibrationMotorsEnumerated, this,
|
||||
connect(g_emu_thread, &EmuThread::onVibrationMotorsEnumerated, this,
|
||||
&ControllerSettingsDialog::onVibrationMotorsEnumerated);
|
||||
|
||||
// trigger a device enumeration to populate the device list
|
||||
|
@ -330,7 +329,7 @@ void ControllerSettingsDialog::createWidgets()
|
|||
// global settings
|
||||
QListWidgetItem* item = new QListWidgetItem();
|
||||
item->setText(tr("Global Settings"));
|
||||
item->setIcon(QIcon::fromTheme("settings-3-line"));
|
||||
item->setIcon(QIcon::fromTheme("GeneralSettings"));
|
||||
m_ui.settingsCategory->addItem(item);
|
||||
m_ui.settingsCategory->setCurrentRow(0);
|
||||
m_global_settings = new ControllerGlobalSettingsWidget(m_ui.settingsContainer, this);
|
||||
|
@ -342,8 +341,14 @@ void ControllerSettingsDialog::createWidgets()
|
|||
}
|
||||
|
||||
// load mtap settings
|
||||
const MultitapMode mtap_mode =
|
||||
Settings::ParseMultitapModeName(
|
||||
getStringValue("ControllerPorts", "MultitapMode", Settings::GetMultitapModeName(Settings::DEFAULT_MULTITAP_MODE))
|
||||
.c_str())
|
||||
.value_or(Settings::DEFAULT_MULTITAP_MODE);
|
||||
const std::array<bool, 2> mtap_enabled = {
|
||||
{getBoolValue("Pad", "MultitapPort1", false), getBoolValue("Pad", "MultitapPort2", false)}};
|
||||
{(mtap_mode == MultitapMode::Port1Only || mtap_mode == MultitapMode::BothPorts),
|
||||
(mtap_mode == MultitapMode::Port2Only || mtap_mode == MultitapMode::BothPorts)}};
|
||||
|
||||
// we reorder things a little to make it look less silly for mtap
|
||||
static constexpr const std::array<u32, MAX_PORTS> mtap_port_order = {{0, 2, 3, 4, 1, 5, 6, 7}};
|
||||
|
@ -373,11 +378,11 @@ void ControllerSettingsDialog::createWidgets()
|
|||
}
|
||||
|
||||
// only add hotkeys if we're editing global settings
|
||||
if (!m_profile_interface || m_profile_interface->GetBoolValue("Pad", "UseProfileHotkeyBindings", false))
|
||||
if (!m_profile_interface || m_profile_interface->GetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false))
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem();
|
||||
item->setText(tr("Hotkeys"));
|
||||
item->setIcon(QIcon::fromTheme("keyboard-line"));
|
||||
item->setIcon(QIcon::fromTheme("HotkeySettings"));
|
||||
m_ui.settingsCategory->addItem(item);
|
||||
m_hotkey_settings = new HotkeySettingsWidget(m_ui.settingsContainer, this);
|
||||
m_ui.settingsContainer->addWidget(m_hotkey_settings);
|
||||
|
@ -397,7 +402,7 @@ void ControllerSettingsDialog::updateListDescription(u32 global_slot, Controller
|
|||
bool is_ok;
|
||||
if (item_data.toUInt(&is_ok) == global_slot && is_ok)
|
||||
{
|
||||
//const bool is_mtap_port = Controller::PadIsMultitapSlot(global_slot);
|
||||
// const bool is_mtap_port = Controller::PadIsMultitapSlot(global_slot);
|
||||
const auto [port, slot] = Controller::ConvertPadToPortAndSlot(global_slot);
|
||||
const bool mtap_enabled = getBoolValue("Pad", (port == 0) ? "MultitapPort1" : "MultitapPort2", false);
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@
|
|||
<string>New Profile</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="file-add-line">
|
||||
<iconset theme="PostProcessingAdd">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
|
@ -92,7 +92,7 @@
|
|||
<string>Load Profile</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="folder-open-line"/>
|
||||
<iconset theme="LoadState"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -102,7 +102,7 @@
|
|||
<string>Delete Profile</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="file-reduce-line">
|
||||
<iconset theme="PostProcessingRemove">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
|
@ -113,7 +113,7 @@
|
|||
<string>Restore Defaults</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="restart-line"/>
|
||||
<iconset theme="Reset"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -84,7 +84,7 @@ void DebuggerWindow::onPauseActionToggled(bool paused)
|
|||
setUIEnabled(false);
|
||||
}
|
||||
|
||||
g_emu_thread->pauseSystem(paused);
|
||||
g_emu_thread->setSystemPaused(paused);
|
||||
}
|
||||
|
||||
void DebuggerWindow::onRunToCursorTriggered()
|
||||
|
@ -97,7 +97,7 @@ void DebuggerWindow::onRunToCursorTriggered()
|
|||
}
|
||||
|
||||
CPU::AddBreakpoint(addr.value(), true, true);
|
||||
g_emu_thread->pauseSystem(false);
|
||||
g_emu_thread->setSystemPaused(false);
|
||||
}
|
||||
|
||||
void DebuggerWindow::onGoToPCTriggered()
|
||||
|
@ -195,7 +195,7 @@ void DebuggerWindow::onStepOverActionTriggered()
|
|||
|
||||
// unpause to let it run to the breakpoint
|
||||
m_registers_model->saveCurrentValues();
|
||||
g_emu_thread->pauseSystem(false);
|
||||
g_emu_thread->setSystemPaused(false);
|
||||
}
|
||||
|
||||
void DebuggerWindow::onStepOutActionTriggered()
|
||||
|
@ -209,7 +209,7 @@ void DebuggerWindow::onStepOutActionTriggered()
|
|||
|
||||
// unpause to let it run to the breakpoint
|
||||
m_registers_model->saveCurrentValues();
|
||||
g_emu_thread->pauseSystem(false);
|
||||
g_emu_thread->setSystemPaused(false);
|
||||
}
|
||||
|
||||
void DebuggerWindow::onCodeViewItemActivated(QModelIndex index)
|
||||
|
@ -355,9 +355,9 @@ void DebuggerWindow::onMemorySearchStringChanged(const QString&)
|
|||
void DebuggerWindow::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
QMainWindow::closeEvent(event);
|
||||
g_emu_thread->pauseSystem(true, true);
|
||||
g_emu_thread->setSystemPaused(true, true);
|
||||
CPU::ClearBreakpoints();
|
||||
g_emu_thread->pauseSystem(false);
|
||||
g_emu_thread->setSystemPaused(false);
|
||||
emit closed();
|
||||
}
|
||||
|
||||
|
@ -383,10 +383,10 @@ void DebuggerWindow::setupAdditionalUi()
|
|||
|
||||
void DebuggerWindow::connectSignals()
|
||||
{
|
||||
QtHostInterface* hi = g_emu_thread;
|
||||
connect(hi, &QtHostInterface::systemPaused, this, &DebuggerWindow::onEmulationPaused);
|
||||
connect(hi, &QtHostInterface::systemResumed, this, &DebuggerWindow::onEmulationResumed);
|
||||
connect(hi, &QtHostInterface::debuggerMessageReported, this, &DebuggerWindow::onDebuggerMessageReported);
|
||||
EmuThread* hi = g_emu_thread;
|
||||
connect(hi, &EmuThread::systemPaused, this, &DebuggerWindow::onEmulationPaused);
|
||||
connect(hi, &EmuThread::systemResumed, this, &DebuggerWindow::onEmulationResumed);
|
||||
connect(hi, &EmuThread::debuggerMessageReported, this, &DebuggerWindow::onDebuggerMessageReported);
|
||||
|
||||
connect(m_ui.actionPause, &QAction::toggled, this, &DebuggerWindow::onPauseActionToggled);
|
||||
connect(m_ui.actionRunToCursor, &QAction::triggered, this, &DebuggerWindow::onRunToCursorTriggered);
|
||||
|
@ -415,7 +415,7 @@ void DebuggerWindow::connectSignals()
|
|||
|
||||
void DebuggerWindow::disconnectSignals()
|
||||
{
|
||||
QtHostInterface* hi = g_emu_thread;
|
||||
EmuThread* hi = g_emu_thread;
|
||||
hi->disconnect(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
#include <qpa/qplatformnativeinterface.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "common/windows_headers.h"
|
||||
#endif
|
||||
|
||||
Log_SetChannel(DisplayWidget);
|
||||
|
||||
DisplayWidget::DisplayWidget(QWidget* parent) : QWidget(parent)
|
||||
|
@ -288,7 +292,7 @@ bool DisplayWidget::event(QEvent* event)
|
|||
if (event->type() == QEvent::MouseButtonDblClick &&
|
||||
static_cast<const QMouseEvent*>(event)->button() == Qt::LeftButton &&
|
||||
!InputManager::HasAnyBindingsForKey(InputManager::MakePointerButtonKey(0, 0)) &&
|
||||
Host::GetBoolSettingValue("UI", "DoubleClickTogglesFullscreen", true))
|
||||
Host::GetBoolSettingValue("Main", "DoubleClickTogglesFullscreen", true))
|
||||
{
|
||||
g_emu_thread->toggleFullscreen();
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ private:
|
|||
bool m_should_hide_cursor = false;
|
||||
bool m_cursor_hidden = false;
|
||||
|
||||
std::vector<int> m_keys_pressed_with_modifiers;
|
||||
std::vector<u32> m_keys_pressed_with_modifiers;
|
||||
|
||||
u32 m_last_window_width = 0;
|
||||
u32 m_last_window_height = 0;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
<ClCompile Include="debuggermodels.cpp" />
|
||||
<ClCompile Include="debuggerwindow.cpp" />
|
||||
<ClCompile Include="enhancementsettingswidget.cpp" />
|
||||
<ClCompile Include="foldersettingswidget.cpp" />
|
||||
<ClCompile Include="gamelistmodel.cpp" />
|
||||
<ClCompile Include="gamelistsearchdirectoriesmodel.cpp" />
|
||||
<ClCompile Include="generalsettingswidget.cpp" />
|
||||
|
@ -32,10 +33,10 @@
|
|||
<ClCompile Include="gamelistsettingswidget.cpp" />
|
||||
<ClCompile Include="gamelistrefreshthread.cpp" />
|
||||
<ClCompile Include="gamelistwidget.cpp" />
|
||||
<ClCompile Include="gamesummarywidget.cpp" />
|
||||
<ClCompile Include="gamepropertiesdialog.cpp" />
|
||||
<ClCompile Include="gdbconnection.cpp" />
|
||||
<ClCompile Include="gdbserver.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="mainwindow.cpp" />
|
||||
<ClCompile Include="memorycardsettingswidget.cpp" />
|
||||
<ClCompile Include="memorycardeditordialog.cpp" />
|
||||
|
@ -86,6 +87,7 @@
|
|||
<QtMoc Include="gamelistrefreshthread.h" />
|
||||
<QtMoc Include="gamelistwidget.h" />
|
||||
<QtMoc Include="gamepropertiesdialog.h" />
|
||||
<QtMoc Include="gamesummarywidget.h" />
|
||||
<QtMoc Include="gdbconnection.h" />
|
||||
<QtMoc Include="gdbserver.h" />
|
||||
<QtMoc Include="postprocessingchainconfigwidget.h" />
|
||||
|
@ -93,6 +95,7 @@
|
|||
<QtMoc Include="postprocessingsettingswidget.h" />
|
||||
<QtMoc Include="mainwindow.h" />
|
||||
<QtMoc Include="qthost.h" />
|
||||
<QtMoc Include="foldersettingswidget.h" />
|
||||
<ClInclude Include="qtutils.h" />
|
||||
<QtMoc Include="settingsdialog.h" />
|
||||
</ItemGroup>
|
||||
|
@ -187,6 +190,12 @@
|
|||
<QtUi Include="gamelistwidget.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
<QtUi Include="gamesummarywidget.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
<QtUi Include="foldersettingswidget.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtResource Include="resources\resources.qrc">
|
||||
|
@ -211,12 +220,14 @@
|
|||
<ClCompile Include="$(IntDir)moc_displaywidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_emulationsettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_enhancementsettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_foldersettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_gamelistmodel.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_gamelistrefreshthread.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_gamelistsearchdirectoriesmodel.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_gamelistsettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_gamelistwidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_gamepropertiesdialog.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_gamesummarywidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_gdbconnection.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_gdbserver.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_generalsettingswidget.cpp" />
|
||||
|
@ -310,9 +321,10 @@
|
|||
<ItemDefinitionGroup>
|
||||
<Link>
|
||||
<AdditionalDependencies>$(RootBuildDir)frontend-common\frontend-common.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>$(QtEntryPointLib);%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<ClCompile>
|
||||
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">4127;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<DisableSpecificWarnings>4127;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="..\..\dep\msvc\vsprops\Targets.props" />
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="mainwindow.cpp" />
|
||||
<ClCompile Include="gamelistwidget.cpp" />
|
||||
<ClCompile Include="settingsdialog.cpp" />
|
||||
|
@ -21,7 +20,6 @@
|
|||
<ClCompile Include="$(IntDir)moc_inputbindingwidgets.cpp" />
|
||||
<ClCompile Include="audiosettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_audiosettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_qtdisplaywidget.cpp" />
|
||||
<ClCompile Include="displaywidget.cpp" />
|
||||
<ClCompile Include="qtprogresscallback.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_qtprogresscallback.cpp" />
|
||||
|
@ -89,6 +87,11 @@
|
|||
<ClCompile Include="$(IntDir)moc_controllersettingsdialog.cpp" />
|
||||
<ClCompile Include="gamelistrefreshthread.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_gamelistrefreshthread.cpp" />
|
||||
<ClCompile Include="foldersettingswidget.cpp" />
|
||||
<ClCompile Include="gamesummarywidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_displaywidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_foldersettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_gamesummarywidget.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="qtutils.h" />
|
||||
|
@ -147,6 +150,8 @@
|
|||
<QtMoc Include="controllerglobalsettingswidget.h" />
|
||||
<QtMoc Include="controllersettingsdialog.h" />
|
||||
<QtMoc Include="gamelistrefreshthread.h" />
|
||||
<QtMoc Include="gamesummarywidget.h" />
|
||||
<QtMoc Include="foldersettingswidget.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtUi Include="consolesettingswidget.ui" />
|
||||
|
@ -179,6 +184,8 @@
|
|||
<QtUi Include="controllerbindingwidget_digital_controller.ui" />
|
||||
<QtUi Include="emptygamelistwidget.ui" />
|
||||
<QtUi Include="gamelistwidget.ui" />
|
||||
<QtUi Include="gamesummarywidget.ui" />
|
||||
<QtUi Include="foldersettingswidget.ui" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="qt5.natvis" />
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "emulationsettingswidget.h"
|
||||
#include "common/make_array.h"
|
||||
#include "core/system.h"
|
||||
#include "qtutils.h"
|
||||
#include "settingsdialog.h"
|
||||
|
@ -14,30 +15,52 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsDialog* dialog, QWidget
|
|||
m_ui.setupUi(this);
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.rewindEnable, "Main", "RewindEnable", false);
|
||||
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.rewindSaveFrequency, "Main", "RewindFrequency",
|
||||
10.0f);
|
||||
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.rewindSaveFrequency, "Main", "RewindFrequency", 10.0f);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.rewindSaveSlots, "Main", "RewindSaveSlots", 10);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.runaheadFrames, "Main", "RunaheadFrameCount", 0);
|
||||
|
||||
QtUtils::FillComboBoxWithEmulationSpeeds(m_ui.emulationSpeed);
|
||||
const int emulation_speed_index =
|
||||
m_ui.emulationSpeed->findData(QVariant(m_dialog->getEffectiveFloatValue("Main", "EmulationSpeed", 1.0f)));
|
||||
if (emulation_speed_index >= 0)
|
||||
m_ui.emulationSpeed->setCurrentIndex(emulation_speed_index);
|
||||
const float effective_emulation_speed = m_dialog->getEffectiveFloatValue("Main", "EmulationSpeed", 1.0f);
|
||||
fillComboBoxWithEmulationSpeeds(m_ui.emulationSpeed, effective_emulation_speed);
|
||||
if (m_dialog->isPerGameSettings() && !m_dialog->getFloatValue("Main", "EmulationSpeed", std::nullopt).has_value())
|
||||
{
|
||||
m_ui.emulationSpeed->setCurrentIndex(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
const int emulation_speed_index = m_ui.emulationSpeed->findData(QVariant(effective_emulation_speed));
|
||||
if (emulation_speed_index >= 0)
|
||||
m_ui.emulationSpeed->setCurrentIndex(emulation_speed_index);
|
||||
}
|
||||
connect(m_ui.emulationSpeed, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
&EmulationSettingsWidget::onEmulationSpeedIndexChanged);
|
||||
QtUtils::FillComboBoxWithEmulationSpeeds(m_ui.fastForwardSpeed);
|
||||
const int fast_forward_speed_index =
|
||||
m_ui.fastForwardSpeed->findData(QVariant(m_dialog->getEffectiveFloatValue("Main", "FastForwardSpeed", 0.0f)));
|
||||
if (fast_forward_speed_index >= 0)
|
||||
m_ui.fastForwardSpeed->setCurrentIndex(fast_forward_speed_index);
|
||||
|
||||
const float effective_fast_forward_speed = m_dialog->getEffectiveFloatValue("Main", "FastForwardSpeed", 0.0f);
|
||||
fillComboBoxWithEmulationSpeeds(m_ui.fastForwardSpeed, effective_fast_forward_speed);
|
||||
if (m_dialog->isPerGameSettings() && !m_dialog->getFloatValue("Main", "FastForwardSpeed", std::nullopt).has_value())
|
||||
{
|
||||
m_ui.emulationSpeed->setCurrentIndex(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
const int fast_forward_speed_index = m_ui.fastForwardSpeed->findData(QVariant(effective_fast_forward_speed));
|
||||
if (fast_forward_speed_index >= 0)
|
||||
m_ui.fastForwardSpeed->setCurrentIndex(fast_forward_speed_index);
|
||||
}
|
||||
connect(m_ui.fastForwardSpeed, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
&EmulationSettingsWidget::onFastForwardSpeedIndexChanged);
|
||||
QtUtils::FillComboBoxWithEmulationSpeeds(m_ui.turboSpeed);
|
||||
const int turbo_speed_index =
|
||||
m_ui.turboSpeed->findData(QVariant(m_dialog->getEffectiveFloatValue("Main", "TurboSpeed", 0.0f)));
|
||||
if (turbo_speed_index >= 0)
|
||||
m_ui.turboSpeed->setCurrentIndex(turbo_speed_index);
|
||||
|
||||
const float effective_turbo_speed = m_dialog->getEffectiveFloatValue("Main", "TurboSpeed", 0.0f);
|
||||
fillComboBoxWithEmulationSpeeds(m_ui.turboSpeed, effective_turbo_speed);
|
||||
if (m_dialog->isPerGameSettings() && !m_dialog->getFloatValue("Main", "TurboSpeed", std::nullopt).has_value())
|
||||
{
|
||||
m_ui.emulationSpeed->setCurrentIndex(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
const int turbo_speed_index = m_ui.turboSpeed->findData(QVariant(effective_turbo_speed));
|
||||
if (turbo_speed_index >= 0)
|
||||
m_ui.turboSpeed->setCurrentIndex(turbo_speed_index);
|
||||
}
|
||||
connect(m_ui.turboSpeed, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
&EmulationSettingsWidget::onTurboSpeedIndexChanged);
|
||||
|
||||
|
@ -77,8 +100,35 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsDialog* dialog, QWidget
|
|||
|
||||
EmulationSettingsWidget::~EmulationSettingsWidget() = default;
|
||||
|
||||
void EmulationSettingsWidget::fillComboBoxWithEmulationSpeeds(QComboBox* cb, float global_value)
|
||||
{
|
||||
if (m_dialog->isPerGameSettings())
|
||||
{
|
||||
if (global_value == 0.0f)
|
||||
cb->addItem(tr("Use Global Setting [Unlimited]"));
|
||||
else
|
||||
cb->addItem(tr("Use Global Setting [%1%]").arg(static_cast<u32>(global_value * 100.0f)));
|
||||
}
|
||||
|
||||
cb->addItem(tr("Unlimited"), QVariant(0.0f));
|
||||
|
||||
static constexpr auto speeds = make_array(10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 125, 150, 175, 200, 250, 300, 350,
|
||||
400, 450, 500, 600, 700, 800, 900, 1000);
|
||||
for (const int speed : speeds)
|
||||
{
|
||||
cb->addItem(tr("%1% [%2 FPS (NTSC) / %3 FPS (PAL)]").arg(speed).arg((60 * speed) / 100).arg((50 * speed) / 100),
|
||||
QVariant(static_cast<float>(speed) / 100.0f));
|
||||
}
|
||||
}
|
||||
|
||||
void EmulationSettingsWidget::onEmulationSpeedIndexChanged(int index)
|
||||
{
|
||||
if (m_dialog->isPerGameSettings() && index == 0)
|
||||
{
|
||||
m_dialog->removeSettingValue("Main", "EmulationSpeed");
|
||||
return;
|
||||
}
|
||||
|
||||
bool okay;
|
||||
const float value = m_ui.emulationSpeed->currentData().toFloat(&okay);
|
||||
m_dialog->setFloatSettingValue("Main", "EmulationSpeed", okay ? value : 1.0f);
|
||||
|
@ -86,6 +136,12 @@ void EmulationSettingsWidget::onEmulationSpeedIndexChanged(int index)
|
|||
|
||||
void EmulationSettingsWidget::onFastForwardSpeedIndexChanged(int index)
|
||||
{
|
||||
if (m_dialog->isPerGameSettings() && index == 0)
|
||||
{
|
||||
m_dialog->removeSettingValue("Main", "FastForwardSpeed");
|
||||
return;
|
||||
}
|
||||
|
||||
bool okay;
|
||||
const float value = m_ui.fastForwardSpeed->currentData().toFloat(&okay);
|
||||
m_dialog->setFloatSettingValue("Main", "FastForwardSpeed", okay ? value : 0.0f);
|
||||
|
@ -93,6 +149,12 @@ void EmulationSettingsWidget::onFastForwardSpeedIndexChanged(int index)
|
|||
|
||||
void EmulationSettingsWidget::onTurboSpeedIndexChanged(int index)
|
||||
{
|
||||
if (m_dialog->isPerGameSettings() && index == 0)
|
||||
{
|
||||
m_dialog->removeSettingValue("Main", "TurboSpeed");
|
||||
return;
|
||||
}
|
||||
|
||||
bool okay;
|
||||
const float value = m_ui.turboSpeed->currentData().toFloat(&okay);
|
||||
m_dialog->setFloatSettingValue("Main", "TurboSpeed", okay ? value : 0.0f);
|
||||
|
@ -100,9 +162,11 @@ void EmulationSettingsWidget::onTurboSpeedIndexChanged(int index)
|
|||
|
||||
void EmulationSettingsWidget::updateRewind()
|
||||
{
|
||||
m_ui.rewindEnable->setEnabled(!runaheadEnabled());
|
||||
const bool rewind_enabled = m_dialog->getEffectiveBoolValue("Main", "RewindEnable", false);
|
||||
const bool runahead_enabled = m_dialog->getIntValue("Main", "RunaheadFrameCount", 0) > 0;
|
||||
m_ui.rewindEnable->setEnabled(!runahead_enabled);
|
||||
|
||||
if (m_ui.rewindEnable->isEnabled() && m_ui.rewindEnable->isChecked())
|
||||
if (!runahead_enabled && rewind_enabled)
|
||||
{
|
||||
const u32 frames = static_cast<u32>(m_ui.rewindSaveSlots->value());
|
||||
const float frequency = static_cast<float>(m_ui.rewindSaveFrequency->value());
|
||||
|
@ -122,7 +186,7 @@ void EmulationSettingsWidget::updateRewind()
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!m_ui.rewindEnable->isEnabled())
|
||||
if (runahead_enabled)
|
||||
{
|
||||
m_ui.rewindSummary->setText(tr(
|
||||
"Rewind is disabled because runahead is enabled. Runahead will significantly increase system requirements."));
|
||||
|
|
|
@ -21,7 +21,7 @@ private Q_SLOTS:
|
|||
void updateRewind();
|
||||
|
||||
private:
|
||||
bool runaheadEnabled() { return m_ui.runaheadFrames->currentIndex() > 0; }
|
||||
void fillComboBoxWithEmulationSpeeds(QComboBox* cb, float global_value);
|
||||
|
||||
Ui::EmulationSettingsWidget m_ui;
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
#include <QtWidgets/QMessageBox>
|
||||
#include <algorithm>
|
||||
|
||||
#include "foldersettingswidget.h"
|
||||
#include "settingsdialog.h"
|
||||
#include "settingwidgetbinder.h"
|
||||
|
||||
FolderSettingsWidget::FolderSettingsWidget(SettingsDialog* dialog, QWidget* parent) : QWidget(parent)
|
||||
{
|
||||
SettingsInterface* sif = dialog->getSettingsInterface();
|
||||
|
||||
m_ui.setupUi(this);
|
||||
|
||||
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.cache, m_ui.cacheBrowse, m_ui.cacheOpen, m_ui.cacheReset,
|
||||
"Folders", "Cache", "cache");
|
||||
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.covers, m_ui.coversBrowse, m_ui.coversOpen, m_ui.coversReset,
|
||||
"Folders", "Covers", "covers");
|
||||
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.screenshots, m_ui.screenshotsBrowse, m_ui.screenshotsOpen,
|
||||
m_ui.screenshotsReset, "Folders", "Screenshots", "screenshots");
|
||||
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.saveStates, m_ui.saveStatesBrowse, m_ui.saveStatesOpen,
|
||||
m_ui.saveStatesReset, "Folders", "SaveStates", "savestates");
|
||||
}
|
||||
|
||||
FolderSettingsWidget::~FolderSettingsWidget() = default;
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
#include "ui_foldersettingswidget.h"
|
||||
|
||||
class SettingsDialog;
|
||||
|
||||
class FolderSettingsWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FolderSettingsWidget(SettingsDialog* dialog, QWidget* parent);
|
||||
~FolderSettingsWidget();
|
||||
|
||||
private:
|
||||
Ui::FolderSettingsWidget m_ui;
|
||||
};
|
|
@ -0,0 +1,208 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FolderSettingsWidget</class>
|
||||
<widget class="QWidget" name="FolderSettingsWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>648</width>
|
||||
<height>487</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>Cache Directory</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLineEdit" name="cache"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="cacheBrowse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="cacheOpen">
|
||||
<property name="text">
|
||||
<string>Open...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="cacheReset">
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="4">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Used for storing shaders and game list data.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
<string>Covers Directory</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLineEdit" name="covers"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="coversBrowse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="coversOpen">
|
||||
<property name="text">
|
||||
<string>Open...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="coversReset">
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="4">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Used for storing covers in the game grid/Big Picture UIs.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Screenshots Directory</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLineEdit" name="screenshots"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="screenshotsBrowse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="screenshotsOpen">
|
||||
<property name="text">
|
||||
<string>Open...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="screenshotsReset">
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="4">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Used for screenshots.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Save States Directory</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLineEdit" name="saveStates"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="saveStatesBrowse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="saveStatesOpen">
|
||||
<property name="text">
|
||||
<string>Open...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="saveStatesReset">
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="4">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Used for storing save states.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>132</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../../p2-qt-rebase/pcsx2-qt/resources/resources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -3,6 +3,7 @@
|
|||
#include "common/path.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/system.h"
|
||||
#include "qtutils.h"
|
||||
#include <QtCore/QDate>
|
||||
#include <QtCore/QDateTime>
|
||||
#include <QtGui/QGuiApplication>
|
||||
|
@ -290,43 +291,18 @@ QVariant GameListModel::data(const QModelIndex& index, int role) const
|
|||
{
|
||||
case Column_Type:
|
||||
{
|
||||
switch (ge->type)
|
||||
{
|
||||
case GameList::EntryType::Disc:
|
||||
return (/*(ge.settings.GetUserSettingsCount() > 0)*/ false ? m_type_disc_with_settings_pixmap :
|
||||
m_type_disc_pixmap);
|
||||
case GameList::EntryType::Playlist:
|
||||
return m_type_playlist_pixmap;
|
||||
case GameList::EntryType::PSF:
|
||||
return m_type_psf_pixmap;
|
||||
case GameList::EntryType::PSExe:
|
||||
default:
|
||||
return m_type_exe_pixmap;
|
||||
}
|
||||
// TODO: Test for settings
|
||||
return m_type_pixmaps[static_cast<u32>(ge->type)];
|
||||
}
|
||||
|
||||
case Column_Region:
|
||||
{
|
||||
switch (ge->region)
|
||||
{
|
||||
case DiscRegion::NTSC_J:
|
||||
return m_region_jp_pixmap;
|
||||
case DiscRegion::NTSC_U:
|
||||
return m_region_us_pixmap;
|
||||
case DiscRegion::Other:
|
||||
return m_region_other_pixmap;
|
||||
case DiscRegion::PAL:
|
||||
default:
|
||||
return m_region_eu_pixmap;
|
||||
}
|
||||
return m_region_pixmaps[static_cast<u32>(ge->region)];
|
||||
}
|
||||
|
||||
case Column_Compatibility:
|
||||
{
|
||||
return m_compatibiliy_pixmaps[static_cast<int>(
|
||||
(ge->compatibility >= GameDatabase::CompatibilityRating::Count) ?
|
||||
GameDatabase::CompatibilityRating::Unknown :
|
||||
ge->compatibility)];
|
||||
return m_compatibiliy_pixmaps[static_cast<u32>(ge->compatibility)];
|
||||
}
|
||||
|
||||
case Column_Cover:
|
||||
|
@ -514,16 +490,11 @@ bool GameListModel::lessThan(const QModelIndex& left_index, const QModelIndex& r
|
|||
|
||||
void GameListModel::loadCommonImages()
|
||||
{
|
||||
// TODO: Use svg instead of png
|
||||
m_type_disc_pixmap = QIcon(QStringLiteral(":/icons/media-optical-24.png")).pixmap(QSize(24, 24));
|
||||
m_type_disc_with_settings_pixmap = QIcon(QStringLiteral(":/icons/media-optical-gear-24.png")).pixmap(QSize(24, 24));
|
||||
m_type_exe_pixmap = QIcon(QStringLiteral(":/icons/applications-system-24.png")).pixmap(QSize(24, 24));
|
||||
m_type_playlist_pixmap = QIcon(QStringLiteral(":/icons/address-book-new-22.png")).pixmap(QSize(22, 22));
|
||||
m_type_psf_pixmap = QIcon(QStringLiteral(":/icons/multimedia-player.png")).pixmap(QSize(22, 22));
|
||||
m_region_eu_pixmap = QIcon(QStringLiteral(":/icons/flag-eu.png")).pixmap(QSize(42, 30));
|
||||
m_region_jp_pixmap = QIcon(QStringLiteral(":/icons/flag-jp.png")).pixmap(QSize(42, 30));
|
||||
m_region_us_pixmap = QIcon(QStringLiteral(":/icons/flag-uc.png")).pixmap(QSize(42, 30));
|
||||
m_region_other_pixmap = QIcon(QStringLiteral(":/icons/flag-other.png")).pixmap(QSize(42, 30));
|
||||
for (u32 i = 0; i < static_cast<u32>(GameList::EntryType::Count); i++)
|
||||
m_type_pixmaps[i] = QtUtils::GetIconForEntryType(static_cast<GameList::EntryType>(i)).pixmap(QSize(24, 24));
|
||||
|
||||
for (u32 i = 0; i < static_cast<u32>(DiscRegion::Count); i++)
|
||||
m_region_pixmaps[i] = QtUtils::GetIconForRegion(static_cast<DiscRegion>(i)).pixmap(42, 30);
|
||||
|
||||
for (int i = 0; i < static_cast<int>(GameDatabase::CompatibilityRating::Count); i++)
|
||||
m_compatibiliy_pixmaps[i].load(QStringLiteral(":/icons/star-%1.png").arg(i));
|
||||
|
|
|
@ -71,17 +71,8 @@ private:
|
|||
|
||||
std::array<QString, Column_Count> m_column_display_names;
|
||||
|
||||
QPixmap m_type_disc_pixmap;
|
||||
QPixmap m_type_disc_with_settings_pixmap;
|
||||
QPixmap m_type_exe_pixmap;
|
||||
QPixmap m_type_playlist_pixmap;
|
||||
QPixmap m_type_psf_pixmap;
|
||||
|
||||
QPixmap m_region_jp_pixmap;
|
||||
QPixmap m_region_eu_pixmap;
|
||||
QPixmap m_region_us_pixmap;
|
||||
QPixmap m_region_other_pixmap;
|
||||
|
||||
std::array<QPixmap, static_cast<int>(GameList::EntryType::Count)> m_type_pixmaps;
|
||||
std::array<QPixmap, static_cast<int>(DiscRegion::Count)> m_region_pixmaps;
|
||||
std::array<QPixmap, static_cast<int>(GameDatabase::CompatibilityRating::Count)> m_compatibiliy_pixmaps;
|
||||
mutable UnorderedStringMap<QPixmap> m_cover_pixmap_cache;
|
||||
};
|
|
@ -4,7 +4,7 @@
|
|||
#include "qtutils.h"
|
||||
#include <QtCore/QUrl>
|
||||
|
||||
GameListSearchDirectoriesModel::GameListSearchDirectoriesModel(QtHostInterface* host_interface)
|
||||
GameListSearchDirectoriesModel::GameListSearchDirectoriesModel(EmuThread* host_interface)
|
||||
: m_host_interface(host_interface)
|
||||
{
|
||||
loadFromSettings();
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
#include <QtCore/QString>
|
||||
#include <vector>
|
||||
|
||||
class QtHostInterface;
|
||||
class EmuThread;
|
||||
|
||||
class GameListSearchDirectoriesModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GameListSearchDirectoriesModel(QtHostInterface* host_interface);
|
||||
GameListSearchDirectoriesModel(EmuThread* host_interface);
|
||||
~GameListSearchDirectoriesModel();
|
||||
|
||||
int columnCount(const QModelIndex& parent) const override;
|
||||
|
@ -36,6 +36,6 @@ private:
|
|||
bool recursive;
|
||||
};
|
||||
|
||||
QtHostInterface* m_host_interface;
|
||||
EmuThread* m_host_interface;
|
||||
std::vector<Entry> m_entries;
|
||||
};
|
||||
|
|
|
@ -89,8 +89,17 @@ void GameListWidget::initialize()
|
|||
m_sort_model->setSourceModel(m_model);
|
||||
|
||||
m_ui.setupUi(this);
|
||||
for (u32 type = 0; type < static_cast<u32>(GameList::EntryType::Count); type++)
|
||||
{
|
||||
m_ui.filterType->addItem(
|
||||
QtUtils::GetIconForEntryType(static_cast<GameList::EntryType>(type)),
|
||||
qApp->translate("GameList", GameList::GetEntryTypeDisplayName(static_cast<GameList::EntryType>(type))));
|
||||
}
|
||||
for (u32 region = 0; region < static_cast<u32>(DiscRegion::Count); region++)
|
||||
m_ui.filterRegion->addItem(QString::fromUtf8(Settings::GetDiscRegionDisplayName(static_cast<DiscRegion>(region))));
|
||||
{
|
||||
m_ui.filterRegion->addItem(QtUtils::GetIconForRegion(static_cast<DiscRegion>(region)),
|
||||
QString::fromUtf8(Settings::GetDiscRegionName(static_cast<DiscRegion>(region))));
|
||||
}
|
||||
|
||||
connect(m_ui.viewGameList, &QPushButton::clicked, this, &GameListWidget::showGameList);
|
||||
connect(m_ui.viewGameGrid, &QPushButton::clicked, this, &GameListWidget::showGameGrid);
|
||||
|
@ -107,7 +116,7 @@ void GameListWidget::initialize()
|
|||
[this](const QString& text) { m_sort_model->setFilterName(text); });
|
||||
|
||||
// Works around a strange bug where after hiding the game list, the cursor for the whole window changes to a beam..
|
||||
//m_ui.searchText->setCursor(QCursor(Qt::ArrowCursor));
|
||||
// m_ui.searchText->setCursor(QCursor(Qt::ArrowCursor));
|
||||
|
||||
m_table_view = new QTableView(m_ui.stack);
|
||||
m_table_view->setModel(m_sort_model);
|
||||
|
@ -347,7 +356,10 @@ void GameListWidget::refreshGridCovers()
|
|||
void GameListWidget::showGameList()
|
||||
{
|
||||
if (m_ui.stack->currentIndex() == 0 || m_model->rowCount() == 0)
|
||||
{
|
||||
updateToolbar();
|
||||
return;
|
||||
}
|
||||
|
||||
Host::SetBaseBoolSettingValue("UI", "GameListGridView", false);
|
||||
m_ui.stack->setCurrentIndex(0);
|
||||
|
@ -359,7 +371,10 @@ void GameListWidget::showGameList()
|
|||
void GameListWidget::showGameGrid()
|
||||
{
|
||||
if (m_ui.stack->currentIndex() == 1 || m_model->rowCount() == 0)
|
||||
{
|
||||
updateToolbar();
|
||||
return;
|
||||
}
|
||||
|
||||
Host::SetBaseBoolSettingValue("UI", "GameListGridView", true);
|
||||
m_ui.stack->setCurrentIndex(1);
|
||||
|
@ -370,7 +385,10 @@ void GameListWidget::showGameGrid()
|
|||
void GameListWidget::setShowCoverTitles(bool enabled)
|
||||
{
|
||||
if (m_model->getShowCoverTitles() == enabled)
|
||||
{
|
||||
updateToolbar();
|
||||
return;
|
||||
}
|
||||
|
||||
Host::SetBaseBoolSettingValue("UI", "GameListShowCoverTitles", enabled);
|
||||
m_model->setShowCoverTitles(enabled);
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
<string>Game List</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="list-check">
|
||||
<iconset theme="GameList">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
|
@ -83,7 +83,7 @@
|
|||
<string>Game Grid</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="function-line">
|
||||
<iconset theme="GameGrid">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
|
@ -106,7 +106,7 @@
|
|||
<string>Show Titles</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="window-2-line">
|
||||
<iconset theme="RescanAllGames">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
|
@ -162,25 +162,10 @@
|
|||
<property name="text">
|
||||
<string>All Types</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>PS2 Discs</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>PS1 Discs</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>PS2 ELFs</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Playlists</string>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normalon>:/icons/system-file-manager.png</normalon>
|
||||
</iconset>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
|
@ -191,6 +176,9 @@
|
|||
<property name="text">
|
||||
<string>All Regions</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="Language"/>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
#include "common/string_util.h"
|
||||
|
||||
#include "frontend-common/game_list.h"
|
||||
|
||||
#include "gamesummarywidget.h"
|
||||
#include "qthost.h"
|
||||
#include "settingsdialog.h"
|
||||
|
||||
GameSummaryWidget::GameSummaryWidget(const std::string& path, const std::string& serial, DiscRegion region,
|
||||
const GameDatabase::Entry* entry, SettingsDialog* dialog, QWidget* parent)
|
||||
: m_dialog(dialog)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
#if 0
|
||||
const QString base_path(QtHost::GetResourcesBasePath());
|
||||
for (int i = 0; i < m_ui.region->count(); i++)
|
||||
{
|
||||
m_ui.region->setItemIcon(i, QIcon(
|
||||
QStringLiteral("%1/icons/flags/%2.png").arg(base_path).arg(GameList::RegionToString(static_cast<GameList::Region>(i)))));
|
||||
}
|
||||
for (int i = 1; i < m_ui.compatibility->count(); i++)
|
||||
{
|
||||
m_ui.compatibility->setItemIcon(i, QIcon(
|
||||
QStringLiteral("%1/icons/star-%2.png").arg(base_path).arg(i)));
|
||||
}
|
||||
#endif
|
||||
|
||||
populateUi(path, serial, region, entry);
|
||||
|
||||
// connect(m_ui.inputProfile, &QComboBox::currentIndexChanged, this, &GameSummaryWidget::onInputProfileChanged);
|
||||
}
|
||||
|
||||
GameSummaryWidget::~GameSummaryWidget() = default;
|
||||
|
||||
void GameSummaryWidget::populateUi(const std::string& path, const std::string& serial, DiscRegion region,
|
||||
const GameDatabase::Entry* entry)
|
||||
{
|
||||
m_ui.path->setText(QString::fromStdString(path));
|
||||
m_ui.serial->setText(QString::fromStdString(serial));
|
||||
m_ui.region->setCurrentIndex(static_cast<int>(region));
|
||||
|
||||
if (entry)
|
||||
{
|
||||
m_ui.title->setText(QString::fromStdString(entry->title));
|
||||
m_ui.compatibility->setCurrentIndex(static_cast<int>(entry->compatibility));
|
||||
}
|
||||
|
||||
#if 0
|
||||
for (const std::string& name : PAD::GetInputProfileNames())
|
||||
m_ui.inputProfile->addItem(QString::fromStdString(name));
|
||||
|
||||
std::optional<std::string> profile(m_dialog->getStringValue("EmuCore", "InputProfileName", std::nullopt));
|
||||
if (profile.has_value())
|
||||
m_ui.inputProfile->setCurrentIndex(m_ui.inputProfile->findText(QString::fromStdString(profile.value())));
|
||||
else
|
||||
m_ui.inputProfile->setCurrentIndex(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GameSummaryWidget::onInputProfileChanged(int index)
|
||||
{
|
||||
#if 0
|
||||
if (index == 0)
|
||||
m_dialog->setStringSettingValue("EmuCore", "InputProfileName", std::nullopt);
|
||||
else
|
||||
m_dialog->setStringSettingValue("EmuCore", "InputProfileName", m_ui.inputProfile->itemText(index).toUtf8());
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
#include "common/types.h"
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
#include "ui_gamesummarywidget.h"
|
||||
|
||||
enum class DiscRegion : u8;
|
||||
|
||||
namespace GameDatabase {
|
||||
struct Entry;
|
||||
}
|
||||
|
||||
class SettingsDialog;
|
||||
|
||||
class GameSummaryWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GameSummaryWidget(const std::string& path, const std::string& serial, DiscRegion region,
|
||||
const GameDatabase::Entry* entry, SettingsDialog* dialog, QWidget* parent);
|
||||
~GameSummaryWidget();
|
||||
|
||||
private:
|
||||
void populateUi(const std::string& path, const std::string& serial, DiscRegion region,
|
||||
const GameDatabase::Entry* entry);
|
||||
|
||||
void onInputProfileChanged(int index);
|
||||
|
||||
Ui::GameSummaryWidget m_ui;
|
||||
SettingsDialog* m_dialog;
|
||||
};
|
|
@ -0,0 +1,204 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>GameSummaryWidget</class>
|
||||
<widget class="QWidget" name="GameSummaryWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>692</width>
|
||||
<height>562</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset>
|
||||
<normaloff>:/icons/duck.png</normaloff>:/icons/duck.png</iconset>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="8" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Tracks:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Comments:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="revision">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="title">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0" colspan="2">
|
||||
<widget class="QTableWidget" name="tracks">
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="cornerButtonEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>#</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Mode</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Start</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Length</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Hash</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Status</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QLineEdit" name="upscalingIssues"/>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="region">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Region:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Image Path:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Compatibility:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Title:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_36">
|
||||
<property name="text">
|
||||
<string>Revision:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Upscaling Issues:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="compatibility"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="versionTested"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="editCompatibility">
|
||||
<property name="text">
|
||||
<string>Edit...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Game Serial:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="path">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="serial">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QLineEdit" name="comments"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -13,7 +13,7 @@ GDBConnection::GDBConnection(QObject* parent, int descriptor) : QThread(parent),
|
|||
|
||||
if (m_socket.setSocketDescriptor(m_descriptor))
|
||||
{
|
||||
g_emu_thread->pauseSystem(true, true);
|
||||
g_emu_thread->setSystemPaused(true, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -42,13 +42,13 @@ void GDBConnection::receivedData()
|
|||
if (GDBProtocol::IsPacketInterrupt(m_readBuffer))
|
||||
{
|
||||
Log_DebugPrintf("(%u) > Interrupt request", m_descriptor);
|
||||
g_emu_thread->pauseSystem(true, true);
|
||||
g_emu_thread->setSystemPaused(true, true);
|
||||
m_readBuffer.erase();
|
||||
}
|
||||
else if (GDBProtocol::IsPacketContinue(m_readBuffer))
|
||||
{
|
||||
Log_DebugPrintf("(%u) > Continue request", m_descriptor);
|
||||
g_emu_thread->pauseSystem(false, false);
|
||||
g_emu_thread->setSystemPaused(false, false);
|
||||
m_readBuffer.erase();
|
||||
}
|
||||
else if (GDBProtocol::IsPacketComplete(m_readBuffer))
|
||||
|
|
|
@ -29,8 +29,8 @@ void GDBServer::incomingConnection(qintptr descriptor)
|
|||
{
|
||||
Log_InfoPrint("Accepted connection on GDB server");
|
||||
GDBConnection *thread = new GDBConnection(this, descriptor);
|
||||
connect(g_emu_thread, &QtHostInterface::systemPaused, thread, &GDBConnection::onEmulationPaused);
|
||||
connect(g_emu_thread, &QtHostInterface::systemResumed, thread, &GDBConnection::onEmulationResumed);
|
||||
connect(g_emu_thread, &EmuThread::systemPaused, thread, &GDBConnection::onEmulationPaused);
|
||||
connect(g_emu_thread, &EmuThread::systemResumed, thread, &GDBConnection::onEmulationResumed);
|
||||
thread->start();
|
||||
m_connections.push_back(thread);
|
||||
}
|
||||
|
|
|
@ -13,20 +13,30 @@ GeneralSettingsWidget::GeneralSettingsWidget(SettingsDialog* dialog, QWidget* pa
|
|||
|
||||
m_ui.setupUi(this);
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pauseOnStart, "Main", "StartPaused", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pauseOnFocusLoss, "Main", "PauseOnFocusLoss", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.startFullscreen, "Main", "StartFullscreen", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.hideCursorInFullscreen, "Main", "HideCursorInFullscreen",
|
||||
true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.inhibitScreensaver, "Main", "InhibitScreensaver", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.renderToMain, "Main", "RenderToMainWindow", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pauseOnFocusLoss, "Main", "PauseOnFocusLoss", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pauseOnStart, "Main", "StartPaused", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.saveStateOnExit, "Main", "SaveStateOnExit", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.confirmPowerOff, "Main", "ConfirmPowerOff", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.loadDevicesFromSaveStates, "Main", "LoadDevicesFromSaveStates",
|
||||
false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.applyGameSettings, "Main", "ApplyGameSettings", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.autoLoadCheats, "Main", "AutoLoadCheats", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableFullscreenUI, "Main", "EnableFullscreenUI", false);
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.startFullscreen, "Main", "StartFullscreen", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.doubleClickTogglesFullscreen, "Main",
|
||||
"DoubleClickTogglesFullscreen", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.renderToSeparateWindow, "Main", "RenderToSeparateWindow",
|
||||
false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.hideMainWindow, "Main", "HideMainWindowWhenRunning", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableWindowResizing, "Main", "DisableWindowResize", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.hideMouseCursor, "Main", "HideCursorInFullscreen", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.createSaveStateBackups, "Main", "CreateSaveStateBackups",
|
||||
false);
|
||||
connect(m_ui.renderToSeparateWindow, &QCheckBox::stateChanged, this,
|
||||
&GeneralSettingsWidget::onRenderToSeparateWindowChanged);
|
||||
|
||||
onRenderToSeparateWindowChanged();
|
||||
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.confirmPowerOff, tr("Confirm Power Off"), tr("Checked"),
|
||||
|
@ -37,15 +47,15 @@ GeneralSettingsWidget::GeneralSettingsWidget(SettingsDialog* dialog, QWidget* pa
|
|||
"resume directly from where you left off next time."));
|
||||
dialog->registerWidgetHelp(m_ui.startFullscreen, tr("Start Fullscreen"), tr("Unchecked"),
|
||||
tr("Automatically switches to fullscreen mode when a game is started."));
|
||||
dialog->registerWidgetHelp(m_ui.hideCursorInFullscreen, tr("Hide Cursor In Fullscreen"), tr("Checked"),
|
||||
dialog->registerWidgetHelp(m_ui.hideMouseCursor, tr("Hide Cursor In Fullscreen"), tr("Checked"),
|
||||
tr("Hides the mouse pointer/cursor when the emulator is in fullscreen mode."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.inhibitScreensaver, tr("Inhibit Screensaver"), tr("Checked"),
|
||||
tr("Prevents the screen saver from activating and the host from sleeping while emulation is running."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.renderToMain, tr("Render To Main Window"), tr("Checked"),
|
||||
m_ui.renderToSeparateWindow, tr("Render To Separate Window"), tr("Checked"),
|
||||
tr("Renders the display of the simulated console to the main window of the application, over "
|
||||
"the game list. If unchecked, the display will render in a separate window."));
|
||||
"the game list. If checked, the display will render in a separate window."));
|
||||
dialog->registerWidgetHelp(m_ui.pauseOnStart, tr("Pause On Start"), tr("Unchecked"),
|
||||
tr("Pauses the emulator when a game is started."));
|
||||
dialog->registerWidgetHelp(m_ui.pauseOnFocusLoss, tr("Pause On Focus Loss"), tr("Unchecked"),
|
||||
|
@ -62,23 +72,17 @@ GeneralSettingsWidget::GeneralSettingsWidget(SettingsDialog* dialog, QWidget* pa
|
|||
"leave this option enabled except when testing enhancements with incompatible games."));
|
||||
dialog->registerWidgetHelp(m_ui.autoLoadCheats, tr("Automatically Load Cheats"), tr("Unchecked"),
|
||||
tr("Automatically loads and applies cheats on game start."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.enableFullscreenUI, tr("Enable Fullscreen UI"), tr("Unchecked"),
|
||||
tr("Enables the fullscreen UI mode, suitable for controller operation which is used in the NoGUI frontend."));
|
||||
|
||||
// Since this one is compile-time selected, we don't put it in the .ui file.
|
||||
int current_col = 0;
|
||||
int current_row = m_ui.formLayout_4->rowCount() - current_col;
|
||||
#ifdef WITH_DISCORD_PRESENCE
|
||||
{
|
||||
QCheckBox* enableDiscordPresence = new QCheckBox(tr("Enable Discord Presence"), m_ui.groupBox_4);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, enableDiscordPresence, "Main", "EnableDiscordPresence", false);
|
||||
m_ui.formLayout_4->addWidget(enableDiscordPresence, current_row, current_col);
|
||||
dialog->registerWidgetHelp(enableDiscordPresence, tr("Enable Discord Presence"), tr("Unchecked"),
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableDiscordPresence, "Main", "EnableDiscordPresence",
|
||||
false);
|
||||
dialog->registerWidgetHelp(m_ui.enableDiscordPresence, tr("Enable Discord Presence"), tr("Unchecked"),
|
||||
tr("Shows the game you are currently playing as part of your profile in Discord."));
|
||||
current_col++;
|
||||
current_row += (current_col / 2);
|
||||
current_col %= 2;
|
||||
}
|
||||
#else
|
||||
{
|
||||
m_ui.enableDiscordPresence->setEnabled(false);
|
||||
}
|
||||
#endif
|
||||
if (AutoUpdaterDialog::isSupported())
|
||||
|
@ -94,9 +98,6 @@ GeneralSettingsWidget::GeneralSettingsWidget(SettingsDialog* dialog, QWidget* pa
|
|||
|
||||
m_ui.autoUpdateCurrentVersion->setText(tr("%1 (%2)").arg(g_scm_tag_str).arg(g_scm_date_str));
|
||||
connect(m_ui.checkForUpdates, &QPushButton::clicked, [this]() { g_main_window->checkForUpdates(true); });
|
||||
current_col++;
|
||||
current_row += (current_col / 2);
|
||||
current_col %= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -106,3 +107,8 @@ GeneralSettingsWidget::GeneralSettingsWidget(SettingsDialog* dialog, QWidget* pa
|
|||
}
|
||||
|
||||
GeneralSettingsWidget::~GeneralSettingsWidget() = default;
|
||||
|
||||
void GeneralSettingsWidget::onRenderToSeparateWindowChanged()
|
||||
{
|
||||
m_ui.hideMainWindow->setEnabled(m_ui.renderToSeparateWindow->isChecked());
|
||||
}
|
||||
|
|
|
@ -14,6 +14,9 @@ public:
|
|||
explicit GeneralSettingsWidget(SettingsDialog* dialog, QWidget* parent);
|
||||
~GeneralSettingsWidget();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onRenderToSeparateWindowChanged();
|
||||
|
||||
private:
|
||||
Ui::GeneralSettingsWidget m_ui;
|
||||
|
||||
|
|
|
@ -32,52 +32,17 @@
|
|||
<string>Behaviour</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="formLayout_4">
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="confirmPowerOff">
|
||||
<item row="6" column="1">
|
||||
<widget class="QCheckBox" name="autoLoadCheats">
|
||||
<property name="text">
|
||||
<string>Confirm Power Off</string>
|
||||
<string>Automatically Load Cheats</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="inhibitScreensaver">
|
||||
<property name="text">
|
||||
<string>Inhibit Screensaver</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="renderToMain">
|
||||
<property name="text">
|
||||
<string>Render To Main Window</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="pauseOnStart">
|
||||
<property name="text">
|
||||
<string>Pause On Start</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="pauseOnFocusLoss">
|
||||
<property name="text">
|
||||
<string>Pause On Focus Loss</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="startFullscreen">
|
||||
<property name="text">
|
||||
<string>Start Fullscreen</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="saveStateOnExit">
|
||||
<property name="text">
|
||||
<string>Save State On Exit</string>
|
||||
<string>Save State On Shutdown</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -88,10 +53,10 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QCheckBox" name="autoLoadCheats">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="inhibitScreensaver">
|
||||
<property name="text">
|
||||
<string>Automatically Load Cheats</string>
|
||||
<string>Inhibit Screensaver</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -102,17 +67,38 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="hideCursorInFullscreen">
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="confirmPowerOff">
|
||||
<property name="text">
|
||||
<string>Hide Cursor In Fullscreen</string>
|
||||
<string>Confirm Power Off</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="pauseOnFocusLoss">
|
||||
<property name="text">
|
||||
<string>Pause On Focus Loss</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="enableFullscreenUI">
|
||||
<widget class="QCheckBox" name="pauseOnStart">
|
||||
<property name="text">
|
||||
<string>Enable Fullscreen UI</string>
|
||||
<string>Pause On Start</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QCheckBox" name="createSaveStateBackups">
|
||||
<property name="text">
|
||||
<string>Create Save State Backups</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QCheckBox" name="enableDiscordPresence">
|
||||
<property name="text">
|
||||
<string>Enable Discord Presence</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -120,24 +106,52 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Miscellaneous</string>
|
||||
<string>Game Display</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Controller Backend:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="controllerBackend"/>
|
||||
</item>
|
||||
</layout>
|
||||
<widget class="QCheckBox" name="startFullscreen">
|
||||
<property name="text">
|
||||
<string>Start Fullscreen</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="doubleClickTogglesFullscreen">
|
||||
<property name="text">
|
||||
<string>Double-Click Toggles Fullscreen</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="renderToSeparateWindow">
|
||||
<property name="text">
|
||||
<string>Render To Separate Window</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="hideMainWindow">
|
||||
<property name="text">
|
||||
<string>Hide Main Window When Running</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="disableWindowResizing">
|
||||
<property name="text">
|
||||
<string>Disable Window Resizing</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="hideMouseCursor">
|
||||
<property name="text">
|
||||
<string>Hide Cursor In Fullscreen</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
|
|
@ -1,152 +0,0 @@
|
|||
#include "common/crash_handler.h"
|
||||
#include "mainwindow.h"
|
||||
#include "qthost.h"
|
||||
#include "qtutils.h"
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <csignal>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
|
||||
static bool ParseCommandLineParameters(QApplication& app, QtHostInterface* host_interface,
|
||||
std::unique_ptr<SystemBootParameters>* boot_params)
|
||||
{
|
||||
const QStringList args(app.arguments());
|
||||
std::vector<std::string> converted_args;
|
||||
std::vector<char*> converted_argv;
|
||||
converted_args.reserve(args.size());
|
||||
converted_argv.reserve(args.size());
|
||||
|
||||
for (const QString& arg : args)
|
||||
converted_args.push_back(arg.toStdString());
|
||||
|
||||
for (std::string& arg : converted_args)
|
||||
converted_argv.push_back(arg.data());
|
||||
|
||||
return CommonHost::ParseCommandLineParameters(args.size(), converted_argv.data(), boot_params);
|
||||
}
|
||||
|
||||
static void SignalHandler(int signal)
|
||||
{
|
||||
// First try the normal (graceful) shutdown/exit.
|
||||
static bool graceful_shutdown_attempted = false;
|
||||
if (!graceful_shutdown_attempted)
|
||||
{
|
||||
std::fprintf(stderr, "Received CTRL+C, attempting graceful shutdown. Press CTRL+C again to force.\n");
|
||||
graceful_shutdown_attempted = true;
|
||||
g_emu_thread->requestExit();
|
||||
return;
|
||||
}
|
||||
|
||||
std::signal(signal, SIG_DFL);
|
||||
|
||||
// MacOS is missing std::quick_exit() despite it being C++11...
|
||||
#ifndef __APPLE__
|
||||
std::quick_exit(1);
|
||||
#else
|
||||
_Exit(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void HookSignals()
|
||||
{
|
||||
std::signal(SIGINT, SignalHandler);
|
||||
std::signal(SIGTERM, SignalHandler);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
CrashHandler::Install();
|
||||
|
||||
// Register any standard types we need elsewhere
|
||||
qRegisterMetaType<std::optional<bool>>();
|
||||
qRegisterMetaType<std::function<void()>>();
|
||||
|
||||
|
||||
QApplication app(argc, argv);
|
||||
|
||||
// TODO: Remove me
|
||||
Log::SetFilterLevel(LOGLEVEL_DEBUG);
|
||||
Log::SetConsoleOutputParams(true, nullptr, LOGLEVEL_DEBUG);
|
||||
|
||||
std::unique_ptr<QtHostInterface> host_interface = std::make_unique<QtHostInterface>();
|
||||
std::unique_ptr<SystemBootParameters> boot_params;
|
||||
if (!ParseCommandLineParameters(app, host_interface.get(), &boot_params))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
MainWindow* window = new MainWindow();
|
||||
|
||||
if (!host_interface->Initialize())
|
||||
{
|
||||
host_interface->Shutdown();
|
||||
QMessageBox::critical(nullptr, QObject::tr("DuckStation Error"),
|
||||
QObject::tr("Failed to initialize host interface. Cannot continue."), QMessageBox::Ok);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
window->initializeAndShow();
|
||||
HookSignals();
|
||||
|
||||
// When running in batch mode, ensure game list is loaded, but don't scan for any new files.
|
||||
if (!QtHost::InBatchMode())
|
||||
window->refreshGameList(false);
|
||||
else
|
||||
GameList::Refresh(false, true);
|
||||
|
||||
if (boot_params)
|
||||
{
|
||||
host_interface->bootSystem(std::move(boot_params));
|
||||
}
|
||||
else
|
||||
{
|
||||
window->startupUpdateCheck();
|
||||
}
|
||||
|
||||
int result = app.exec();
|
||||
|
||||
host_interface->Shutdown();
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
// Apparently Qt6 got rid of this?
|
||||
#include "common/windows_headers.h"
|
||||
#include <shellapi.h>
|
||||
|
||||
/*
|
||||
WinMain() - Initializes Windows and calls user's startup function main().
|
||||
NOTE: WinMain() won't be called if the application was linked as a "console"
|
||||
application.
|
||||
*/
|
||||
|
||||
// Convert a wchar_t to char string, equivalent to QString::toLocal8Bit()
|
||||
// when passed CP_ACP.
|
||||
static inline char* wideToMulti(unsigned int codePage, const wchar_t* aw)
|
||||
{
|
||||
const int required = WideCharToMultiByte(codePage, 0, aw, -1, nullptr, 0, nullptr, nullptr);
|
||||
char* result = new char[required];
|
||||
WideCharToMultiByte(codePage, 0, aw, -1, result, required, nullptr, nullptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C" int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR /*cmdParamarg*/, int /* cmdShow */)
|
||||
{
|
||||
int argc = 0;
|
||||
wchar_t** argvW = CommandLineToArgvW(GetCommandLineW(), &argc);
|
||||
if (argvW == nullptr)
|
||||
return -1;
|
||||
char** argv = new char* [argc + 1];
|
||||
for (int i = 0; i != argc; ++i)
|
||||
argv[i] = wideToMulti(CP_ACP, argvW[i]);
|
||||
argv[argc] = nullptr;
|
||||
LocalFree(argvW);
|
||||
const int exitCode = main(argc, argv);
|
||||
for (int i = 0; (i != argc) && (argv[i] != nullptr); ++i)
|
||||
delete[] argv[i];
|
||||
delete[] argv;
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -7,6 +7,7 @@
|
|||
#include "common/log.h"
|
||||
#include "core/host.h"
|
||||
#include "core/host_display.h"
|
||||
#include "core/memory_card.h"
|
||||
#include "core/settings.h"
|
||||
#include "core/system.h"
|
||||
#include "debuggerwindow.h"
|
||||
|
@ -90,7 +91,7 @@ MainWindow::~MainWindow()
|
|||
g_main_window = nullptr;
|
||||
}
|
||||
|
||||
void MainWindow::initializeAndShow()
|
||||
void MainWindow::initialize()
|
||||
{
|
||||
setIconThemeFromSettings();
|
||||
|
||||
|
@ -102,8 +103,6 @@ void MainWindow::initializeAndShow()
|
|||
restoreStateFromConfig();
|
||||
switchToGameListView();
|
||||
|
||||
show();
|
||||
|
||||
#ifdef WITH_RAINTEGRATION
|
||||
if (Cheevos::IsUsingRAIntegration())
|
||||
Cheevos::RAIntegration::MainWindowChanged((void*)winId());
|
||||
|
@ -113,15 +112,13 @@ void MainWindow::initializeAndShow()
|
|||
void MainWindow::reportError(const QString& title, const QString& message)
|
||||
{
|
||||
QMessageBox::critical(this, title, message, QMessageBox::Ok);
|
||||
focusDisplayWidget();
|
||||
}
|
||||
|
||||
bool MainWindow::confirmMessage(const QString& title, const QString& message)
|
||||
{
|
||||
const int result = QMessageBox::question(this, title, message);
|
||||
focusDisplayWidget();
|
||||
SystemLock lock(pauseAndLockSystem());
|
||||
|
||||
return (result == QMessageBox::Yes);
|
||||
return (QMessageBox::question(this, title, message) == QMessageBox::Yes);
|
||||
}
|
||||
|
||||
bool MainWindow::shouldHideCursorInFullscreen() const
|
||||
|
@ -611,7 +608,7 @@ void MainWindow::onApplicationStateChanged(Qt::ApplicationState state)
|
|||
{
|
||||
if (!m_was_paused_by_focus_loss && !s_system_paused)
|
||||
{
|
||||
g_emu_thread->pauseSystem(true);
|
||||
g_emu_thread->setSystemPaused(true);
|
||||
m_was_paused_by_focus_loss = true;
|
||||
updateMouseMode(true);
|
||||
}
|
||||
|
@ -621,7 +618,7 @@ void MainWindow::onApplicationStateChanged(Qt::ApplicationState state)
|
|||
if (m_was_paused_by_focus_loss)
|
||||
{
|
||||
if (s_system_paused)
|
||||
g_emu_thread->pauseSystem(false);
|
||||
g_emu_thread->setSystemPaused(false);
|
||||
m_was_paused_by_focus_loss = false;
|
||||
updateMouseMode(false);
|
||||
}
|
||||
|
@ -683,25 +680,131 @@ std::string MainWindow::getDeviceDiscPath(const QString& title)
|
|||
void MainWindow::recreate()
|
||||
{
|
||||
if (s_system_valid)
|
||||
g_emu_thread->synchronousPowerOffSystem();
|
||||
requestShutdown(false, true, true);
|
||||
|
||||
close();
|
||||
g_main_window = nullptr;
|
||||
|
||||
MainWindow* new_main_window = new MainWindow();
|
||||
new_main_window->initializeAndShow();
|
||||
new_main_window->initialize();
|
||||
new_main_window->refreshGameList(false);
|
||||
new_main_window->show();
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
std::optional<bool> MainWindow::promptForResumeState(const QString& save_state_path)
|
||||
void MainWindow::populateGameListContextMenu(const GameList::Entry* entry, QWidget* parent_window, QMenu* menu)
|
||||
{
|
||||
if (save_state_path.isEmpty())
|
||||
return false;
|
||||
QAction* resume_action = menu->addAction(tr("Resume"));
|
||||
resume_action->setEnabled(false);
|
||||
|
||||
QFileInfo fi(save_state_path);
|
||||
if (!fi.exists())
|
||||
QMenu* load_state_menu = menu->addMenu(tr("Load State"));
|
||||
load_state_menu->setEnabled(false);
|
||||
|
||||
if (!entry->serial.empty())
|
||||
{
|
||||
std::vector<SaveStateInfo> available_states(System::GetAvailableSaveStates(entry->serial.c_str()));
|
||||
const QString timestamp_format = QLocale::system().dateTimeFormat(QLocale::ShortFormat);
|
||||
const bool challenge_mode = Cheevos::IsChallengeModeActive();
|
||||
for (SaveStateInfo& ssi : available_states)
|
||||
{
|
||||
if (ssi.global)
|
||||
continue;
|
||||
|
||||
const s32 slot = ssi.slot;
|
||||
const QDateTime timestamp(QDateTime::fromSecsSinceEpoch(static_cast<qint64>(ssi.timestamp)));
|
||||
const QString timestamp_str(timestamp.toString(timestamp_format));
|
||||
|
||||
QAction* action;
|
||||
if (slot < 0)
|
||||
{
|
||||
resume_action->setText(tr("Resume (%1)").arg(timestamp_str));
|
||||
resume_action->setEnabled(!challenge_mode);
|
||||
action = resume_action;
|
||||
}
|
||||
else
|
||||
{
|
||||
load_state_menu->setEnabled(true);
|
||||
action = load_state_menu->addAction(tr("Game Save %1 (%2)").arg(slot).arg(timestamp_str));
|
||||
}
|
||||
|
||||
action->setDisabled(challenge_mode);
|
||||
connect(action, &QAction::triggered, [this, entry, path = std::move(ssi.path)]() {
|
||||
startGameListEntry(entry, std::move(path), std::nullopt);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
QAction* open_memory_cards_action = menu->addAction(tr("Edit Memory Cards..."));
|
||||
connect(open_memory_cards_action, &QAction::triggered, [this, entry]() {
|
||||
QString paths[2];
|
||||
for (u32 i = 0; i < 2; i++)
|
||||
{
|
||||
MemoryCardType type = g_settings.memory_card_types[i];
|
||||
if (entry->serial.empty() && type == MemoryCardType::PerGame)
|
||||
type = MemoryCardType::Shared;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case MemoryCardType::None:
|
||||
continue;
|
||||
case MemoryCardType::Shared:
|
||||
if (g_settings.memory_card_paths[i].empty())
|
||||
{
|
||||
paths[i] = QString::fromStdString(g_settings.GetSharedMemoryCardPath(i));
|
||||
}
|
||||
else
|
||||
{
|
||||
QFileInfo path(QString::fromStdString(g_settings.memory_card_paths[i]));
|
||||
path.makeAbsolute();
|
||||
paths[i] = QDir::toNativeSeparators(path.canonicalFilePath());
|
||||
}
|
||||
break;
|
||||
case MemoryCardType::PerGame:
|
||||
paths[i] = QString::fromStdString(g_settings.GetGameMemoryCardPath(entry->serial.c_str(), i));
|
||||
break;
|
||||
case MemoryCardType::PerGameTitle:
|
||||
paths[i] = QString::fromStdString(
|
||||
g_settings.GetGameMemoryCardPath(MemoryCard::SanitizeGameTitleForFileName(entry->title).c_str(), i));
|
||||
break;
|
||||
case MemoryCardType::PerGameFileTitle:
|
||||
{
|
||||
const std::string display_name(FileSystem::GetDisplayNameFromPath(entry->path));
|
||||
paths[i] = QString::fromStdString(g_settings.GetGameMemoryCardPath(
|
||||
MemoryCard::SanitizeGameTitleForFileName(Path::GetFileTitle(display_name)).c_str(), i));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_main_window->openMemoryCardEditor(paths[0], paths[1]);
|
||||
});
|
||||
|
||||
const bool has_any_states = resume_action->isEnabled() || load_state_menu->isEnabled();
|
||||
QAction* delete_save_states_action = menu->addAction(tr("Delete Save States..."));
|
||||
delete_save_states_action->setEnabled(has_any_states);
|
||||
if (has_any_states)
|
||||
{
|
||||
connect(delete_save_states_action, &QAction::triggered, [this, parent_window, entry] {
|
||||
if (QMessageBox::warning(
|
||||
parent_window, tr("Confirm Save State Deletion"),
|
||||
tr("Are you sure you want to delete all save states for %1?\n\nThe saves will not be recoverable.")
|
||||
.arg(QString::fromStdString(entry->serial)),
|
||||
QMessageBox::Yes, QMessageBox::No) != QMessageBox::Yes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
System::DeleteSaveStates(entry->serial.c_str(), true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<bool> MainWindow::promptForResumeState(const std::string& save_state_path)
|
||||
{
|
||||
FILESYSTEM_STAT_DATA sd;
|
||||
if (save_state_path.empty() || !FileSystem::StatFile(save_state_path.c_str(), &sd))
|
||||
return false;
|
||||
|
||||
QMessageBox msgbox(this);
|
||||
|
@ -709,7 +812,7 @@ std::optional<bool> MainWindow::promptForResumeState(const QString& save_state_p
|
|||
msgbox.setWindowTitle(tr("Load Resume State"));
|
||||
msgbox.setText(tr("A resume save state was found for this game, saved at:\n\n%1.\n\nDo you want to load this state, "
|
||||
"or start from a fresh boot?")
|
||||
.arg(fi.lastModified().toLocalTime().toString()));
|
||||
.arg(QDateTime::fromSecsSinceEpoch(sd.ModificationTime, Qt::UTC).toLocalTime().toString()));
|
||||
|
||||
QPushButton* load = msgbox.addButton(tr("Load State"), QMessageBox::AcceptRole);
|
||||
QPushButton* boot = msgbox.addButton(tr("Fresh Boot"), QMessageBox::RejectRole);
|
||||
|
@ -729,8 +832,11 @@ std::optional<bool> MainWindow::promptForResumeState(const QString& save_state_p
|
|||
}
|
||||
else if (delboot == clicked)
|
||||
{
|
||||
if (!QFile::remove(save_state_path))
|
||||
QMessageBox::critical(this, tr("Error"), tr("Failed to delete save state file '%1'.").arg(save_state_path));
|
||||
if (!FileSystem::DeleteFile(save_state_path.c_str()))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"),
|
||||
tr("Failed to delete save state file '%1'.").arg(QString::fromStdString(save_state_path)));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -738,24 +844,14 @@ std::optional<bool> MainWindow::promptForResumeState(const QString& save_state_p
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
void MainWindow::startGameListEntry(const GameList::Entry* entry, std::optional<s32> save_slot,
|
||||
void MainWindow::startGameListEntry(const GameList::Entry* entry, std::optional<std::string> save_path,
|
||||
std::optional<bool> fast_boot)
|
||||
{
|
||||
std::shared_ptr<SystemBootParameters> params = std::make_shared<SystemBootParameters>();
|
||||
params->filename = entry->path;
|
||||
params->override_fast_boot = fast_boot;
|
||||
|
||||
if (save_slot.has_value() && !entry->serial.empty())
|
||||
{
|
||||
std::string state_filename = System::GetGameSaveStateFileName(entry->serial.c_str(), save_slot.value());
|
||||
if (!FileSystem::FileExists(state_filename.c_str()))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("This save state does not exist."));
|
||||
return;
|
||||
}
|
||||
|
||||
params->save_state = std::move(state_filename);
|
||||
}
|
||||
if (save_path.has_value())
|
||||
params->save_state = std::move(save_path.value());
|
||||
|
||||
g_emu_thread->bootSystem(std::move(params));
|
||||
}
|
||||
|
@ -786,7 +882,7 @@ void MainWindow::onChangeDiscFromFileActionTriggered()
|
|||
|
||||
void MainWindow::onChangeDiscFromGameListActionTriggered()
|
||||
{
|
||||
g_emu_thread->pauseSystem(true);
|
||||
g_emu_thread->setSystemPaused(true);
|
||||
switchToGameListView();
|
||||
}
|
||||
|
||||
|
@ -880,22 +976,11 @@ void MainWindow::onViewGamePropertiesActionTriggered()
|
|||
return;
|
||||
|
||||
const std::string& path = System::GetRunningPath();
|
||||
if (path.empty())
|
||||
const std::string& serial = System::GetRunningCode();
|
||||
if (path.empty() || serial.empty())
|
||||
return;
|
||||
|
||||
#if 0
|
||||
const GameListEntry* entry = m_host_interface->getGameList()->GetEntryForPath(path.c_str());
|
||||
if (!entry)
|
||||
{
|
||||
QMessageBox::critical(this, tr("DuckStation"),
|
||||
tr("Could not find a game list entry for the currently running file. Please make sure this "
|
||||
"file is in a location scanned by the game list."));
|
||||
return;
|
||||
}
|
||||
|
||||
GamePropertiesDialog::showForEntry(m_host_interface, entry, this);
|
||||
#endif
|
||||
Panic("FIXME");
|
||||
SettingsDialog::openGamePropertiesDialog(path, serial, System::GetDiscRegion());
|
||||
}
|
||||
|
||||
void MainWindow::onGitHubRepositoryActionTriggered()
|
||||
|
@ -967,20 +1052,22 @@ void MainWindow::onGameListEntryActivated()
|
|||
// we might still be saving a resume state...
|
||||
// VMManager::WaitForSaveStateFlush();
|
||||
|
||||
std::optional<bool> resume = true;
|
||||
std::optional<std::string> save_path;
|
||||
if (!entry->serial.empty())
|
||||
{
|
||||
resume =
|
||||
promptForResumeState(QString::fromStdString(System::GetGameSaveStateFileName(entry->serial.c_str(), -1)));
|
||||
std::string resume_path(System::GetGameSaveStateFileName(entry->serial.c_str(), -1));
|
||||
std::optional<bool> resume = promptForResumeState(resume_path);
|
||||
if (!resume.has_value())
|
||||
{
|
||||
// cancelled
|
||||
return;
|
||||
}
|
||||
else if (resume.value())
|
||||
save_path = std::move(resume_path);
|
||||
}
|
||||
|
||||
// only resume if the option is enabled, and we have one for this game
|
||||
startGameListEntry(entry, resume.value() ? std::optional<s32>(-1) : std::optional<s32>(), std::nullopt);
|
||||
startGameListEntry(entry, std::move(save_path), std::nullopt);
|
||||
}
|
||||
|
||||
void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
|
||||
|
@ -995,7 +1082,7 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
|
|||
{
|
||||
QAction* action = menu.addAction(tr("Properties..."));
|
||||
connect(action, &QAction::triggered,
|
||||
[this, entry]() { /*GamePropertiesDialog::showForEntry(m_host_interface, entry, this);*/ });
|
||||
[this, entry]() { SettingsDialog::openGamePropertiesDialog(entry->path, entry->serial, entry->region); });
|
||||
|
||||
connect(menu.addAction(tr("Open Containing Directory...")), &QAction::triggered, [this, entry]() {
|
||||
const QFileInfo fi(QString::fromStdString(entry->path));
|
||||
|
@ -1009,7 +1096,7 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
|
|||
|
||||
if (!s_system_valid)
|
||||
{
|
||||
g_emu_thread->populateGameListContextMenu(entry, this, &menu);
|
||||
populateGameListContextMenu(entry, this, &menu);
|
||||
menu.addSeparator();
|
||||
|
||||
connect(menu.addAction(tr("Default Boot")), &QAction::triggered,
|
||||
|
@ -1042,7 +1129,7 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
|
|||
{
|
||||
connect(menu.addAction(tr("Change Disc")), &QAction::triggered, [this, entry]() {
|
||||
g_emu_thread->changeDisc(QString::fromStdString(entry->path));
|
||||
g_emu_thread->pauseSystem(false);
|
||||
g_emu_thread->setSystemPaused(false);
|
||||
switchToEmulationView();
|
||||
});
|
||||
}
|
||||
|
@ -1194,7 +1281,7 @@ void MainWindow::setupAdditionalUi()
|
|||
|
||||
const QString current_language(QString::fromStdString(Host::GetBaseStringSettingValue("Main", "Language", "")));
|
||||
QActionGroup* language_group = new QActionGroup(m_ui.menuSettingsLanguage);
|
||||
for (const std::pair<QString, QString>& it : g_emu_thread->getAvailableLanguageList())
|
||||
for (const std::pair<QString, QString>& it : QtHost::GetAvailableLanguageList())
|
||||
{
|
||||
QAction* action = language_group->addAction(it.first);
|
||||
action->setCheckable(true);
|
||||
|
@ -1215,7 +1302,7 @@ void MainWindow::setupAdditionalUi()
|
|||
connect(action, &QAction::triggered, [this, action]() {
|
||||
const QString new_language = action->data().toString();
|
||||
Host::SetBaseStringSettingValue("Main", "Language", new_language.toUtf8().constData());
|
||||
g_emu_thread->reinstallTranslator();
|
||||
QtHost::ReinstallTranslator();
|
||||
recreate();
|
||||
});
|
||||
}
|
||||
|
@ -1223,7 +1310,7 @@ void MainWindow::setupAdditionalUi()
|
|||
for (u32 scale = 1; scale <= 10; scale++)
|
||||
{
|
||||
QAction* action = m_ui.menuWindowSize->addAction(tr("%1x Scale").arg(scale));
|
||||
connect(action, &QAction::triggered, [scale]() { g_emu_thread->requestRenderWindowScale(scale); });
|
||||
connect(action, &QAction::triggered, [scale]() { g_emu_thread->requestDisplaySize(scale); });
|
||||
}
|
||||
|
||||
#ifdef WITH_RAINTEGRATION
|
||||
|
@ -1243,9 +1330,8 @@ void MainWindow::setupAdditionalUi()
|
|||
}
|
||||
|
||||
QAction* raAction = raMenu->addAction(QString::fromUtf8(title));
|
||||
connect(raAction, &QAction::triggered, this, [id]() {
|
||||
g_emu_thread->executeOnEmulationThread([id]() { Cheevos::RAIntegration::ActivateMenuItem(id); });
|
||||
});
|
||||
connect(raAction, &QAction::triggered, this,
|
||||
[id]() { Host::RunOnCPUThread([id]() { Cheevos::RAIntegration::ActivateMenuItem(id); }); });
|
||||
}
|
||||
});
|
||||
m_ui.menuDebug->insertMenu(m_ui.menuCPUExecutionMode->menuAction(), raMenu);
|
||||
|
@ -1406,7 +1492,7 @@ void MainWindow::updateWindowState(bool force_visible)
|
|||
return;
|
||||
|
||||
const bool hide_window = !isRenderingToMain() && shouldHideMainWindow();
|
||||
const bool disable_resize = Host::GetBaseBoolSettingValue("UI", "DisableWindowResize", false);
|
||||
const bool disable_resize = Host::GetBaseBoolSettingValue("Main", "DisableWindowResize", false);
|
||||
const bool has_window = s_system_valid || m_display_widget;
|
||||
|
||||
// Need to test both valid and display widget because of startup (vm invalid while window is created).
|
||||
|
@ -1467,12 +1553,12 @@ bool MainWindow::isRenderingToMain() const
|
|||
|
||||
bool MainWindow::shouldHideMouseCursor() const
|
||||
{
|
||||
return isRenderingFullscreen() && Host::GetBoolSettingValue("UI", "HideMouseCursor", false);
|
||||
return isRenderingFullscreen() && Host::GetBoolSettingValue("Main", "HideMouseCursor", false);
|
||||
}
|
||||
|
||||
bool MainWindow::shouldHideMainWindow() const
|
||||
{
|
||||
return Host::GetBaseBoolSettingValue("UI", "HideMainWindowWhenRunning", false) || isRenderingFullscreen() ||
|
||||
return Host::GetBaseBoolSettingValue("Main", "HideMainWindowWhenRunning", false) || isRenderingFullscreen() ||
|
||||
QtHost::InNoGUIMode();
|
||||
}
|
||||
|
||||
|
@ -1488,7 +1574,7 @@ void MainWindow::switchToGameListView()
|
|||
{
|
||||
m_was_paused_on_surface_loss = s_system_paused;
|
||||
if (!s_system_paused)
|
||||
g_emu_thread->pauseSystem(true);
|
||||
g_emu_thread->setSystemPaused(true);
|
||||
|
||||
// switch to surfaceless. we have to wait until the display widget is gone before we swap over.
|
||||
g_emu_thread->setSurfaceless(true);
|
||||
|
@ -1513,7 +1599,7 @@ void MainWindow::switchToEmulationView()
|
|||
|
||||
// resume if we weren't paused at switch time
|
||||
if (s_system_paused && !m_was_paused_on_surface_loss)
|
||||
g_emu_thread->pauseSystem(false);
|
||||
g_emu_thread->setSystemPaused(false);
|
||||
|
||||
if (m_display_widget)
|
||||
m_display_widget->setFocus();
|
||||
|
@ -1528,8 +1614,7 @@ void MainWindow::connectSignals()
|
|||
connect(m_ui.actionStartFile, &QAction::triggered, this, &MainWindow::onStartFileActionTriggered);
|
||||
connect(m_ui.actionStartDisc, &QAction::triggered, this, &MainWindow::onStartDiscActionTriggered);
|
||||
connect(m_ui.actionStartBios, &QAction::triggered, this, &MainWindow::onStartBIOSActionTriggered);
|
||||
connect(m_ui.actionResumeLastState, &QAction::triggered, g_emu_thread,
|
||||
&QtHostInterface::resumeSystemFromMostRecentState);
|
||||
connect(m_ui.actionResumeLastState, &QAction::triggered, g_emu_thread, &EmuThread::resumeSystemFromMostRecentState);
|
||||
connect(m_ui.actionChangeDisc, &QAction::triggered, [this] { m_ui.menuChangeDisc->exec(QCursor::pos()); });
|
||||
connect(m_ui.actionChangeDiscFromFile, &QAction::triggered, this, &MainWindow::onChangeDiscFromFileActionTriggered);
|
||||
connect(m_ui.actionChangeDiscFromDevice, &QAction::triggered, this,
|
||||
|
@ -1545,47 +1630,35 @@ void MainWindow::connectSignals()
|
|||
connect(m_ui.actionRemoveDisc, &QAction::triggered, this, &MainWindow::onRemoveDiscActionTriggered);
|
||||
connect(m_ui.actionAddGameDirectory, &QAction::triggered,
|
||||
[this]() { getSettingsDialog()->getGameListSettingsWidget()->addSearchDirectory(this); });
|
||||
connect(m_ui.actionPowerOff, &QAction::triggered, g_emu_thread, &QtHostInterface::powerOffSystem);
|
||||
connect(m_ui.actionPowerOffWithoutSaving, &QAction::triggered, g_emu_thread,
|
||||
&QtHostInterface::powerOffSystemWithoutSaving);
|
||||
connect(m_ui.actionReset, &QAction::triggered, g_emu_thread, &QtHostInterface::resetSystem);
|
||||
connect(m_ui.actionPause, &QAction::toggled, [this](bool active) { g_emu_thread->pauseSystem(active); });
|
||||
connect(m_ui.actionScreenshot, &QAction::triggered, g_emu_thread, &QtHostInterface::saveScreenshot);
|
||||
connect(m_ui.actionPowerOff, &QAction::triggered, this, [this]() { requestShutdown(true, true); });
|
||||
connect(m_ui.actionPowerOffWithoutSaving, &QAction::triggered, this, [this]() { requestShutdown(false, false); });
|
||||
connect(m_ui.actionReset, &QAction::triggered, g_emu_thread, &EmuThread::resetSystem);
|
||||
connect(m_ui.actionPause, &QAction::toggled, [this](bool active) { g_emu_thread->setSystemPaused(active); });
|
||||
connect(m_ui.actionScreenshot, &QAction::triggered, g_emu_thread, &EmuThread::saveScreenshot);
|
||||
connect(m_ui.actionScanForNewGames, &QAction::triggered, this, [this]() { refreshGameList(false); });
|
||||
connect(m_ui.actionRescanAllGames, &QAction::triggered, this, [this]() { refreshGameList(true); });
|
||||
connect(m_ui.actionLoadState, &QAction::triggered, this, [this]() { m_ui.menuLoadState->exec(QCursor::pos()); });
|
||||
connect(m_ui.actionSaveState, &QAction::triggered, this, [this]() { m_ui.menuSaveState->exec(QCursor::pos()); });
|
||||
connect(m_ui.actionExit, &QAction::triggered, this, &MainWindow::close);
|
||||
connect(m_ui.actionFullscreen, &QAction::triggered, g_emu_thread, &QtHostInterface::toggleFullscreen);
|
||||
connect(m_ui.actionSettings, &QAction::triggered, [this]() { doSettings(SettingsDialog::Category::Count); });
|
||||
connect(m_ui.actionGeneralSettings, &QAction::triggered,
|
||||
[this]() { doSettings(SettingsDialog::Category::GeneralSettings); });
|
||||
connect(m_ui.actionBIOSSettings, &QAction::triggered,
|
||||
[this]() { doSettings(SettingsDialog::Category::BIOSSettings); });
|
||||
connect(m_ui.actionConsoleSettings, &QAction::triggered,
|
||||
[this]() { doSettings(SettingsDialog::Category::ConsoleSettings); });
|
||||
connect(m_ui.actionEmulationSettings, &QAction::triggered,
|
||||
[this]() { doSettings(SettingsDialog::Category::EmulationSettings); });
|
||||
connect(m_ui.actionGameListSettings, &QAction::triggered,
|
||||
[this]() { doSettings(SettingsDialog::Category::GameListSettings); });
|
||||
connect(m_ui.actionFullscreen, &QAction::triggered, g_emu_thread, &EmuThread::toggleFullscreen);
|
||||
connect(m_ui.actionSettings, &QAction::triggered, [this]() { doSettings(); });
|
||||
connect(m_ui.actionGeneralSettings, &QAction::triggered, [this]() { doSettings("General"); });
|
||||
connect(m_ui.actionBIOSSettings, &QAction::triggered, [this]() { doSettings("BIOS"); });
|
||||
connect(m_ui.actionConsoleSettings, &QAction::triggered, [this]() { doSettings("Console"); });
|
||||
connect(m_ui.actionEmulationSettings, &QAction::triggered, [this]() { doSettings("Emulation"); });
|
||||
connect(m_ui.actionGameListSettings, &QAction::triggered, [this]() { doSettings("Game List"); });
|
||||
connect(m_ui.actionHotkeySettings, &QAction::triggered,
|
||||
[this]() { doControllerSettings(ControllerSettingsDialog::Category::HotkeySettings); });
|
||||
connect(m_ui.actionControllerSettings, &QAction::triggered,
|
||||
[this]() { doControllerSettings(ControllerSettingsDialog::Category::GlobalSettings); });
|
||||
connect(m_ui.actionMemoryCardSettings, &QAction::triggered,
|
||||
[this]() { doSettings(SettingsDialog::Category::MemoryCardSettings); });
|
||||
connect(m_ui.actionDisplaySettings, &QAction::triggered,
|
||||
[this]() { doSettings(SettingsDialog::Category::DisplaySettings); });
|
||||
connect(m_ui.actionEnhancementSettings, &QAction::triggered,
|
||||
[this]() { doSettings(SettingsDialog::Category::EnhancementSettings); });
|
||||
connect(m_ui.actionPostProcessingSettings, &QAction::triggered,
|
||||
[this]() { doSettings(SettingsDialog::Category::PostProcessingSettings); });
|
||||
connect(m_ui.actionAudioSettings, &QAction::triggered,
|
||||
[this]() { doSettings(SettingsDialog::Category::AudioSettings); });
|
||||
connect(m_ui.actionAchievementSettings, &QAction::triggered,
|
||||
[this]() { doSettings(SettingsDialog::Category::AchievementSettings); });
|
||||
connect(m_ui.actionAdvancedSettings, &QAction::triggered,
|
||||
[this]() { doSettings(SettingsDialog::Category::AdvancedSettings); });
|
||||
connect(m_ui.actionMemoryCardSettings, &QAction::triggered, [this]() { doSettings("Memory Cards"); });
|
||||
connect(m_ui.actionDisplaySettings, &QAction::triggered, [this]() { doSettings("Display"); });
|
||||
connect(m_ui.actionEnhancementSettings, &QAction::triggered, [this]() { doSettings("Enhancements"); });
|
||||
connect(m_ui.actionPostProcessingSettings, &QAction::triggered, [this]() { doSettings("Post-Processing"); });
|
||||
connect(m_ui.actionAudioSettings, &QAction::triggered, [this]() { doSettings("Audio"); });
|
||||
connect(m_ui.actionAchievementSettings, &QAction::triggered, [this]() { doSettings("Achievements"); });
|
||||
connect(m_ui.actionFolderSettings, &QAction::triggered, [this]() { doSettings("Folders"); });
|
||||
connect(m_ui.actionAdvancedSettings, &QAction::triggered, [this]() { doSettings("Advanced"); });
|
||||
connect(m_ui.actionViewToolbar, &QAction::toggled, this, &MainWindow::onViewToolbarActionToggled);
|
||||
connect(m_ui.actionViewLockToolbar, &QAction::toggled, this, &MainWindow::onViewLockToolbarActionToggled);
|
||||
connect(m_ui.actionViewStatusBar, &QAction::toggled, this, &MainWindow::onViewStatusBarActionToggled);
|
||||
|
@ -1615,27 +1688,25 @@ void MainWindow::connectSignals()
|
|||
connect(m_ui.actionGridViewRefreshCovers, &QAction::triggered, m_game_list_widget,
|
||||
&GameListWidget::refreshGridCovers);
|
||||
|
||||
connect(g_emu_thread, &QtHostInterface::settingsResetToDefault, this, &MainWindow::onSettingsResetToDefault);
|
||||
connect(g_emu_thread, &QtHostInterface::errorReported, this, &MainWindow::reportError, Qt::BlockingQueuedConnection);
|
||||
connect(g_emu_thread, &QtHostInterface::messageConfirmed, this, &MainWindow::confirmMessage,
|
||||
connect(g_emu_thread, &EmuThread::settingsResetToDefault, this, &MainWindow::onSettingsResetToDefault);
|
||||
connect(g_emu_thread, &EmuThread::errorReported, this, &MainWindow::reportError, Qt::BlockingQueuedConnection);
|
||||
connect(g_emu_thread, &EmuThread::messageConfirmed, this, &MainWindow::confirmMessage, Qt::BlockingQueuedConnection);
|
||||
connect(g_emu_thread, &EmuThread::createDisplayRequested, this, &MainWindow::createDisplay,
|
||||
Qt::BlockingQueuedConnection);
|
||||
connect(g_emu_thread, &QtHostInterface::createDisplayRequested, this, &MainWindow::createDisplay,
|
||||
connect(g_emu_thread, &EmuThread::destroyDisplayRequested, this, &MainWindow::destroyDisplay);
|
||||
connect(g_emu_thread, &EmuThread::updateDisplayRequested, this, &MainWindow::updateDisplay,
|
||||
Qt::BlockingQueuedConnection);
|
||||
connect(g_emu_thread, &QtHostInterface::destroyDisplayRequested, this, &MainWindow::destroyDisplay);
|
||||
connect(g_emu_thread, &QtHostInterface::updateDisplayRequested, this, &MainWindow::updateDisplay,
|
||||
Qt::BlockingQueuedConnection);
|
||||
connect(g_emu_thread, &QtHostInterface::displaySizeRequested, this, &MainWindow::displaySizeRequested);
|
||||
connect(g_emu_thread, &QtHostInterface::focusDisplayWidgetRequested, this, &MainWindow::focusDisplayWidget);
|
||||
connect(g_emu_thread, &QtHostInterface::systemStarting, this, &MainWindow::onSystemStarting);
|
||||
connect(g_emu_thread, &QtHostInterface::systemStarted, this, &MainWindow::onSystemStarted);
|
||||
connect(g_emu_thread, &QtHostInterface::systemDestroyed, this, &MainWindow::onSystemDestroyed);
|
||||
connect(g_emu_thread, &QtHostInterface::systemPaused, this, &MainWindow::onSystemPaused);
|
||||
connect(g_emu_thread, &QtHostInterface::systemResumed, this, &MainWindow::onSystemResumed);
|
||||
connect(g_emu_thread, &QtHostInterface::systemPerformanceCountersUpdated, this,
|
||||
connect(g_emu_thread, &EmuThread::displaySizeRequested, this, &MainWindow::displaySizeRequested);
|
||||
connect(g_emu_thread, &EmuThread::focusDisplayWidgetRequested, this, &MainWindow::focusDisplayWidget);
|
||||
connect(g_emu_thread, &EmuThread::systemStarting, this, &MainWindow::onSystemStarting);
|
||||
connect(g_emu_thread, &EmuThread::systemStarted, this, &MainWindow::onSystemStarted);
|
||||
connect(g_emu_thread, &EmuThread::systemDestroyed, this, &MainWindow::onSystemDestroyed);
|
||||
connect(g_emu_thread, &EmuThread::systemPaused, this, &MainWindow::onSystemPaused);
|
||||
connect(g_emu_thread, &EmuThread::systemResumed, this, &MainWindow::onSystemResumed);
|
||||
connect(g_emu_thread, &EmuThread::systemPerformanceCountersUpdated, this,
|
||||
&MainWindow::onSystemPerformanceCountersUpdated);
|
||||
connect(g_emu_thread, &QtHostInterface::runningGameChanged, this, &MainWindow::onRunningGameChanged);
|
||||
connect(g_emu_thread, &QtHostInterface::exitRequested, this, &MainWindow::close);
|
||||
connect(g_emu_thread, &QtHostInterface::mouseModeRequested, this, &MainWindow::onMouseModeRequested);
|
||||
connect(g_emu_thread, &EmuThread::runningGameChanged, this, &MainWindow::onRunningGameChanged);
|
||||
connect(g_emu_thread, &EmuThread::mouseModeRequested, this, &MainWindow::onMouseModeRequested);
|
||||
|
||||
// These need to be queued connections to stop crashing due to menus opening/closing and switching focus.
|
||||
connect(m_game_list_widget, &GameListWidget::refreshProgress, this, &MainWindow::onGameListRefreshProgress);
|
||||
|
@ -1766,6 +1837,7 @@ void MainWindow::setStyleFromSettings()
|
|||
darkPalette.setColor(QPalette::Link, blue);
|
||||
darkPalette.setColor(QPalette::Highlight, lighterGray);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
darkPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, gray.darker());
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
||||
|
@ -1802,6 +1874,7 @@ void MainWindow::setStyleFromSettings()
|
|||
darkPalette.setColor(QPalette::Link, blue);
|
||||
darkPalette.setColor(QPalette::Highlight, blue2);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
darkPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, gray.darker());
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
||||
|
@ -1930,7 +2003,7 @@ SettingsDialog* MainWindow::getSettingsDialog()
|
|||
return m_settings_dialog;
|
||||
}
|
||||
|
||||
void MainWindow::doSettings(SettingsDialog::Category category)
|
||||
void MainWindow::doSettings(const char* category /* = nullptr */)
|
||||
{
|
||||
SettingsDialog* dlg = getSettingsDialog();
|
||||
if (!dlg->isVisible())
|
||||
|
@ -1939,7 +2012,7 @@ void MainWindow::doSettings(SettingsDialog::Category category)
|
|||
dlg->show();
|
||||
}
|
||||
|
||||
if (category != SettingsDialog::Category::Count)
|
||||
if (category)
|
||||
dlg->setCategory(category);
|
||||
}
|
||||
|
||||
|
@ -2038,8 +2111,20 @@ void MainWindow::updateMenuSelectedTheme()
|
|||
|
||||
void MainWindow::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
g_emu_thread->synchronousPowerOffSystem();
|
||||
if (!requestShutdown(true, true, true))
|
||||
{
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (g_emu_thread->isRunningFullscreenUI())
|
||||
g_emu_thread->stopFullscreenUI();
|
||||
#endif
|
||||
|
||||
saveStateToConfig();
|
||||
m_is_closing = true;
|
||||
|
||||
QMainWindow::closeEvent(event);
|
||||
}
|
||||
|
||||
|
@ -2107,6 +2192,93 @@ void MainWindow::refreshGameList(bool invalidate_cache)
|
|||
m_game_list_widget->refresh(invalidate_cache);
|
||||
}
|
||||
|
||||
void MainWindow::runOnUIThread(const std::function<void()>& func)
|
||||
{
|
||||
func();
|
||||
}
|
||||
|
||||
bool MainWindow::requestShutdown(bool allow_confirm /* = true */, bool allow_save_to_state /* = true */,
|
||||
bool block_until_done /* = false */)
|
||||
{
|
||||
if (!s_system_valid)
|
||||
return true;
|
||||
|
||||
// If we don't have a serial, we can't save state.
|
||||
allow_save_to_state &= !m_current_game_code.empty();
|
||||
bool save_state = allow_save_to_state && g_settings.save_state_on_exit;
|
||||
|
||||
// Only confirm on UI thread because we need to display a msgbox.
|
||||
if (!m_is_closing && allow_confirm && g_settings.confim_power_off)
|
||||
{
|
||||
SystemLock lock(pauseAndLockSystem());
|
||||
|
||||
QMessageBox msgbox(lock.getDialogParent());
|
||||
msgbox.setIcon(QMessageBox::Question);
|
||||
msgbox.setWindowTitle(tr("Confirm Shutdown"));
|
||||
msgbox.setText("Are you sure you want to shut down the virtual machine?");
|
||||
|
||||
QCheckBox* save_cb = new QCheckBox(tr("Save State For Resume"), &msgbox);
|
||||
save_cb->setChecked(save_state);
|
||||
save_cb->setEnabled(allow_save_to_state);
|
||||
msgbox.setCheckBox(save_cb);
|
||||
msgbox.addButton(QMessageBox::Yes);
|
||||
msgbox.addButton(QMessageBox::No);
|
||||
msgbox.setDefaultButton(QMessageBox::Yes);
|
||||
if (msgbox.exec() != QMessageBox::Yes)
|
||||
return false;
|
||||
|
||||
save_state = save_cb->isChecked();
|
||||
|
||||
// Don't switch back to fullscreen when we're shutting down anyway.
|
||||
lock.cancelResume();
|
||||
}
|
||||
|
||||
// This is a little bit annoying. Qt will close everything down if we don't have at least one window visible,
|
||||
// but we might not be visible because the user is using render-to-separate and hide. We don't want to always
|
||||
// reshow the main window during display updates, because otherwise fullscreen transitions and renderer switches
|
||||
// would briefly show and then hide the main window. So instead, we do it on shutdown, here. Except if we're in
|
||||
// batch mode, when we're going to exit anyway.
|
||||
if (!isRenderingToMain() && isHidden() && !QtHost::InBatchMode())
|
||||
updateWindowState(true);
|
||||
|
||||
// Now we can actually shut down the VM.
|
||||
g_emu_thread->shutdownSystem(save_state);
|
||||
|
||||
if (block_until_done || m_is_closing || QtHost::InBatchMode())
|
||||
{
|
||||
// We need to yield here, since the display gets destroyed.
|
||||
while (s_system_valid || System::GetState() != System::State::Shutdown)
|
||||
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
|
||||
}
|
||||
|
||||
if (!m_is_closing && QtHost::InBatchMode())
|
||||
{
|
||||
// Closing the window should shut down everything. If we don't set the closing flag here,
|
||||
// the VM shutdown may not complete by the time closeEvent() is called, leading to a confirm.
|
||||
m_is_closing = true;
|
||||
close();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainWindow::requestExit()
|
||||
{
|
||||
// this is block, because otherwise closeEvent() will also prompt
|
||||
if (!requestShutdown(true, true, true))
|
||||
return;
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
void MainWindow::checkForSettingChanges()
|
||||
{
|
||||
if (m_display_widget)
|
||||
m_display_widget->updateRelativeMode(s_system_valid && !s_system_paused);
|
||||
|
||||
updateWindowState();
|
||||
}
|
||||
|
||||
void MainWindow::onCheckForUpdatesActionTriggered()
|
||||
{
|
||||
// Wipe out the last version, that way it displays the update if we've previously skipped it.
|
||||
|
@ -2226,7 +2398,7 @@ void MainWindow::onToolsCheatManagerTriggered()
|
|||
|
||||
void MainWindow::openCPUDebugger()
|
||||
{
|
||||
g_emu_thread->pauseSystem(true, true);
|
||||
g_emu_thread->setSystemPaused(true, true);
|
||||
if (!System::IsValid())
|
||||
return;
|
||||
|
||||
|
@ -2299,3 +2471,49 @@ void MainWindow::onUpdateCheckComplete()
|
|||
m_auto_updater_dialog->deleteLater();
|
||||
m_auto_updater_dialog = nullptr;
|
||||
}
|
||||
|
||||
MainWindow::SystemLock MainWindow::pauseAndLockSystem()
|
||||
{
|
||||
const bool was_fullscreen = isRenderingFullscreen();
|
||||
const bool was_paused = s_system_paused;
|
||||
|
||||
// We use surfaceless rather than switching out of fullscreen, because
|
||||
// we're paused, so we're not going to be rendering anyway.
|
||||
if (was_fullscreen)
|
||||
g_emu_thread->setSurfaceless(true);
|
||||
if (!was_paused)
|
||||
g_emu_thread->setSystemPaused(true);
|
||||
|
||||
// We want to parent dialogs to the display widget, except if we were fullscreen,
|
||||
// since it's going to get destroyed by the surfaceless call above.
|
||||
QWidget* dialog_parent = was_fullscreen ? static_cast<QWidget*>(this) : getDisplayContainer();
|
||||
|
||||
return SystemLock(dialog_parent, was_paused, was_fullscreen);
|
||||
}
|
||||
|
||||
MainWindow::SystemLock::SystemLock(QWidget* dialog_parent, bool was_paused, bool was_fullscreen)
|
||||
: m_dialog_parent(dialog_parent), m_was_paused(was_paused), m_was_fullscreen(was_fullscreen)
|
||||
{
|
||||
}
|
||||
|
||||
MainWindow::SystemLock::SystemLock(SystemLock&& lock)
|
||||
: m_dialog_parent(lock.m_dialog_parent), m_was_paused(lock.m_was_paused), m_was_fullscreen(lock.m_was_fullscreen)
|
||||
{
|
||||
lock.m_dialog_parent = nullptr;
|
||||
lock.m_was_paused = true;
|
||||
lock.m_was_fullscreen = false;
|
||||
}
|
||||
|
||||
MainWindow::SystemLock::~SystemLock()
|
||||
{
|
||||
if (m_was_fullscreen)
|
||||
g_emu_thread->setSurfaceless(false);
|
||||
if (!m_was_paused)
|
||||
g_emu_thread->setSystemPaused(false);
|
||||
}
|
||||
|
||||
void MainWindow::SystemLock::cancelResume()
|
||||
{
|
||||
m_was_paused = true;
|
||||
m_was_fullscreen = false;
|
||||
}
|
||||
|
|
|
@ -16,15 +16,16 @@ class QThread;
|
|||
class QProgressBar;
|
||||
|
||||
class GameListWidget;
|
||||
class QtHostInterface;
|
||||
class EmuThread;
|
||||
class AutoUpdaterDialog;
|
||||
class MemoryCardEditorDialog;
|
||||
class CheatManagerDialog;
|
||||
class DebuggerWindow;
|
||||
class MainWindow;
|
||||
|
||||
class HostDisplay;
|
||||
namespace GameList {
|
||||
struct GameListEntry;
|
||||
struct Entry;
|
||||
}
|
||||
|
||||
class GDBServer;
|
||||
|
@ -33,12 +34,39 @@ class MainWindow final : public QMainWindow
|
|||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/// This class is a scoped lock on the VM, which prevents it from running while
|
||||
/// the object exists. Its purpose is to be used for blocking/modal popup boxes,
|
||||
/// where the VM needs to exit fullscreen temporarily.
|
||||
class SystemLock
|
||||
{
|
||||
public:
|
||||
SystemLock(SystemLock&& lock);
|
||||
SystemLock(const SystemLock&) = delete;
|
||||
~SystemLock();
|
||||
|
||||
/// Returns the parent widget, which can be used for any popup dialogs.
|
||||
ALWAYS_INLINE QWidget* getDialogParent() const { return m_dialog_parent; }
|
||||
|
||||
/// Cancels any pending unpause/fullscreen transition.
|
||||
/// Call when you're going to destroy the VM anyway.
|
||||
void cancelResume();
|
||||
|
||||
private:
|
||||
SystemLock(QWidget* dialog_parent, bool was_paused, bool was_fullscreen);
|
||||
friend MainWindow;
|
||||
|
||||
QWidget* m_dialog_parent;
|
||||
bool m_was_paused;
|
||||
bool m_was_fullscreen;
|
||||
};
|
||||
|
||||
public:
|
||||
explicit MainWindow();
|
||||
~MainWindow();
|
||||
|
||||
/// Initializes the window. Call once at startup.
|
||||
void initializeAndShow();
|
||||
void initialize();
|
||||
|
||||
/// Performs update check if enabled in settings.
|
||||
void startupUpdateCheck();
|
||||
|
@ -49,11 +77,20 @@ public:
|
|||
/// Updates the state of the controls which should be disabled by achievements challenge mode.
|
||||
void onAchievementsChallengeModeToggled(bool enabled);
|
||||
|
||||
/// Locks the VM by pausing it, while a popup dialog is displayed.
|
||||
SystemLock pauseAndLockSystem();
|
||||
|
||||
public Q_SLOTS:
|
||||
/// Updates debug menu visibility (hides if disabled).
|
||||
void updateDebugMenuVisibility();
|
||||
|
||||
void refreshGameList(bool invalidate_cache);
|
||||
|
||||
void runOnUIThread(const std::function<void()>& func);
|
||||
bool requestShutdown(bool allow_confirm = true, bool allow_save_to_state = true, bool block_until_done = false);
|
||||
void requestExit();
|
||||
void checkForSettingChanges();
|
||||
|
||||
void checkForUpdates(bool display_message);
|
||||
|
||||
private Q_SLOTS:
|
||||
|
@ -158,7 +195,7 @@ private:
|
|||
bool shouldHideCursorInFullscreen() const;
|
||||
|
||||
SettingsDialog* getSettingsDialog();
|
||||
void doSettings(SettingsDialog::Category category = SettingsDialog::Category::Count);
|
||||
void doSettings(const char* category = nullptr);
|
||||
|
||||
ControllerSettingsDialog* getControllerSettingsDialog();
|
||||
void doControllerSettings(ControllerSettingsDialog::Category category = ControllerSettingsDialog::Category::Count);
|
||||
|
@ -171,8 +208,11 @@ private:
|
|||
void setGameListEntryCoverImage(const GameList::Entry* entry);
|
||||
void recreate();
|
||||
|
||||
std::optional<bool> promptForResumeState(const QString& save_state_path);
|
||||
void startGameListEntry(const GameList::Entry* entry, std::optional<s32> save_slot, std::optional<bool> fast_boot);
|
||||
/// Fills menu with save state info and handlers.
|
||||
void populateGameListContextMenu(const GameList::Entry* entry, QWidget* parent_window, QMenu* menu);
|
||||
|
||||
std::optional<bool> promptForResumeState(const std::string& save_state_path);
|
||||
void startGameListEntry(const GameList::Entry* entry, std::optional<std::string> save_path, std::optional<bool> fast_boot);
|
||||
|
||||
Ui::MainWindow m_ui;
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>754</width>
|
||||
<width>800</width>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -38,7 +38,8 @@
|
|||
<string>Change Disc</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="ChangeDisc"/>
|
||||
<iconset theme="ChangeDisc">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<actiongroup name="actionGroupChangeDiscSubImages"/>
|
||||
<addaction name="actionChangeDiscFromFile"/>
|
||||
|
@ -52,7 +53,8 @@
|
|||
<string>Cheats</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="Cheats"/>
|
||||
<iconset theme="Cheats">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuLoadState">
|
||||
|
@ -60,7 +62,8 @@
|
|||
<string>Load State</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="LoadState"/>
|
||||
<iconset theme="LoadState">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuSaveState">
|
||||
|
@ -68,7 +71,8 @@
|
|||
<string>Save State</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="SaveState"/>
|
||||
<iconset theme="SaveState">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
<addaction name="actionStartFile"/>
|
||||
|
@ -99,28 +103,36 @@
|
|||
<property name="title">
|
||||
<string>Theme</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="Clear"/>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuSettingsLanguage">
|
||||
<property name="title">
|
||||
<string>Language</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="Language"/>
|
||||
</property>
|
||||
</widget>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionGeneralSettings"/>
|
||||
<addaction name="actionGameListSettings"/>
|
||||
<addaction name="actionBIOSSettings"/>
|
||||
<addaction name="actionConsoleSettings"/>
|
||||
<addaction name="actionEmulationSettings"/>
|
||||
<addaction name="actionGameListSettings"/>
|
||||
<addaction name="actionHotkeySettings"/>
|
||||
<addaction name="actionControllerSettings"/>
|
||||
<addaction name="actionMemoryCardSettings"/>
|
||||
<addaction name="actionDisplaySettings"/>
|
||||
<addaction name="actionEnhancementSettings"/>
|
||||
<addaction name="actionPostProcessingSettings"/>
|
||||
<addaction name="actionAudioSettings"/>
|
||||
<addaction name="actionAchievementSettings"/>
|
||||
<addaction name="actionFolderSettings"/>
|
||||
<addaction name="actionAdvancedSettings"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionControllerSettings"/>
|
||||
<addaction name="actionHotkeySettings"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionAddGameDirectory"/>
|
||||
<addaction name="actionScanForNewGames"/>
|
||||
<addaction name="actionRescanAllGames"/>
|
||||
|
@ -266,7 +278,8 @@
|
|||
<widget class="QStatusBar" name="statusBar"/>
|
||||
<action name="actionStartFile">
|
||||
<property name="icon">
|
||||
<iconset theme="StartfileSettings"/>
|
||||
<iconset theme="StartfileSettings">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Start &File...</string>
|
||||
|
@ -274,7 +287,8 @@
|
|||
</action>
|
||||
<action name="actionStartDisc">
|
||||
<property name="icon">
|
||||
<iconset theme="StartdiscSettings"/>
|
||||
<iconset theme="StartdiscSettings">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Start &Disc...</string>
|
||||
|
@ -282,7 +296,8 @@
|
|||
</action>
|
||||
<action name="actionStartBios">
|
||||
<property name="icon">
|
||||
<iconset theme="BIOSSettings"/>
|
||||
<iconset theme="BIOSSettings">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Start &BIOS</string>
|
||||
|
@ -290,7 +305,8 @@
|
|||
</action>
|
||||
<action name="actionScanForNewGames">
|
||||
<property name="icon">
|
||||
<iconset theme="ScanForGames"/>
|
||||
<iconset theme="ScanForGames">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Scan For New Games</string>
|
||||
|
@ -298,7 +314,8 @@
|
|||
</action>
|
||||
<action name="actionRescanAllGames">
|
||||
<property name="icon">
|
||||
<iconset theme="RescanAllGames"/>
|
||||
<iconset theme="RescanAllGames">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Rescan All Games</string>
|
||||
|
@ -306,7 +323,8 @@
|
|||
</action>
|
||||
<action name="actionPowerOff">
|
||||
<property name="icon">
|
||||
<iconset theme="PowerOff"/>
|
||||
<iconset theme="PowerOff">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Power &Off</string>
|
||||
|
@ -314,7 +332,8 @@
|
|||
</action>
|
||||
<action name="actionReset">
|
||||
<property name="icon">
|
||||
<iconset theme="Reset"/>
|
||||
<iconset theme="Reset">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Reset</string>
|
||||
|
@ -325,7 +344,8 @@
|
|||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="Pause"/>
|
||||
<iconset theme="Pause">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Pause</string>
|
||||
|
@ -333,7 +353,8 @@
|
|||
</action>
|
||||
<action name="actionLoadState">
|
||||
<property name="icon">
|
||||
<iconset theme="LoadState"/>
|
||||
<iconset theme="LoadState">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Load State</string>
|
||||
|
@ -341,7 +362,8 @@
|
|||
</action>
|
||||
<action name="actionSaveState">
|
||||
<property name="icon">
|
||||
<iconset theme="SaveState"/>
|
||||
<iconset theme="SaveState">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Save State</string>
|
||||
|
@ -349,7 +371,8 @@
|
|||
</action>
|
||||
<action name="actionExit">
|
||||
<property name="icon">
|
||||
<iconset theme="Exit"/>
|
||||
<iconset theme="Exit">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>E&xit</string>
|
||||
|
@ -357,71 +380,80 @@
|
|||
</action>
|
||||
<action name="actionBIOSSettings">
|
||||
<property name="icon">
|
||||
<iconset theme="BIOSSettings"/>
|
||||
<iconset theme="BIOSSettings">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>B&IOS Settings...</string>
|
||||
<string>B&IOS</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionConsoleSettings">
|
||||
<property name="icon">
|
||||
<iconset theme="ConsoleSettings"/>
|
||||
<iconset theme="ConsoleSettings">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>C&onsole Settings...</string>
|
||||
<string>C&onsole</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionEmulationSettings">
|
||||
<property name="icon">
|
||||
<iconset theme="EmulationSettings"/>
|
||||
<iconset theme="EmulationSettings">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>E&mulation Settings...</string>
|
||||
<string>E&mulation</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionControllerSettings">
|
||||
<property name="icon">
|
||||
<iconset theme="ControllerSettings"/>
|
||||
<iconset theme="ControllerSettings">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Controller Settings...</string>
|
||||
<string>&Controllers</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionHotkeySettings">
|
||||
<property name="icon">
|
||||
<iconset theme="HotkeySettings"/>
|
||||
<iconset theme="HotkeySettings">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Hotkey Settings...</string>
|
||||
<string>&Hotkeys</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDisplaySettings">
|
||||
<property name="icon">
|
||||
<iconset theme="DisplaySettings"/>
|
||||
<iconset theme="DisplaySettings">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Display Settings...</string>
|
||||
<string>&Display</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionEnhancementSettings">
|
||||
<property name="icon">
|
||||
<iconset theme="EnhancementSettings"/>
|
||||
<iconset theme="EnhancementSettings">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Enhancement Settings...</string>
|
||||
<string>&Enhancements</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionPostProcessingSettings">
|
||||
<property name="icon">
|
||||
<iconset theme="PostprocessingSettings"/>
|
||||
<iconset theme="PostprocessingSettings">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Post-Processing Settings...</string>
|
||||
<string>&Post-Processing</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionFullscreen">
|
||||
<property name="icon">
|
||||
<iconset theme="Fullscreen"/>
|
||||
<iconset theme="Fullscreen">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Fullscreen</string>
|
||||
|
@ -488,7 +520,8 @@
|
|||
</action>
|
||||
<action name="actionChangeDisc">
|
||||
<property name="icon">
|
||||
<iconset theme="ChangeDisc"/>
|
||||
<iconset theme="ChangeDisc">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Change Disc...</string>
|
||||
|
@ -496,7 +529,8 @@
|
|||
</action>
|
||||
<action name="actionCheats">
|
||||
<property name="icon">
|
||||
<iconset theme="Cheats"/>
|
||||
<iconset theme="Cheats">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Cheats...</string>
|
||||
|
@ -504,47 +538,62 @@
|
|||
</action>
|
||||
<action name="actionAudioSettings">
|
||||
<property name="icon">
|
||||
<iconset theme="AudioSettings"/>
|
||||
<iconset theme="AudioSettings">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Audio Settings...</string>
|
||||
<string>Audio</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAchievementSettings">
|
||||
<property name="icon">
|
||||
<iconset theme="AchievementsSettings"/>
|
||||
<iconset theme="AchievementsSettings">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Achievement Settings...</string>
|
||||
<string>Achievements</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionFolderSettings">
|
||||
<property name="icon">
|
||||
<iconset theme="Options">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Folders</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionGameListSettings">
|
||||
<property name="icon">
|
||||
<iconset theme="GamelistSettings"/>
|
||||
<iconset theme="GamelistSettings">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Game List Settings...</string>
|
||||
<string>Game List</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionGeneralSettings">
|
||||
<property name="icon">
|
||||
<iconset theme="GeneralSettings"/>
|
||||
<iconset theme="GeneralSettings">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>General Settings...</string>
|
||||
<string>General</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAdvancedSettings">
|
||||
<property name="icon">
|
||||
<iconset theme="AdvancedSettings"/>
|
||||
<iconset theme="AdvancedSettings">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Advanced Settings...</string>
|
||||
<string>Advanced</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAddGameDirectory">
|
||||
<property name="icon">
|
||||
<iconset theme="AddGameDirectory"/>
|
||||
<iconset theme="AddGameDirectory">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add Game Directory...</string>
|
||||
|
@ -552,7 +601,8 @@
|
|||
</action>
|
||||
<action name="actionSettings">
|
||||
<property name="icon">
|
||||
<iconset theme="GeneralSettings"/>
|
||||
<iconset theme="GeneralSettings">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Settings...</string>
|
||||
|
@ -709,7 +759,8 @@
|
|||
</action>
|
||||
<action name="actionScreenshot">
|
||||
<property name="icon">
|
||||
<iconset theme="Screenshot"/>
|
||||
<iconset theme="Screenshot">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Screenshot</string>
|
||||
|
@ -717,15 +768,17 @@
|
|||
</action>
|
||||
<action name="actionMemoryCardSettings">
|
||||
<property name="icon">
|
||||
<iconset theme="MemorycardSettings"/>
|
||||
<iconset theme="MemorycardSettings">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Memory Card Settings...</string>
|
||||
<string>&Memory Cards</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionResumeLastState">
|
||||
<property name="icon">
|
||||
<iconset theme="Resume"/>
|
||||
<iconset theme="Resume">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Resume</string>
|
||||
|
@ -769,7 +822,8 @@
|
|||
</action>
|
||||
<action name="actionViewGameList">
|
||||
<property name="icon">
|
||||
<iconset theme="GameList"/>
|
||||
<iconset theme="GameList">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Game &List</string>
|
||||
|
@ -808,7 +862,8 @@
|
|||
</action>
|
||||
<action name="actionViewGameGrid">
|
||||
<property name="icon">
|
||||
<iconset theme="GameGrid"/>
|
||||
<iconset theme="GameGrid">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Game &Grid</string>
|
||||
|
@ -858,7 +913,8 @@
|
|||
</action>
|
||||
<action name="actionPowerOffWithoutSaving">
|
||||
<property name="icon">
|
||||
<iconset theme="PoweroffWsaving"/>
|
||||
<iconset theme="PoweroffWsaving">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Power Off &Without Saving</string>
|
||||
|
@ -866,7 +922,7 @@
|
|||
</action>
|
||||
<action name="actionStartFullscreenUI">
|
||||
<property name="icon">
|
||||
<iconset theme="tv-2-line">
|
||||
<iconset theme="DisplaySettings">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
|
@ -875,7 +931,7 @@
|
|||
</action>
|
||||
<action name="actionStartFullscreenUI2">
|
||||
<property name="icon">
|
||||
<iconset theme="tv-2-line">
|
||||
<iconset theme="DisplaySettings">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
|
|
|
@ -128,8 +128,8 @@ void MemoryCardSettingsWidget::createPortSettingsUi(SettingsDialog* dialog, int
|
|||
|
||||
QHBoxLayout* memory_card_layout = new QHBoxLayout();
|
||||
ui->memory_card_path = new QLineEdit(ui->container);
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(m_dialog->getSettingsInterface(), ui->memory_card_path, "MemoryCards",
|
||||
StringUtil::StdStringFromFormat("Card%dPath", index + 1));
|
||||
updateMemoryCardPath(index);
|
||||
connect(ui->memory_card_path, &QLineEdit::textChanged, this, [this, index]() { onMemoryCardPathChanged(index); });
|
||||
if (ui->memory_card_path->text().isEmpty())
|
||||
{
|
||||
QSignalBlocker sb(ui->memory_card_path);
|
||||
|
@ -138,11 +138,13 @@ void MemoryCardSettingsWidget::createPortSettingsUi(SettingsDialog* dialog, int
|
|||
memory_card_layout->addWidget(ui->memory_card_path);
|
||||
|
||||
QPushButton* memory_card_path_browse = new QPushButton(tr("Browse..."), ui->container);
|
||||
connect(memory_card_path_browse, &QPushButton::clicked, [this, index]() { onBrowseMemoryCardPathClicked(index); });
|
||||
connect(memory_card_path_browse, &QPushButton::clicked, this,
|
||||
[this, index]() { onBrowseMemoryCardPathClicked(index); });
|
||||
memory_card_layout->addWidget(memory_card_path_browse);
|
||||
|
||||
QPushButton* memory_card_path_reset = new QPushButton(tr("Reset"), ui->container);
|
||||
connect(memory_card_path_reset, &QPushButton::clicked, [this, index]() { onResetMemoryCardPathClicked(index); });
|
||||
connect(memory_card_path_reset, &QPushButton::clicked, this,
|
||||
[this, index]() { onResetMemoryCardPathClicked(index); });
|
||||
memory_card_layout->addWidget(memory_card_path_reset);
|
||||
|
||||
ui->layout->addWidget(new QLabel(tr("Shared Memory Card Path:"), ui->container));
|
||||
|
@ -161,14 +163,33 @@ void MemoryCardSettingsWidget::onBrowseMemoryCardPathClicked(int index)
|
|||
m_port_ui[index].memory_card_path->setText(path);
|
||||
}
|
||||
|
||||
void MemoryCardSettingsWidget::onMemoryCardPathChanged(int index)
|
||||
{
|
||||
const auto key = TinyString::FromFormat("Card%dPath", index + 1);
|
||||
std::string relative_path(
|
||||
Path::MakeRelative(m_port_ui[index].memory_card_path->text().toStdString(), EmuFolders::MemoryCards));
|
||||
m_dialog->setStringSettingValue("MemoryCards", key, relative_path.c_str());
|
||||
}
|
||||
|
||||
void MemoryCardSettingsWidget::onResetMemoryCardPathClicked(int index)
|
||||
{
|
||||
m_dialog->removeSettingValue("MemoryCards", TinyString::FromFormat("Card%dPath", index + 1));
|
||||
const auto key = TinyString::FromFormat("Card%dPath", index + 1);
|
||||
if (m_dialog->isPerGameSettings())
|
||||
m_dialog->removeSettingValue("MemoryCards", key);
|
||||
else
|
||||
m_dialog->setStringSettingValue("MemoryCards", key, Settings::GetDefaultSharedMemoryCardName(index).c_str());
|
||||
|
||||
Panic("Fixme");
|
||||
#if 0
|
||||
QSignalBlocker db(m_port_ui[index].memory_card_path);
|
||||
m_port_ui[index].memory_card_path->setText(
|
||||
QString::fromStdString(g_emu_thread->GetSharedMemoryCardPath(index)));
|
||||
#endif
|
||||
updateMemoryCardPath(index);
|
||||
}
|
||||
|
||||
void MemoryCardSettingsWidget::updateMemoryCardPath(int index)
|
||||
{
|
||||
const auto key = TinyString::FromFormat("Card%dPath", index + 1);
|
||||
std::string path(
|
||||
m_dialog->getEffectiveStringValue("MemoryCards", key, Settings::GetDefaultSharedMemoryCardName(index).c_str()));
|
||||
if (!Path::IsAbsolute(path))
|
||||
path = Path::Combine(EmuFolders::MemoryCards, path);
|
||||
|
||||
QSignalBlocker db(m_port_ui[index].memory_card_path);
|
||||
m_port_ui[index].memory_card_path->setText(QString::fromStdString(path));
|
||||
}
|
||||
|
|
|
@ -33,6 +33,8 @@ private:
|
|||
void createPortSettingsUi(SettingsDialog* dialog, int index, PortSettingsUI* ui);
|
||||
void onBrowseMemoryCardPathClicked(int index);
|
||||
void onResetMemoryCardPathClicked(int index);
|
||||
void onMemoryCardPathChanged(int index);
|
||||
void updateMemoryCardPath(int index);
|
||||
|
||||
std::array<PortSettingsUI, 2> m_port_ui = {};
|
||||
QLineEdit* m_memory_card_directory = nullptr;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#pragma once
|
||||
#include "common/event.h"
|
||||
#include "core/host.h"
|
||||
#include "core/host_settings.h"
|
||||
#include "core/system.h"
|
||||
|
@ -9,6 +8,7 @@
|
|||
#include "qtutils.h"
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QSemaphore>
|
||||
#include <QtCore/QSettings>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QThread>
|
||||
|
@ -40,50 +40,35 @@ Q_DECLARE_METATYPE(std::shared_ptr<SystemBootParameters>);
|
|||
Q_DECLARE_METATYPE(GPURenderer);
|
||||
Q_DECLARE_METATYPE(InputBindingKey);
|
||||
|
||||
class QtHostInterface final : public QObject
|
||||
class EmuThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QtHostInterface(QObject* parent = nullptr);
|
||||
~QtHostInterface();
|
||||
explicit EmuThread(QThread* ui_thread);
|
||||
~EmuThread();
|
||||
|
||||
bool Initialize();
|
||||
void Shutdown();
|
||||
static void start();
|
||||
static void stop();
|
||||
|
||||
void RunLater(std::function<void()> func);
|
||||
ALWAYS_INLINE bool isOnThread() const { return QThread::currentThread() == this; }
|
||||
|
||||
public:
|
||||
ALWAYS_INLINE void requestExit() { RequestExit(); }
|
||||
|
||||
ALWAYS_INLINE bool isOnWorkerThread() const { return QThread::currentThread() == m_worker_thread; }
|
||||
|
||||
ALWAYS_INLINE QEventLoop* getEventLoop() const { return m_worker_thread_event_loop; }
|
||||
ALWAYS_INLINE QEventLoop* getEventLoop() const { return m_event_loop; }
|
||||
|
||||
ALWAYS_INLINE bool isFullscreen() const { return m_is_fullscreen; }
|
||||
ALWAYS_INLINE bool isRenderingToMain() const { return m_is_rendering_to_main; }
|
||||
ALWAYS_INLINE bool isSurfaceless() const { return m_is_surfaceless; }
|
||||
ALWAYS_INLINE bool isRunningFullscreenUI() const { return m_run_fullscreen_ui; }
|
||||
|
||||
void reinstallTranslator();
|
||||
|
||||
void populateLoadStateMenu(const char* game_code, QMenu* menu);
|
||||
void populateSaveStateMenu(const char* game_code, QMenu* menu);
|
||||
|
||||
/// Fills menu with save state info and handlers.
|
||||
void populateGameListContextMenu(const GameList::Entry* entry, QWidget* parent_window, QMenu* menu);
|
||||
|
||||
/// Fills menu with the current playlist entries. The disc index is marked as checked.
|
||||
void populateChangeDiscSubImageMenu(QMenu* menu, QActionGroup* action_group);
|
||||
|
||||
/// Fills menu with the current cheat options.
|
||||
void populateCheatsMenu(QMenu* menu);
|
||||
|
||||
void saveInputProfile(const QString& profile_path);
|
||||
|
||||
/// Returns a list of supported languages and codes (suffixes for translation files).
|
||||
static std::vector<std::pair<QString, QString>> getAvailableLanguageList();
|
||||
|
||||
/// Called back from the GS thread when the display state changes (e.g. fullscreen, render to main).
|
||||
HostDisplay* acquireHostDisplay();
|
||||
void connectDisplaySignals(DisplayWidget* widget);
|
||||
|
@ -94,6 +79,13 @@ public:
|
|||
void stopBackgroundControllerPollTimer();
|
||||
void wakeThread();
|
||||
|
||||
bool shouldRenderToMain() const;
|
||||
void loadSettings(SettingsInterface& si);
|
||||
void setInitialState();
|
||||
void checkForSettingsChanges(const Settings& old_settings);
|
||||
|
||||
void bootOrLoadState(std::string path);
|
||||
|
||||
Q_SIGNALS:
|
||||
void errorReported(const QString& title, const QString& message);
|
||||
bool messageConfirmed(const QString& title, const QString& message);
|
||||
|
@ -118,7 +110,6 @@ Q_SIGNALS:
|
|||
GPURenderer renderer, quint32 render_width, quint32 render_height,
|
||||
bool render_interlaced);
|
||||
void runningGameChanged(const QString& filename, const QString& game_code, const QString& game_title);
|
||||
void exitRequested();
|
||||
void inputProfileLoaded();
|
||||
void mouseModeRequested(bool relative, bool hide_cursor);
|
||||
void achievementsLoaded(quint32 id, const QString& game_info_string, quint32 total, quint32 points);
|
||||
|
@ -127,20 +118,16 @@ Q_SIGNALS:
|
|||
public Q_SLOTS:
|
||||
void setDefaultSettings();
|
||||
void applySettings(bool display_osd_messages = false);
|
||||
void reloadGameSettings();
|
||||
void applyInputProfile(const QString& profile_path);
|
||||
void reloadGameSettings(bool display_osd_messages = false);
|
||||
void reloadInputSources();
|
||||
void reloadInputBindings();
|
||||
void enumerateInputDevices();
|
||||
void enumerateVibrationMotors();
|
||||
void bootSystem(std::shared_ptr<SystemBootParameters> params);
|
||||
void resumeSystemFromState(const QString& filename, bool boot_on_failure);
|
||||
void resumeSystemFromMostRecentState();
|
||||
void powerOffSystem();
|
||||
void powerOffSystemWithoutSaving();
|
||||
void synchronousPowerOffSystem();
|
||||
void shutdownSystem(bool save_state = true);
|
||||
void resetSystem();
|
||||
void pauseSystem(bool paused, bool wait_until_paused = false);
|
||||
void setSystemPaused(bool paused, bool wait_until_paused = false);
|
||||
void changeDisc(const QString& new_disc_filename);
|
||||
void changeDiscFromPlaylist(quint32 index);
|
||||
void loadState(const QString& filename);
|
||||
|
@ -161,81 +148,40 @@ public Q_SLOTS:
|
|||
void toggleFullscreen();
|
||||
void setFullscreen(bool fullscreen);
|
||||
void setSurfaceless(bool surfaceless);
|
||||
void requestDisplaySize(float scale);
|
||||
void loadCheatList(const QString& filename);
|
||||
void setCheatEnabled(quint32 index, bool enabled);
|
||||
void applyCheat(quint32 index);
|
||||
void reloadPostProcessingShaders();
|
||||
void requestRenderWindowScale(qreal scale);
|
||||
void executeOnEmulationThread(std::function<void()> callback, bool wait = false);
|
||||
|
||||
private Q_SLOTS:
|
||||
void doStopThread();
|
||||
void stopInThread();
|
||||
void onDisplayWindowMouseMoveEvent(bool relative, float x, float y);
|
||||
void onDisplayWindowMouseButtonEvent(int button, bool pressed);
|
||||
void onDisplayWindowMouseWheelEvent(const QPoint& delta_angle);
|
||||
void onDisplayWindowResized(int width, int height);
|
||||
void onDisplayWindowKeyEvent(int key, bool pressed);
|
||||
void doBackgroundControllerPoll();
|
||||
void runOnEmuThread(std::function<void()> callback);
|
||||
|
||||
protected:
|
||||
bool IsFullscreen() const;
|
||||
bool SetFullscreen(bool enabled);
|
||||
|
||||
void RequestExit();
|
||||
void run() override;
|
||||
|
||||
private:
|
||||
enum : u32
|
||||
{
|
||||
BACKGROUND_CONTROLLER_POLLING_INTERVAL =
|
||||
100, /// Interval at which the controllers are polled when the system is not active.
|
||||
};
|
||||
|
||||
using InputButtonHandler = std::function<void(bool)>;
|
||||
using InputAxisHandler = std::function<void(float)>;
|
||||
|
||||
class Thread : public QThread
|
||||
{
|
||||
public:
|
||||
Thread(QtHostInterface* parent);
|
||||
~Thread();
|
||||
|
||||
void setInitResult(bool result);
|
||||
bool waitForInit();
|
||||
|
||||
protected:
|
||||
void run() override;
|
||||
|
||||
private:
|
||||
QtHostInterface* m_parent;
|
||||
std::atomic_bool m_init_result{false};
|
||||
Common::Event m_init_event;
|
||||
};
|
||||
|
||||
void createBackgroundControllerPollTimer();
|
||||
void destroyBackgroundControllerPollTimer();
|
||||
|
||||
void setImGuiFont();
|
||||
|
||||
void createThread();
|
||||
void stopThread();
|
||||
void threadEntryPoint();
|
||||
bool initializeOnThread();
|
||||
void shutdownOnThread();
|
||||
void installTranslator();
|
||||
void checkRenderToMainState();
|
||||
void updateDisplayState();
|
||||
void queueSettingsSave();
|
||||
|
||||
QThread* m_original_thread = nullptr;
|
||||
Thread* m_worker_thread = nullptr;
|
||||
QEventLoop* m_worker_thread_event_loop = nullptr;
|
||||
Common::Event m_worker_thread_sync_execute_done;
|
||||
QThread* m_ui_thread;
|
||||
QSemaphore m_started_semaphore;
|
||||
QEventLoop* m_event_loop = nullptr;
|
||||
QTimer* m_background_controller_polling_timer = nullptr;
|
||||
|
||||
std::atomic_bool m_shutdown_flag{false};
|
||||
|
||||
QTimer* m_background_controller_polling_timer = nullptr;
|
||||
std::vector<QTranslator*> m_translators;
|
||||
|
||||
bool m_run_fullscreen_ui = false;
|
||||
bool m_is_rendering_to_main = false;
|
||||
bool m_is_fullscreen = false;
|
||||
|
@ -243,14 +189,19 @@ private:
|
|||
bool m_lost_exclusive_fullscreen = false;
|
||||
bool m_is_surfaceless = false;
|
||||
bool m_save_state_on_shutdown = false;
|
||||
bool m_pause_on_focus_loss = false;
|
||||
|
||||
bool m_was_paused_by_focus_loss = false;
|
||||
};
|
||||
|
||||
extern QtHostInterface* g_emu_thread;
|
||||
extern EmuThread* g_emu_thread;
|
||||
|
||||
namespace QtHost {
|
||||
/// Startup, creates the thread and loads config.
|
||||
bool Initialize();
|
||||
|
||||
/// Execute before exiting, stops the thread and saves settings.
|
||||
void Shutdown();
|
||||
|
||||
/// Sets batch mode (exit after game shutdown).
|
||||
bool InBatchMode();
|
||||
|
||||
|
@ -260,6 +211,12 @@ bool InNoGUIMode();
|
|||
/// Executes a function on the UI thread.
|
||||
void RunOnUIThread(const std::function<void()>& func, bool block = false);
|
||||
|
||||
/// Returns a list of supported languages and codes (suffixes for translation files).
|
||||
std::vector<std::pair<QString, QString>> GetAvailableLanguageList();
|
||||
|
||||
/// Call when the language changes.
|
||||
void ReinstallTranslator();
|
||||
|
||||
/// Returns the application name and version, optionally including debug/devel config indicator.
|
||||
QString GetAppNameAndVersion();
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include "qtutils.h"
|
||||
#include "common/byte_stream.h"
|
||||
#include "common/make_array.h"
|
||||
#include "core/system.h"
|
||||
#include "frontend-common/game_list.h"
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QMetaObject>
|
||||
#include <QtGui/QDesktopServices>
|
||||
|
@ -730,22 +732,6 @@ void FillComboBoxWithMSAAModes(QComboBox* cb)
|
|||
cb->addItem(qApp->translate("GPUSettingsWidget", "%1x SSAA").arg(i), GetMSAAModeValue(i, true));
|
||||
}
|
||||
|
||||
void FillComboBoxWithEmulationSpeeds(QComboBox* cb)
|
||||
{
|
||||
cb->addItem(qApp->translate("GeneralSettingsWidget", "Unlimited"), QVariant(0.0f));
|
||||
|
||||
static constexpr auto speeds = make_array(10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 125, 150, 175, 200, 250, 300, 350,
|
||||
400, 450, 500, 600, 700, 800, 900, 1000);
|
||||
for (const int speed : speeds)
|
||||
{
|
||||
cb->addItem(qApp->translate("GeneralSettingsWidget", "%1% [%2 FPS (NTSC) / %3 FPS (PAL)]")
|
||||
.arg(speed)
|
||||
.arg((60 * speed) / 100)
|
||||
.arg((50 * speed) / 100),
|
||||
QVariant(static_cast<float>(speed) / 100.0f));
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<unsigned> PromptForAddress(QWidget* parent, const QString& title, const QString& label, bool code)
|
||||
{
|
||||
const QString address_str(
|
||||
|
@ -823,4 +809,53 @@ void ResizePotentiallyFixedSizeWindow(QWidget* widget, int width, int height)
|
|||
|
||||
widget->resize(width, height);
|
||||
}
|
||||
|
||||
QIcon GetIconForRegion(ConsoleRegion region)
|
||||
{
|
||||
switch (region)
|
||||
{
|
||||
case ConsoleRegion::NTSC_J:
|
||||
return QIcon(QStringLiteral(":/icons/flag-jp.png"));
|
||||
case ConsoleRegion::PAL:
|
||||
return QIcon(QStringLiteral(":/icons/flag-eu.png"));
|
||||
case ConsoleRegion::NTSC_U:
|
||||
return QIcon(QStringLiteral(":/icons/flag-uc.png"));
|
||||
default:
|
||||
return QIcon(QStringLiteral(":/icons/applications-other.png"));
|
||||
}
|
||||
}
|
||||
|
||||
QIcon GetIconForRegion(DiscRegion region)
|
||||
{
|
||||
switch (region)
|
||||
{
|
||||
case DiscRegion::NTSC_J:
|
||||
return QIcon(QStringLiteral(":/icons/flag-jp.png"));
|
||||
case DiscRegion::PAL:
|
||||
return QIcon(QStringLiteral(":/icons/flag-eu.png"));
|
||||
case DiscRegion::NTSC_U:
|
||||
return QIcon(QStringLiteral(":/icons/flag-uc.png"));
|
||||
case DiscRegion::Other:
|
||||
default:
|
||||
return QIcon(QStringLiteral(":/icons/applications-other.png"));
|
||||
}
|
||||
}
|
||||
|
||||
QIcon GetIconForEntryType(GameList::EntryType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case GameList::EntryType::Disc:
|
||||
return QIcon(
|
||||
QStringLiteral(":/icons/media-optical-24.png")); // QIcon(QStringLiteral(":/icons/media-optical-gear-24.png"))
|
||||
case GameList::EntryType::Playlist:
|
||||
return QIcon(QStringLiteral(":/icons/address-book-new-22.png"));
|
||||
case GameList::EntryType::PSF:
|
||||
return QIcon(QStringLiteral(":/icons/multimedia-player.png"));
|
||||
case GameList::EntryType::PSExe:
|
||||
default:
|
||||
return QIcon(QStringLiteral(":/icons/applications-system-24.png"));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace QtUtils
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QMetaType>
|
||||
#include <QtCore/QString>
|
||||
#include <QtGui/QIcon>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <optional>
|
||||
|
@ -21,6 +22,12 @@ class QVariant;
|
|||
class QWidget;
|
||||
class QUrl;
|
||||
|
||||
enum class ConsoleRegion;
|
||||
enum class DiscRegion : u8;
|
||||
namespace GameList {
|
||||
enum class EntryType;
|
||||
}
|
||||
|
||||
namespace QtUtils {
|
||||
|
||||
/// Wheel delta is 120 as in winapi.
|
||||
|
@ -61,9 +68,6 @@ QVariant GetMSAAModeValue(uint multisamples, bool ssaa);
|
|||
void DecodeMSAAModeValue(const QVariant& userdata, uint* multisamples, bool* ssaa);
|
||||
void FillComboBoxWithMSAAModes(QComboBox* cb);
|
||||
|
||||
/// Fills a combo box with emulation speed options.
|
||||
void FillComboBoxWithEmulationSpeeds(QComboBox* cb);
|
||||
|
||||
/// Prompts for an address in hex.
|
||||
std::optional<unsigned> PromptForAddress(QWidget* parent, const QString& title, const QString& label, bool code);
|
||||
|
||||
|
@ -79,4 +83,11 @@ void SetWindowResizeable(QWidget* widget, bool resizeable);
|
|||
/// Adjusts the fixed size for a window if it's not resizeable.
|
||||
void ResizePotentiallyFixedSizeWindow(QWidget* widget, int width, int height);
|
||||
|
||||
/// Returns icon for region.
|
||||
QIcon GetIconForRegion(ConsoleRegion region);
|
||||
QIcon GetIconForRegion(DiscRegion region);
|
||||
|
||||
/// Returns icon for entry type.
|
||||
QIcon GetIconForEntryType(GameList::EntryType type);
|
||||
|
||||
} // namespace QtUtils
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M16.05 12.05L21 17l-4.95 4.95-1.414-1.414 2.536-2.537L4 18v-2h13.172l-2.536-2.536 1.414-1.414zm-8.1-10l1.414 1.414L6.828 6 20 6v2H6.828l2.536 2.536L7.95 11.95 3 7l4.95-4.95z" fill="#000000"/></svg>
|
Before Width: | Height: | Size: 326 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M8 8v8h8V8H8zM6 6h12v12H6V6zm0-4h2v3H6V2zm0 17h2v3H6v-3zM2 6h3v2H2V6zm0 10h3v2H2v-2zM19 6h3v2h-3V6zm0 10h3v2h-3v-2zM16 2h2v3h-2V2zm0 17h2v3h-2v-3z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 298 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M13 21v2h-2v-2H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h6a3.99 3.99 0 0 1 3 1.354A3.99 3.99 0 0 1 15 3h6a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1h-8zm7-2V5h-5a2 2 0 0 0-2 2v12h7zm-9 0V7a2 2 0 0 0-2-2H4v14h7z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 340 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M15.456 9.678l-.142-.142a5.475 5.475 0 0 0-2.39-1.349c-2.907-.778-5.699.869-6.492 3.83-.043.16-.066.34-.104.791-.154 1.87-.594 3.265-1.8 4.68 2.26.888 4.938 1.514 6.974 1.514a5.505 5.505 0 0 0 5.31-4.078 5.497 5.497 0 0 0-1.356-5.246zM13.29 6.216l4.939-3.841a1 1 0 0 1 1.32.082l2.995 2.994a1 1 0 0 1 .082 1.321l-3.84 4.938a7.505 7.505 0 0 1-7.283 9.292C8 21.002 3.5 19.5 1 18c3.98-3 3.047-4.81 3.5-6.5 1.058-3.95 4.842-6.257 8.789-5.284zm3.413 1.879c.065.063.13.128.193.194l1.135 1.134 2.475-3.182-1.746-1.746-3.182 2.475 1.125 1.125z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 686 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 280 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M13 21V11h8v10h-8zM3 13V3h8v10H3zm6-2V5H5v6h4zM3 21v-6h8v6H3zm2-2h4v-2H5v2zm10 0h4v-6h-4v6zM13 3h8v6h-8V3zm2 2v2h4V5h-4z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 272 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M15 4.582V12a3 3 0 1 1-2-2.83V2.05c5.053.501 9 4.765 9 9.95 0 5.523-4.477 10-10 10S2 17.523 2 12c0-5.185 3.947-9.449 9-9.95v2.012A8.001 8.001 0 0 0 12 20a8 8 0 0 0 3-15.418z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 325 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0H24V24H0z"/>
|
||||
<path d="M2 21v-2h2V4.835c0-.484.346-.898.821-.984l9.472-1.722c.326-.06.638.157.697.483.007.035.01.07.01.107v1.28L19 4c.552 0 1 .448 1 1v14h2v2h-4V6h-3v15H2zM13 4.396L6 5.67V19h7V4.396zM12 11v2h-2v-2h2z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 345 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M13 10h5l-6 6-6-6h5V3h2v7zm-9 9h16v-7h2v8a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1v-8h2v7z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 231 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16zm1-9h3l-5 7v-5H8l5-7v5z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 283 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M7.737 13h8.526L12 6.606 7.737 13zm4.679-9.376l7.066 10.599a.5.5 0 0 1-.416.777H4.934a.5.5 0 0 1-.416-.777l7.066-10.599a.5.5 0 0 1 .832 0zM5 17h14a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 329 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M15 4H5v16h14V8h-4V4zM3 2.992C3 2.444 3.447 2 3.999 2H16l5 5v13.993A1 1 0 0 1 20.007 22H3.993A1 1 0 0 1 3 21.008V2.992zM11 11V8h2v3h3v2h-3v3h-2v-3H8v-2h3z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 306 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M9 2.003V2h10.998C20.55 2 21 2.455 21 2.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 20.993V8l6-5.997zM5.83 8H9V4.83L5.83 8zM11 4v5a1 1 0 0 1-1 1H5v10h14V4h-8z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 319 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M20 22H4a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1zm-1-2V4H5v16h14zM8 7h8v2H8V7zm0 4h8v2H8v-2zm0 4h8v2H8v-2z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 282 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M15 4H5v16h14V8h-4V4zM3 2.992C3 2.444 3.447 2 3.999 2H16l5 5v13.993A1 1 0 0 1 20.007 22H3.993A1 1 0 0 1 3 21.008V2.992zM16 11v2H8v-2h8z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 287 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M15 4H5v16h14V8h-4V4zM3 2.992C3 2.444 3.447 2 3.999 2H16l5 5v13.993A1 1 0 0 1 20.007 22H3.993A1 1 0 0 1 3 21.008V2.992zm10.529 11.454a4.002 4.002 0 0 1-4.86-6.274 4 4 0 0 1 6.274 4.86l2.21 2.21-1.414 1.415-2.21-2.21zm-.618-2.032a2 2 0 1 0-2.828-2.828 2 2 0 0 0 2.828 2.828z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 425 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path fill-rule="nonzero" d="M8.595 12.812a3.51 3.51 0 0 1 0-1.623l-.992-.573 1-1.732.992.573A3.496 3.496 0 0 1 11 8.645V7.5h2v1.145c.532.158 1.012.44 1.405.812l.992-.573 1 1.732-.992.573a3.51 3.51 0 0 1 0 1.622l.992.573-1 1.732-.992-.573a3.496 3.496 0 0 1-1.405.812V16.5h-2v-1.145a3.496 3.496 0 0 1-1.405-.812l-.992.573-1-1.732.992-.572zM12 13.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zM15 4H5v16h14V8h-4V4zM3 2.992C3 2.444 3.447 2 3.999 2H16l5 5v13.993A1 1 0 0 1 20.007 22H3.993A1 1 0 0 1 3 21.008V2.992z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 645 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0H24V24H0z"/>
|
||||
<path d="M16 2v2h-1v3.243c0 1.158.251 2.301.736 3.352l4.282 9.276c.347.753.018 1.644-.734 1.99-.197.092-.411.139-.628.139H5.344c-.828 0-1.5-.672-1.5-1.5 0-.217.047-.432.138-.629l4.282-9.276C8.749 9.545 9 8.401 9 7.243V4H8V2h8zm-2.612 8.001h-2.776c-.104.363-.23.721-.374 1.071l-.158.361L6.125 20h11.749l-3.954-8.567c-.214-.464-.392-.943-.532-1.432zM11 7.243c0 .253-.01.506-.029.758h2.058c-.01-.121-.016-.242-.021-.364L13 7.243V4h-2v3.243z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 580 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M12.414 5H21a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h7.414l2 2zM4 5v14h16V7h-8.414l-2-2H4zm7 7V9h2v3h3v2h-3v3h-2v-3H8v-2h3z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 298 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M3 21a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h7.414l2 2H20a1 1 0 0 1 1 1v3h-2V7h-7.414l-2-2H4v11.998L5.5 11h17l-2.31 9.243a1 1 0 0 1-.97.757H3zm16.938-8H7.062l-1.5 6h12.876l1.5-6z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 321 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M12.414 5H21a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h7.414l2 2zM4 5v14h16V7h-8.414l-2-2H4zm4 7h8v2H8v-2z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 279 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M12.414 5H21a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h7.414l2 2zM4 5v14h16V7h-8.414l-2-2H4zm4.591 8.809a3.508 3.508 0 0 1 0-1.622l-.991-.572 1-1.732.991.573a3.495 3.495 0 0 1 1.404-.812V8.5h2v1.144c.532.159 1.01.44 1.403.812l.992-.573 1 1.731-.991.573a3.508 3.508 0 0 1 0 1.622l.991.572-1 1.731-.991-.572a3.495 3.495 0 0 1-1.404.811v1.145h-2V16.35a3.495 3.495 0 0 1-1.404-.811l-.991.572-1-1.73.991-.573zm3.404.688a1.5 1.5 0 1 0 0-2.998 1.5 1.5 0 0 0 0 2.998z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 632 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M20 3h2v6h-2V5h-4V3h4zM4 3h4v2H4v4H2V3h2zm16 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 234 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M3 3h8v8H3V3zm0 10h8v8H3v-8zM13 3h8v8h-8V3zm0 10h8v8h-8v-8zm2-8v4h4V5h-4zm0 10v4h4v-4h-4zM5 5v4h4V5H5zm0 10v4h4v-4H5z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 269 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path fill-rule="nonzero" d="M17 4a6 6 0 0 1 6 6v4a6 6 0 0 1-6 6H7a6 6 0 0 1-6-6v-4a6 6 0 0 1 6-6h10zm0 2H7a4 4 0 0 0-3.995 3.8L3 10v4a4 4 0 0 0 3.8 3.995L7 18h10a4 4 0 0 0 3.995-3.8L21 14v-4a4 4 0 0 0-3.8-3.995L17 6zm-7 3v2h2v2H9.999L10 15H8l-.001-2H6v-2h2V9h2zm8 4v2h-2v-2h2zm-2-4v2h-2V9h2z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 435 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M5 14h14V4H5v10zm0 2v4h14v-4H5zM4 2h16a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1zm11 15h2v2h-2v-2z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 271 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M3 17h18v2H3v-2zm0-6h3v3H3v-3zm5 0h3v3H8v-3zM3 5h3v3H3V5zm10 0h3v3h-3V5zm5 0h3v3h-3V5zm-5 6h3v3h-3v-3zm5 0h3v3h-3v-3zM8 5h3v3H8V5z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 282 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path fill-rule="nonzero" d="M21 3a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h18zM11 13H4v6h7v-6zm9 0h-7v6h7v-6zm-9-8H4v6h7V5zm9 0h-7v6h7V5z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 303 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M8 4h13v2H8V4zm-5-.5h3v3H3v-3zm0 7h3v3H3v-3zm0 7h3v3H3v-3zM8 11h13v2H8v-2zm0 7h13v2H8v-2z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 241 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M6 5h2v14H6V5zm10 0h2v14h-2V5z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 182 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M16.394 12L10 7.737v8.526L16.394 12zm2.982.416L8.777 19.482A.5.5 0 0 1 8 19.066V4.934a.5.5 0 0 1 .777-.416l10.599 7.066a.5.5 0 0 1 0 .832z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 290 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M5.463 4.433A9.961 9.961 0 0 1 12 2c5.523 0 10 4.477 10 10 0 2.136-.67 4.116-1.81 5.74L17 12h3A8 8 0 0 0 6.46 6.228l-.997-1.795zm13.074 15.134A9.961 9.961 0 0 1 12 22C6.477 22 2 17.523 2 12c0-2.136.67-4.116 1.81-5.74L7 12H4a8 8 0 0 0 13.54 5.772l.997 1.795z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 409 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M18.537 19.567A9.961 9.961 0 0 1 12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10c0 2.136-.67 4.116-1.81 5.74L17 12h3a8 8 0 1 0-2.46 5.772l.997 1.795z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 310 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M18 19h1V6.828L17.172 5H16v4H7V5H5v14h1v-7h12v7zM4 3h14l2.707 2.707a1 1 0 0 1 .293.707V20a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1zm4 11v5h8v-5H8z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 303 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M3 3h2v2H3V3zm4 0h2v2H7V3zm4 0h2v2h-2V3zm4 0h2v2h-2V3zm4 0h2v2h-2V3zm0 4h2v2h-2V7zM3 19h2v2H3v-2zm0-4h2v2H3v-2zm0-4h2v2H3v-2zm0-4h2v2H3V7zm7.667 4l1.036-1.555A1 1 0 0 1 12.535 9h2.93a1 1 0 0 1 .832.445L17.333 11H20a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1v-8a1 1 0 0 1 1-1h2.667zM9 19h10v-6h-2.737l-1.333-2h-1.86l-1.333 2H9v6zm5-1a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 516 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M6 7.828V20h12V4H9.828L6 7.828zm-1.707-1.12L9 2h10a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7.414a1 1 0 0 1 .293-.707zM15 5h2v4h-2V5zm-3 0h2v4h-2V5zM9 6h2v3H9V6z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 319 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M3.34 17a10.018 10.018 0 0 1-.978-2.326 3 3 0 0 0 .002-5.347A9.99 9.99 0 0 1 4.865 4.99a3 3 0 0 0 4.631-2.674 9.99 9.99 0 0 1 5.007.002 3 3 0 0 0 4.632 2.672c.579.59 1.093 1.261 1.525 2.01.433.749.757 1.53.978 2.326a3 3 0 0 0-.002 5.347 9.99 9.99 0 0 1-2.501 4.337 3 3 0 0 0-4.631 2.674 9.99 9.99 0 0 1-5.007-.002 3 3 0 0 0-4.632-2.672A10.018 10.018 0 0 1 3.34 17zm5.66.196a4.993 4.993 0 0 1 2.25 2.77c.499.047 1 .048 1.499.001A4.993 4.993 0 0 1 15 17.197a4.993 4.993 0 0 1 3.525-.565c.29-.408.54-.843.748-1.298A4.993 4.993 0 0 1 18 12c0-1.26.47-2.437 1.273-3.334a8.126 8.126 0 0 0-.75-1.298A4.993 4.993 0 0 1 15 6.804a4.993 4.993 0 0 1-2.25-2.77c-.499-.047-1-.048-1.499-.001A4.993 4.993 0 0 1 9 6.803a4.993 4.993 0 0 1-3.525.565 7.99 7.99 0 0 0-.748 1.298A4.993 4.993 0 0 1 6 12c0 1.26-.47 2.437-1.273 3.334a8.126 8.126 0 0 0 .75 1.298A4.993 4.993 0 0 1 9 17.196zM12 15a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0-2a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.1 KiB |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M6.265 3.807l1.147 1.639a8 8 0 1 0 9.176 0l1.147-1.639A9.988 9.988 0 0 1 22 12c0 5.523-4.477 10-10 10S2 17.523 2 12a9.988 9.988 0 0 1 4.265-8.193zM11 12V2h2v10h-2z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 315 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M2 4c0-.552.455-1 .992-1h18.016c.548 0 .992.445.992 1v14c0 .552-.455 1-.992 1H2.992A.994.994 0 0 1 2 18V4zm2 1v12h16V5H4zm1 15h14v2H5v-2z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 289 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M10 7.22L6.603 10H3v4h3.603L10 16.78V7.22zM5.889 16H2a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1h3.889l5.294-4.332a.5.5 0 0 1 .817.387v15.89a.5.5 0 0 1-.817.387L5.89 16zm13.517 4.134l-1.416-1.416A8.978 8.978 0 0 0 21 12a8.982 8.982 0 0 0-3.304-6.968l1.42-1.42A10.976 10.976 0 0 1 23 12c0 3.223-1.386 6.122-3.594 8.134zm-3.543-3.543l-1.422-1.422A3.993 3.993 0 0 0 16 12c0-1.43-.75-2.685-1.88-3.392l1.439-1.439A5.991 5.991 0 0 1 18 12c0 1.842-.83 3.49-2.137 4.591z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 601 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M3 3h18a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1zm17 8H4v8h16v-8zm0-2V5H4v4h16zm-5-3h4v2h-4V6z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 268 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M16.05 12.05L21 17l-4.95 4.95-1.414-1.414 2.536-2.537L4 18v-2h13.172l-2.536-2.536 1.414-1.414zm-8.1-10l1.414 1.414L6.828 6 20 6v2H6.828l2.536 2.536L7.95 11.95 3 7l4.95-4.95z" fill="#ffffff"/></svg>
|
Before Width: | Height: | Size: 326 B |