Compare commits
23 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
d16288a2a8 | ||
|
600f86dc7b | ||
|
7210c17c5e | ||
|
a16854e55a | ||
|
3e455a90a1 | ||
|
e4413542b2 | ||
|
8c720783f5 | ||
|
8734ea9dd4 | ||
|
c586e6d2b7 | ||
|
3a4eeb77fe | ||
|
51b3953cfc | ||
|
610eecc1c1 | ||
|
492056abf6 | ||
|
ee6e682ab4 | ||
|
6f60e102a2 | ||
|
eeb2af9953 | ||
|
550747eac6 | ||
|
3ffceab1fb | ||
|
b9f2a96595 | ||
|
cbaa845f5d | ||
|
9e2681f2d7 | ||
|
81fae0d1a6 | ||
|
38519f3b9a |
61
.gitattributes
vendored
61
.gitattributes
vendored
@@ -1,63 +1,4 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
# Set default behavior to automatically normalize line endings.
|
# Set default behavior to automatically normalize line endings.
|
||||||
###############################################################################
|
###############################################################################
|
||||||
* text=auto
|
* text=auto eol=lf
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Set default behavior for command prompt diff.
|
|
||||||
#
|
|
||||||
# This is need for earlier builds of msysgit that does not have it on by
|
|
||||||
# default for csharp files.
|
|
||||||
# Note: This is only used by command line
|
|
||||||
###############################################################################
|
|
||||||
#*.cs diff=csharp
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Set the merge driver for project and solution files
|
|
||||||
#
|
|
||||||
# Merging from the command prompt will add diff markers to the files if there
|
|
||||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
|
||||||
# the diff markers are never inserted). Diff markers may cause the following
|
|
||||||
# file extensions to fail to load in VS. An alternative would be to treat
|
|
||||||
# these files as binary and thus will always conflict and require user
|
|
||||||
# intervention with every merge. To do so, just uncomment the entries below
|
|
||||||
###############################################################################
|
|
||||||
#*.sln merge=binary
|
|
||||||
#*.csproj merge=binary
|
|
||||||
#*.vbproj merge=binary
|
|
||||||
#*.vcxproj merge=binary
|
|
||||||
#*.vcproj merge=binary
|
|
||||||
#*.dbproj merge=binary
|
|
||||||
#*.fsproj merge=binary
|
|
||||||
#*.lsproj merge=binary
|
|
||||||
#*.wixproj merge=binary
|
|
||||||
#*.modelproj merge=binary
|
|
||||||
#*.sqlproj merge=binary
|
|
||||||
#*.wwaproj merge=binary
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# behavior for image files
|
|
||||||
#
|
|
||||||
# image files are treated as binary by default.
|
|
||||||
###############################################################################
|
|
||||||
#*.jpg binary
|
|
||||||
#*.png binary
|
|
||||||
#*.gif binary
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# diff behavior for common document formats
|
|
||||||
#
|
|
||||||
# Convert binary document formats to text before diffing them. This feature
|
|
||||||
# is only available from the command line. Turn it on by uncommenting the
|
|
||||||
# entries below.
|
|
||||||
###############################################################################
|
|
||||||
#*.doc diff=astextplain
|
|
||||||
#*.DOC diff=astextplain
|
|
||||||
#*.docx diff=astextplain
|
|
||||||
#*.DOCX diff=astextplain
|
|
||||||
#*.dot diff=astextplain
|
|
||||||
#*.DOT diff=astextplain
|
|
||||||
#*.pdf diff=astextplain
|
|
||||||
#*.PDF diff=astextplain
|
|
||||||
#*.rtf diff=astextplain
|
|
||||||
#*.RTF diff=astextplain
|
|
||||||
|
28
.github/workflows/release.yml
vendored
28
.github/workflows/release.yml
vendored
@@ -38,11 +38,11 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
- name: Configure for release
|
- name: Configure for release
|
||||||
run: |
|
run: |
|
||||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' Ryujinx.Common/ReleaseInformations.cs
|
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' Ryujinx.Common/ReleaseInformation.cs
|
||||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' Ryujinx.Common/ReleaseInformations.cs
|
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' Ryujinx.Common/ReleaseInformation.cs
|
||||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' Ryujinx.Common/ReleaseInformations.cs
|
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' Ryujinx.Common/ReleaseInformation.cs
|
||||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' Ryujinx.Common/ReleaseInformations.cs
|
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' Ryujinx.Common/ReleaseInformation.cs
|
||||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' Ryujinx.Common/ReleaseInformations.cs
|
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' Ryujinx.Common/ReleaseInformation.cs
|
||||||
shell: bash
|
shell: bash
|
||||||
- name: Create output dir
|
- name: Create output dir
|
||||||
run: "mkdir release_output"
|
run: "mkdir release_output"
|
||||||
@@ -75,15 +75,27 @@ jobs:
|
|||||||
- name: Packing Linux builds
|
- name: Packing Linux builds
|
||||||
run: |
|
run: |
|
||||||
pushd publish_linux
|
pushd publish_linux
|
||||||
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
tar --exclude "publish/Ryujinx" --exclude "publish/Ryujinx.sh" -cvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar publish
|
||||||
|
python3 ../distribution/misc/add_tar_exec.py ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx" "publish/Ryujinx"
|
||||||
|
python3 ../distribution/misc/add_tar_exec.py ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.sh" "publish/Ryujinx.sh"
|
||||||
|
gzip -9 < ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar > ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz
|
||||||
|
rm ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar
|
||||||
popd
|
popd
|
||||||
|
|
||||||
pushd publish_linux_sdl2_headless
|
pushd publish_linux_sdl2_headless
|
||||||
tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
tar --exclude "publish/Ryujinx.Headless.SDL2" --exclude "publish/Ryujinx.sh" -cvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar publish
|
||||||
|
python3 ../distribution/misc/add_tar_exec.py ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.Headless.SDL2" "publish/Ryujinx.Headless.SDL2"
|
||||||
|
python3 ../distribution/misc/add_tar_exec.py ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.sh" "publish/Ryujinx.sh"
|
||||||
|
gzip -9 < ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar > ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz
|
||||||
|
rm ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar
|
||||||
popd
|
popd
|
||||||
|
|
||||||
pushd publish_linux_ava
|
pushd publish_linux_ava
|
||||||
tar -czvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
tar --exclude "publish/Ryujinx.Ava" --exclude "publish/Ryujinx.sh" -cvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar publish
|
||||||
|
python3 ../distribution/misc/add_tar_exec.py ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.Ava" "publish/Ryujinx.Ava"
|
||||||
|
python3 ../distribution/misc/add_tar_exec.py ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.sh" "publish/Ryujinx.sh"
|
||||||
|
gzip -9 < ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar > ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz
|
||||||
|
rm ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar
|
||||||
popd
|
popd
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
|
@@ -15,6 +15,8 @@ namespace Ryujinx.Audio.Backends.CompatLayer
|
|||||||
{
|
{
|
||||||
private IHardwareDeviceDriver _realDriver;
|
private IHardwareDeviceDriver _realDriver;
|
||||||
|
|
||||||
|
public static bool IsSupported => true;
|
||||||
|
|
||||||
public CompatLayerHardwareDeviceDriver(IHardwareDeviceDriver realDevice)
|
public CompatLayerHardwareDeviceDriver(IHardwareDeviceDriver realDevice)
|
||||||
{
|
{
|
||||||
_realDriver = realDevice;
|
_realDriver = realDevice;
|
||||||
|
@@ -12,6 +12,8 @@ namespace Ryujinx.Audio.Backends.Dummy
|
|||||||
private ManualResetEvent _updateRequiredEvent;
|
private ManualResetEvent _updateRequiredEvent;
|
||||||
private ManualResetEvent _pauseEvent;
|
private ManualResetEvent _pauseEvent;
|
||||||
|
|
||||||
|
public static bool IsSupported => true;
|
||||||
|
|
||||||
public DummyHardwareDeviceDriver()
|
public DummyHardwareDeviceDriver()
|
||||||
{
|
{
|
||||||
_updateRequiredEvent = new ManualResetEvent(false);
|
_updateRequiredEvent = new ManualResetEvent(false);
|
||||||
|
@@ -26,6 +26,8 @@ namespace Ryujinx.Audio.Integration
|
|||||||
bool SupportsSampleFormat(SampleFormat sampleFormat);
|
bool SupportsSampleFormat(SampleFormat sampleFormat);
|
||||||
bool SupportsChannelCount(uint channelCount);
|
bool SupportsChannelCount(uint channelCount);
|
||||||
|
|
||||||
|
static abstract bool IsSupported { get; }
|
||||||
|
|
||||||
IHardwareDeviceDriver GetRealDeviceDriver()
|
IHardwareDeviceDriver GetRealDeviceDriver()
|
||||||
{
|
{
|
||||||
return this;
|
return this;
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using LibHac.Tools.FsSystem;
|
using LibHac.Tools.FsSystem;
|
||||||
@@ -13,6 +15,7 @@ using Ryujinx.Ava.Input;
|
|||||||
using Ryujinx.Ava.UI.Controls;
|
using Ryujinx.Ava.UI.Controls;
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
using Ryujinx.Ava.UI.Models;
|
using Ryujinx.Ava.UI.Models;
|
||||||
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
using Ryujinx.Ava.UI.Windows;
|
using Ryujinx.Ava.UI.Windows;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
@@ -38,11 +41,12 @@ using SixLabors.ImageSharp.PixelFormats;
|
|||||||
using SixLabors.ImageSharp.Processing;
|
using SixLabors.ImageSharp.Processing;
|
||||||
using SPB.Graphics.Vulkan;
|
using SPB.Graphics.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Image = SixLabors.ImageSharp.Image;
|
||||||
using InputManager = Ryujinx.Input.HLE.InputManager;
|
using InputManager = Ryujinx.Input.HLE.InputManager;
|
||||||
using Key = Ryujinx.Input.Key;
|
using Key = Ryujinx.Input.Key;
|
||||||
using MouseButton = Ryujinx.Input.MouseButton;
|
using MouseButton = Ryujinx.Input.MouseButton;
|
||||||
@@ -54,133 +58,142 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
internal class AppHost
|
internal class AppHost
|
||||||
{
|
{
|
||||||
private const int CursorHideIdleTime = 8; // Hide Cursor seconds
|
private const int CursorHideIdleTime = 8; // Hide Cursor seconds.
|
||||||
private const float MaxResolutionScale = 4.0f; // Max resolution hotkeys can scale to before wrapping.
|
private const float MaxResolutionScale = 4.0f; // Max resolution hotkeys can scale to before wrapping.
|
||||||
private const int TargetFps = 60;
|
private const int TargetFps = 60;
|
||||||
|
private const float VolumeDelta = 0.05f;
|
||||||
|
|
||||||
private const float VolumeDelta = 0.05f;
|
private static readonly Cursor InvisibleCursor = new(StandardCursorType.None);
|
||||||
|
|
||||||
private static readonly Cursor InvisibleCursor = new Cursor(StandardCursorType.None);
|
private readonly long _ticksPerFrame;
|
||||||
|
|
||||||
private readonly long _ticksPerFrame;
|
|
||||||
private readonly Stopwatch _chrono;
|
private readonly Stopwatch _chrono;
|
||||||
private readonly AccountManager _accountManager;
|
private long _ticks;
|
||||||
|
|
||||||
|
private readonly AccountManager _accountManager;
|
||||||
private readonly UserChannelPersistence _userChannelPersistence;
|
private readonly UserChannelPersistence _userChannelPersistence;
|
||||||
private readonly InputManager _inputManager;
|
private readonly InputManager _inputManager;
|
||||||
private readonly MainWindow _parent;
|
|
||||||
private readonly IKeyboard _keyboardInterface;
|
private readonly MainWindowViewModel _viewModel;
|
||||||
|
private readonly IKeyboard _keyboardInterface;
|
||||||
|
private readonly TopLevel _topLevel;
|
||||||
|
|
||||||
private readonly GraphicsDebugLevel _glLogLevel;
|
private readonly GraphicsDebugLevel _glLogLevel;
|
||||||
|
private float _newVolume;
|
||||||
|
private KeyboardHotkeyState _prevHotkeyState;
|
||||||
|
|
||||||
private bool _hideCursorOnIdle;
|
private bool _hideCursorOnIdle;
|
||||||
|
private long _lastCursorMoveTime;
|
||||||
|
private bool _isCursorInRenderer;
|
||||||
|
|
||||||
private bool _isStopped;
|
private bool _isStopped;
|
||||||
private bool _isActive;
|
private bool _isActive;
|
||||||
private long _lastCursorMoveTime;
|
|
||||||
private float _newVolume;
|
|
||||||
private long _ticks = 0;
|
|
||||||
|
|
||||||
private KeyboardHotkeyState _prevHotkeyState;
|
|
||||||
|
|
||||||
private IRenderer _renderer;
|
|
||||||
private readonly Thread _renderingThread;
|
|
||||||
|
|
||||||
private bool _isMouseInRenderer;
|
|
||||||
private bool _renderingStarted;
|
private bool _renderingStarted;
|
||||||
private bool _dialogShown;
|
|
||||||
|
|
||||||
|
private IRenderer _renderer;
|
||||||
|
private readonly Thread _renderingThread;
|
||||||
|
private readonly CancellationTokenSource _gpuCancellationTokenSource;
|
||||||
private WindowsMultimediaTimerResolution _windowsMultimediaTimerResolution;
|
private WindowsMultimediaTimerResolution _windowsMultimediaTimerResolution;
|
||||||
|
|
||||||
private readonly CancellationTokenSource _gpuCancellationTokenSource;
|
private bool _dialogShown;
|
||||||
|
private readonly bool _isFirmwareTitle;
|
||||||
|
|
||||||
|
private readonly object _lockObject = new();
|
||||||
|
|
||||||
public event EventHandler AppExit;
|
public event EventHandler AppExit;
|
||||||
public event EventHandler<StatusUpdatedEventArgs> StatusUpdatedEvent;
|
public event EventHandler<StatusUpdatedEventArgs> StatusUpdatedEvent;
|
||||||
|
|
||||||
public RendererHost Renderer { get; }
|
public RendererHost Renderer { get; }
|
||||||
public VirtualFileSystem VirtualFileSystem { get; }
|
public VirtualFileSystem VirtualFileSystem { get; }
|
||||||
public ContentManager ContentManager { get; }
|
public ContentManager ContentManager { get; }
|
||||||
public Switch Device { get; set; }
|
public NpadManager NpadManager { get; }
|
||||||
public NpadManager NpadManager { get; }
|
|
||||||
public TouchScreenManager TouchScreenManager { get; }
|
public TouchScreenManager TouchScreenManager { get; }
|
||||||
|
public Switch Device { get; set; }
|
||||||
|
|
||||||
public int Width { get; private set; }
|
public int Width { get; private set; }
|
||||||
public int Height { get; private set; }
|
public int Height { get; private set; }
|
||||||
public string ApplicationPath { get; private set; }
|
public string ApplicationPath { get; private set; }
|
||||||
|
public bool ScreenshotRequested { get; set; }
|
||||||
|
|
||||||
private bool _isFirmwareTitle;
|
|
||||||
|
|
||||||
public bool ScreenshotRequested { get; set; }
|
|
||||||
|
|
||||||
private object _lockObject = new();
|
|
||||||
|
|
||||||
public AppHost(
|
public AppHost(
|
||||||
RendererHost renderer,
|
RendererHost renderer,
|
||||||
InputManager inputManager,
|
InputManager inputManager,
|
||||||
string applicationPath,
|
string applicationPath,
|
||||||
VirtualFileSystem virtualFileSystem,
|
VirtualFileSystem virtualFileSystem,
|
||||||
ContentManager contentManager,
|
ContentManager contentManager,
|
||||||
AccountManager accountManager,
|
AccountManager accountManager,
|
||||||
UserChannelPersistence userChannelPersistence,
|
UserChannelPersistence userChannelPersistence,
|
||||||
MainWindow parent)
|
MainWindowViewModel viewmodel,
|
||||||
|
TopLevel topLevel)
|
||||||
{
|
{
|
||||||
_parent = parent;
|
_viewModel = viewmodel;
|
||||||
_inputManager = inputManager;
|
_inputManager = inputManager;
|
||||||
_accountManager = accountManager;
|
_accountManager = accountManager;
|
||||||
_userChannelPersistence = userChannelPersistence;
|
_userChannelPersistence = userChannelPersistence;
|
||||||
_renderingThread = new Thread(RenderLoop, 1 * 1024 * 1024) { Name = "GUI.RenderThread" };
|
_renderingThread = new Thread(RenderLoop, 1 * 1024 * 1024) { Name = "GUI.RenderThread" };
|
||||||
_hideCursorOnIdle = ConfigurationState.Instance.HideCursorOnIdle;
|
_hideCursorOnIdle = ConfigurationState.Instance.HideCursorOnIdle;
|
||||||
_lastCursorMoveTime = Stopwatch.GetTimestamp();
|
_lastCursorMoveTime = Stopwatch.GetTimestamp();
|
||||||
_glLogLevel = ConfigurationState.Instance.Logger.GraphicsDebugLevel;
|
_glLogLevel = ConfigurationState.Instance.Logger.GraphicsDebugLevel;
|
||||||
_inputManager.SetMouseDriver(new AvaloniaMouseDriver(_parent, renderer));
|
_topLevel = topLevel;
|
||||||
|
|
||||||
|
_inputManager.SetMouseDriver(new AvaloniaMouseDriver(_topLevel, renderer));
|
||||||
|
|
||||||
_keyboardInterface = (IKeyboard)_inputManager.KeyboardDriver.GetGamepad("0");
|
_keyboardInterface = (IKeyboard)_inputManager.KeyboardDriver.GetGamepad("0");
|
||||||
|
|
||||||
NpadManager = _inputManager.CreateNpadManager();
|
NpadManager = _inputManager.CreateNpadManager();
|
||||||
TouchScreenManager = _inputManager.CreateTouchScreenManager();
|
TouchScreenManager = _inputManager.CreateTouchScreenManager();
|
||||||
Renderer = renderer;
|
Renderer = renderer;
|
||||||
ApplicationPath = applicationPath;
|
ApplicationPath = applicationPath;
|
||||||
VirtualFileSystem = virtualFileSystem;
|
VirtualFileSystem = virtualFileSystem;
|
||||||
ContentManager = contentManager;
|
ContentManager = contentManager;
|
||||||
|
|
||||||
_chrono = new Stopwatch();
|
_chrono = new Stopwatch();
|
||||||
_ticksPerFrame = Stopwatch.Frequency / TargetFps;
|
_ticksPerFrame = Stopwatch.Frequency / TargetFps;
|
||||||
|
|
||||||
if (ApplicationPath.StartsWith("@SystemContent"))
|
if (ApplicationPath.StartsWith("@SystemContent"))
|
||||||
{
|
{
|
||||||
ApplicationPath = _parent.VirtualFileSystem.SwitchPathToSystemPath(ApplicationPath);
|
ApplicationPath = _viewModel.VirtualFileSystem.SwitchPathToSystemPath(ApplicationPath);
|
||||||
|
|
||||||
_isFirmwareTitle = true;
|
_isFirmwareTitle = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigurationState.Instance.HideCursorOnIdle.Event += HideCursorState_Changed;
|
ConfigurationState.Instance.HideCursorOnIdle.Event += HideCursorState_Changed;
|
||||||
|
|
||||||
_parent.PointerLeave += Parent_PointerLeft;
|
_topLevel.PointerLeave += TopLevel_PointerLeave;
|
||||||
_parent.PointerMoved += Parent_PointerMoved;
|
_topLevel.PointerMoved += TopLevel_PointerMoved;
|
||||||
|
|
||||||
ConfigurationState.Instance.System.IgnoreMissingServices.Event += UpdateIgnoreMissingServicesState;
|
ConfigurationState.Instance.System.IgnoreMissingServices.Event += UpdateIgnoreMissingServicesState;
|
||||||
ConfigurationState.Instance.Graphics.AspectRatio.Event += UpdateAspectRatioState;
|
ConfigurationState.Instance.Graphics.AspectRatio.Event += UpdateAspectRatioState;
|
||||||
ConfigurationState.Instance.System.EnableDockedMode.Event += UpdateDockedModeState;
|
ConfigurationState.Instance.System.EnableDockedMode.Event += UpdateDockedModeState;
|
||||||
ConfigurationState.Instance.System.AudioVolume.Event += UpdateAudioVolumeState;
|
ConfigurationState.Instance.System.AudioVolume.Event += UpdateAudioVolumeState;
|
||||||
|
|
||||||
_gpuCancellationTokenSource = new CancellationTokenSource();
|
_gpuCancellationTokenSource = new CancellationTokenSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Parent_PointerMoved(object sender, PointerEventArgs e)
|
private void TopLevel_PointerMoved(object sender, PointerEventArgs e)
|
||||||
{
|
{
|
||||||
_lastCursorMoveTime = Stopwatch.GetTimestamp();
|
if (sender is Control visual)
|
||||||
var p = e.GetCurrentPoint(_parent).Position;
|
{
|
||||||
var r = _parent.InputHitTest(p);
|
_lastCursorMoveTime = Stopwatch.GetTimestamp();
|
||||||
_isMouseInRenderer = r == Renderer;
|
|
||||||
|
var point = e.GetCurrentPoint(visual).Position;
|
||||||
|
|
||||||
|
_isCursorInRenderer = Equals(visual.InputHitTest(point), Renderer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Parent_PointerLeft(object sender, PointerEventArgs e)
|
private void TopLevel_PointerLeave(object sender, PointerEventArgs e)
|
||||||
{
|
{
|
||||||
_isMouseInRenderer = false;
|
_isCursorInRenderer = false;
|
||||||
_parent.Cursor = Cursor.Default;
|
_viewModel.Cursor = Cursor.Default;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetRendererWindowSize(Size size)
|
private void SetRendererWindowSize(Size size)
|
||||||
{
|
{
|
||||||
if (_renderer != null)
|
if (_renderer != null)
|
||||||
{
|
{
|
||||||
double scale = _parent.PlatformImpl.RenderScaling;
|
double scale = _topLevel.PlatformImpl.RenderScaling;
|
||||||
|
|
||||||
_renderer.Window?.SetSize((int)(size.Width * scale), (int)(size.Height * scale));
|
_renderer.Window?.SetSize((int)(size.Width * scale), (int)(size.Height * scale));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,12 +206,13 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
lock (_lockObject)
|
lock (_lockObject)
|
||||||
{
|
{
|
||||||
var currentTime = DateTime.Now;
|
DateTime currentTime = DateTime.Now;
|
||||||
string filename = $"ryujinx_capture_{currentTime.Year}-{currentTime.Month:D2}-{currentTime.Day:D2}_{currentTime.Hour:D2}-{currentTime.Minute:D2}-{currentTime.Second:D2}.png";
|
string filename = $"ryujinx_capture_{currentTime}-{currentTime:D2}-{currentTime:D2}_{currentTime:D2}-{currentTime:D2}-{currentTime:D2}.png";
|
||||||
|
|
||||||
string directory = AppDataManager.Mode switch
|
string directory = AppDataManager.Mode switch
|
||||||
{
|
{
|
||||||
AppDataManager.LaunchMode.Portable => Path.Combine(AppDataManager.BaseDirPath, "screenshots"),
|
AppDataManager.LaunchMode.Portable => Path.Combine(AppDataManager.BaseDirPath, "screenshots"),
|
||||||
_ => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "Ryujinx")
|
_ => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "Ryujinx")
|
||||||
};
|
};
|
||||||
|
|
||||||
string path = Path.Combine(directory, filename);
|
string path = Path.Combine(directory, filename);
|
||||||
@@ -256,30 +270,19 @@ namespace Ryujinx.Ava
|
|||||||
NpadManager.Initialize(Device, ConfigurationState.Instance.Hid.InputConfig, ConfigurationState.Instance.Hid.EnableKeyboard, ConfigurationState.Instance.Hid.EnableMouse);
|
NpadManager.Initialize(Device, ConfigurationState.Instance.Hid.InputConfig, ConfigurationState.Instance.Hid.EnableKeyboard, ConfigurationState.Instance.Hid.EnableMouse);
|
||||||
TouchScreenManager.Initialize(Device);
|
TouchScreenManager.Initialize(Device);
|
||||||
|
|
||||||
_parent.ViewModel.IsGameRunning = true;
|
_viewModel.IsGameRunning = true;
|
||||||
|
|
||||||
string titleNameSection = string.IsNullOrWhiteSpace(Device.Application.TitleName)
|
string titleNameSection = string.IsNullOrWhiteSpace(Device.Application.TitleName) ? string.Empty : $" - {Device.Application.TitleName}";
|
||||||
? string.Empty
|
string titleVersionSection = string.IsNullOrWhiteSpace(Device.Application.DisplayVersion) ? string.Empty : $" v{Device.Application.DisplayVersion}";
|
||||||
: $" - {Device.Application.TitleName}";
|
string titleIdSection = string.IsNullOrWhiteSpace(Device.Application.TitleIdText) ? string.Empty : $" ({Device.Application.TitleIdText.ToUpper()})";
|
||||||
|
string titleArchSection = Device.Application.TitleIs64Bit ? " (64-bit)" : " (32-bit)";
|
||||||
string titleVersionSection = string.IsNullOrWhiteSpace(Device.Application.DisplayVersion)
|
|
||||||
? string.Empty
|
|
||||||
: $" v{Device.Application.DisplayVersion}";
|
|
||||||
|
|
||||||
string titleIdSection = string.IsNullOrWhiteSpace(Device.Application.TitleIdText)
|
|
||||||
? string.Empty
|
|
||||||
: $" ({Device.Application.TitleIdText.ToUpper()})";
|
|
||||||
|
|
||||||
string titleArchSection = Device.Application.TitleIs64Bit
|
|
||||||
? " (64-bit)"
|
|
||||||
: " (32-bit)";
|
|
||||||
|
|
||||||
Dispatcher.UIThread.InvokeAsync(() =>
|
Dispatcher.UIThread.InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
_parent.Title = $"Ryujinx {Program.Version}{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}";
|
_viewModel.Title = $"Ryujinx {Program.Version}{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}";
|
||||||
});
|
});
|
||||||
|
|
||||||
_parent.ViewModel.SetUiProgressHandlers(Device);
|
_viewModel.SetUIProgressHandlers(Device);
|
||||||
|
|
||||||
Renderer.SizeChanged += Window_SizeChanged;
|
Renderer.SizeChanged += Window_SizeChanged;
|
||||||
|
|
||||||
@@ -287,7 +290,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
_renderingThread.Start();
|
_renderingThread.Start();
|
||||||
|
|
||||||
_parent.ViewModel.Volume = ConfigurationState.Instance.System.AudioVolume.Value;
|
_viewModel.Volume = ConfigurationState.Instance.System.AudioVolume.Value;
|
||||||
|
|
||||||
MainLoop();
|
MainLoop();
|
||||||
|
|
||||||
@@ -318,10 +321,10 @@ namespace Ryujinx.Ava
|
|||||||
private void UpdateAudioVolumeState(object sender, ReactiveEventArgs<float> e)
|
private void UpdateAudioVolumeState(object sender, ReactiveEventArgs<float> e)
|
||||||
{
|
{
|
||||||
Device?.SetVolume(e.NewValue);
|
Device?.SetVolume(e.NewValue);
|
||||||
|
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
{
|
{
|
||||||
var value = e.NewValue;
|
_viewModel.Volume = e.NewValue;
|
||||||
_parent.ViewModel.Volume = e.NewValue;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,7 +343,7 @@ namespace Ryujinx.Ava
|
|||||||
}
|
}
|
||||||
|
|
||||||
_isStopped = true;
|
_isStopped = true;
|
||||||
_isActive = false;
|
_isActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DisposeContext()
|
public void DisposeContext()
|
||||||
@@ -369,13 +372,16 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
if (Device.Application != null)
|
if (Device.Application != null)
|
||||||
{
|
{
|
||||||
_parent.UpdateGameMetadata(Device.Application.TitleIdText);
|
_viewModel.UpdateGameMetadata(Device.Application.TitleIdText);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigurationState.Instance.System.IgnoreMissingServices.Event -= UpdateIgnoreMissingServicesState;
|
ConfigurationState.Instance.System.IgnoreMissingServices.Event -= UpdateIgnoreMissingServicesState;
|
||||||
ConfigurationState.Instance.Graphics.AspectRatio.Event -= UpdateAspectRatioState;
|
ConfigurationState.Instance.Graphics.AspectRatio.Event -= UpdateAspectRatioState;
|
||||||
ConfigurationState.Instance.System.EnableDockedMode.Event -= UpdateDockedModeState;
|
ConfigurationState.Instance.System.EnableDockedMode.Event -= UpdateDockedModeState;
|
||||||
ConfigurationState.Instance.System.AudioVolume.Event -= UpdateAudioVolumeState;
|
ConfigurationState.Instance.System.AudioVolume.Event -= UpdateAudioVolumeState;
|
||||||
|
|
||||||
|
_topLevel.PointerLeave -= TopLevel_PointerLeave;
|
||||||
|
_topLevel.PointerMoved -= TopLevel_PointerMoved;
|
||||||
|
|
||||||
_gpuCancellationTokenSource.Cancel();
|
_gpuCancellationTokenSource.Cancel();
|
||||||
_gpuCancellationTokenSource.Dispose();
|
_gpuCancellationTokenSource.Dispose();
|
||||||
@@ -410,7 +416,7 @@ namespace Ryujinx.Ava
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_parent.Cursor = Cursor.Default;
|
_viewModel.Cursor = Cursor.Default;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -422,57 +428,65 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
SystemVersion firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
SystemVersion firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
||||||
|
|
||||||
if (!SetupValidator.CanStartApplication(ContentManager, ApplicationPath, out UserError userError))
|
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
{
|
{
|
||||||
if (SetupValidator.CanFixStartApplication(ContentManager, ApplicationPath, userError, out firmwareVersion))
|
if (!SetupValidator.CanStartApplication(ContentManager, ApplicationPath, out UserError userError))
|
||||||
{
|
{
|
||||||
if (userError == UserError.NoFirmware)
|
|
||||||
{
|
{
|
||||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
if (SetupValidator.CanFixStartApplication(ContentManager, ApplicationPath, userError, out firmwareVersion))
|
||||||
LocaleManager.Instance[LocaleKeys.DialogFirmwareNoFirmwareInstalledMessage],
|
|
||||||
string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallEmbeddedMessage], firmwareVersion.VersionString),
|
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
|
||||||
"");
|
|
||||||
|
|
||||||
if (result != UserResult.Yes)
|
|
||||||
{
|
{
|
||||||
await UserErrorDialog.ShowUserErrorDialog(userError, _parent);
|
if (userError == UserError.NoFirmware)
|
||||||
|
{
|
||||||
|
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
||||||
|
LocaleManager.Instance[LocaleKeys.DialogFirmwareNoFirmwareInstalledMessage],
|
||||||
|
string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallEmbeddedMessage],
|
||||||
|
firmwareVersion.VersionString),
|
||||||
|
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
||||||
|
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||||
|
"");
|
||||||
|
|
||||||
|
if (result != UserResult.Yes)
|
||||||
|
{
|
||||||
|
await UserErrorDialog.ShowUserErrorDialog(userError, (desktop.MainWindow as MainWindow));
|
||||||
|
Device.Dispose();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SetupValidator.TryFixStartApplication(ContentManager, ApplicationPath, userError, out _))
|
||||||
|
{
|
||||||
|
await UserErrorDialog.ShowUserErrorDialog(userError, (desktop.MainWindow as MainWindow));
|
||||||
|
Device.Dispose();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tell the user that we installed a firmware for them.
|
||||||
|
if (userError == UserError.NoFirmware)
|
||||||
|
{
|
||||||
|
firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
||||||
|
|
||||||
|
_viewModel.RefreshFirmwareStatus();
|
||||||
|
|
||||||
|
await ContentDialogHelper.CreateInfoDialog(
|
||||||
|
string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstalledMessage],
|
||||||
|
firmwareVersion.VersionString),
|
||||||
|
string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallEmbeddedSuccessMessage],
|
||||||
|
firmwareVersion.VersionString),
|
||||||
|
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
||||||
|
"",
|
||||||
|
LocaleManager.Instance[LocaleKeys.RyujinxInfo]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await UserErrorDialog.ShowUserErrorDialog(userError, (desktop.MainWindow as MainWindow));
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SetupValidator.TryFixStartApplication(ContentManager, ApplicationPath, userError, out _))
|
|
||||||
{
|
|
||||||
await UserErrorDialog.ShowUserErrorDialog(userError, _parent);
|
|
||||||
Device.Dispose();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tell the user that we installed a firmware for them.
|
|
||||||
if (userError == UserError.NoFirmware)
|
|
||||||
{
|
|
||||||
firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
|
||||||
|
|
||||||
_parent.RefreshFirmwareStatus();
|
|
||||||
|
|
||||||
await ContentDialogHelper.CreateInfoDialog(
|
|
||||||
string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstalledMessage], firmwareVersion.VersionString),
|
|
||||||
string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallEmbeddedSuccessMessage], firmwareVersion.VersionString),
|
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
|
||||||
"",
|
|
||||||
LocaleManager.Instance[LocaleKeys.RyujinxInfo]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await UserErrorDialog.ShowUserErrorDialog(userError, _parent);
|
|
||||||
Device.Dispose();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -567,7 +581,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
DiscordIntegrationModule.SwitchToPlayingState(Device.Application.TitleIdText, Device.Application.TitleName);
|
DiscordIntegrationModule.SwitchToPlayingState(Device.Application.TitleIdText, Device.Application.TitleName);
|
||||||
|
|
||||||
_parent.ApplicationLibrary.LoadAndSaveMetaData(Device.Application.TitleIdText, appMetadata =>
|
_viewModel.ApplicationLibrary.LoadAndSaveMetaData(Device.Application.TitleIdText, appMetadata =>
|
||||||
{
|
{
|
||||||
appMetadata.LastPlayed = DateTime.UtcNow.ToString();
|
appMetadata.LastPlayed = DateTime.UtcNow.ToString();
|
||||||
});
|
});
|
||||||
@@ -578,19 +592,23 @@ namespace Ryujinx.Ava
|
|||||||
internal void Resume()
|
internal void Resume()
|
||||||
{
|
{
|
||||||
Device?.System.TogglePauseEmulation(false);
|
Device?.System.TogglePauseEmulation(false);
|
||||||
_parent.ViewModel.IsPaused = false;
|
|
||||||
|
_viewModel.IsPaused = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Pause()
|
internal void Pause()
|
||||||
{
|
{
|
||||||
Device?.System.TogglePauseEmulation(true);
|
Device?.System.TogglePauseEmulation(true);
|
||||||
_parent.ViewModel.IsPaused = true;
|
|
||||||
|
_viewModel.IsPaused = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeSwitchInstance()
|
private void InitializeSwitchInstance()
|
||||||
{
|
{
|
||||||
|
// Initialize KeySet.
|
||||||
VirtualFileSystem.ReloadKeySet();
|
VirtualFileSystem.ReloadKeySet();
|
||||||
|
|
||||||
|
// Initialize Renderer.
|
||||||
IRenderer renderer;
|
IRenderer renderer;
|
||||||
|
|
||||||
if (Renderer.IsVulkan)
|
if (Renderer.IsVulkan)
|
||||||
@@ -604,12 +622,9 @@ namespace Ryujinx.Ava
|
|||||||
renderer = new OpenGLRenderer();
|
renderer = new OpenGLRenderer();
|
||||||
}
|
}
|
||||||
|
|
||||||
IHardwareDeviceDriver deviceDriver = new DummyHardwareDeviceDriver();
|
|
||||||
|
|
||||||
BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading;
|
BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading;
|
||||||
|
|
||||||
var isGALthreaded = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading);
|
var isGALthreaded = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading);
|
||||||
|
|
||||||
if (isGALthreaded)
|
if (isGALthreaded)
|
||||||
{
|
{
|
||||||
renderer = new ThreadedRenderer(renderer);
|
renderer = new ThreadedRenderer(renderer);
|
||||||
@@ -617,159 +632,104 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend Threading ({threadingMode}): {isGALthreaded}");
|
Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend Threading ({threadingMode}): {isGALthreaded}");
|
||||||
|
|
||||||
if (ConfigurationState.Instance.System.AudioBackend.Value == AudioBackend.SDL2)
|
// Initialize Configuration.
|
||||||
{
|
|
||||||
if (SDL2HardwareDeviceDriver.IsSupported)
|
|
||||||
{
|
|
||||||
deviceDriver = new SDL2HardwareDeviceDriver();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Audio, "SDL2 is not supported, trying to fall back to OpenAL.");
|
|
||||||
|
|
||||||
if (OpenALHardwareDeviceDriver.IsSupported)
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Audio, "Found OpenAL, changing configuration.");
|
|
||||||
|
|
||||||
ConfigurationState.Instance.System.AudioBackend.Value = AudioBackend.OpenAl;
|
|
||||||
MainWindow.SaveConfig();
|
|
||||||
|
|
||||||
deviceDriver = new OpenALHardwareDeviceDriver();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Audio, "OpenAL is not supported, trying to fall back to SoundIO.");
|
|
||||||
|
|
||||||
if (SoundIoHardwareDeviceDriver.IsSupported)
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Audio, "Found SoundIO, changing configuration.");
|
|
||||||
|
|
||||||
ConfigurationState.Instance.System.AudioBackend.Value = AudioBackend.SoundIo;
|
|
||||||
MainWindow.SaveConfig();
|
|
||||||
|
|
||||||
deviceDriver = new SoundIoHardwareDeviceDriver();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Audio, "SoundIO is not supported, falling back to dummy audio out.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (ConfigurationState.Instance.System.AudioBackend.Value == AudioBackend.SoundIo)
|
|
||||||
{
|
|
||||||
if (SoundIoHardwareDeviceDriver.IsSupported)
|
|
||||||
{
|
|
||||||
deviceDriver = new SoundIoHardwareDeviceDriver();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Audio, "SoundIO is not supported, trying to fall back to SDL2.");
|
|
||||||
|
|
||||||
if (SDL2HardwareDeviceDriver.IsSupported)
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Audio, "Found SDL2, changing configuration.");
|
|
||||||
|
|
||||||
ConfigurationState.Instance.System.AudioBackend.Value = AudioBackend.SDL2;
|
|
||||||
MainWindow.SaveConfig();
|
|
||||||
|
|
||||||
deviceDriver = new SDL2HardwareDeviceDriver();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Audio, "SDL2 is not supported, trying to fall back to OpenAL.");
|
|
||||||
|
|
||||||
if (OpenALHardwareDeviceDriver.IsSupported)
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Audio, "Found OpenAL, changing configuration.");
|
|
||||||
|
|
||||||
ConfigurationState.Instance.System.AudioBackend.Value = AudioBackend.OpenAl;
|
|
||||||
MainWindow.SaveConfig();
|
|
||||||
|
|
||||||
deviceDriver = new OpenALHardwareDeviceDriver();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Audio, "OpenAL is not supported, falling back to dummy audio out.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (ConfigurationState.Instance.System.AudioBackend.Value == AudioBackend.OpenAl)
|
|
||||||
{
|
|
||||||
if (OpenALHardwareDeviceDriver.IsSupported)
|
|
||||||
{
|
|
||||||
deviceDriver = new OpenALHardwareDeviceDriver();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Audio, "OpenAL is not supported, trying to fall back to SDL2.");
|
|
||||||
|
|
||||||
if (SDL2HardwareDeviceDriver.IsSupported)
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Audio, "Found SDL2, changing configuration.");
|
|
||||||
|
|
||||||
ConfigurationState.Instance.System.AudioBackend.Value = AudioBackend.SDL2;
|
|
||||||
MainWindow.SaveConfig();
|
|
||||||
|
|
||||||
deviceDriver = new SDL2HardwareDeviceDriver();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Audio, "SDL2 is not supported, trying to fall back to SoundIO.");
|
|
||||||
|
|
||||||
if (SoundIoHardwareDeviceDriver.IsSupported)
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Audio, "Found SoundIO, changing configuration.");
|
|
||||||
|
|
||||||
ConfigurationState.Instance.System.AudioBackend.Value = AudioBackend.SoundIo;
|
|
||||||
MainWindow.SaveConfig();
|
|
||||||
|
|
||||||
deviceDriver = new SoundIoHardwareDeviceDriver();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Audio, "SoundIO is not supported, falling back to dummy audio out.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value ? HLE.MemoryConfiguration.MemoryConfiguration6GiB : HLE.MemoryConfiguration.MemoryConfiguration4GiB;
|
var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value ? HLE.MemoryConfiguration.MemoryConfiguration6GiB : HLE.MemoryConfiguration.MemoryConfiguration4GiB;
|
||||||
|
|
||||||
IntegrityCheckLevel fsIntegrityCheckLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None;
|
HLE.HLEConfiguration configuration = new(VirtualFileSystem,
|
||||||
|
_viewModel.LibHacHorizonManager,
|
||||||
HLE.HLEConfiguration configuration = new HLE.HLEConfiguration(VirtualFileSystem,
|
ContentManager,
|
||||||
_parent.LibHacHorizonManager,
|
_accountManager,
|
||||||
ContentManager,
|
_userChannelPersistence,
|
||||||
_accountManager,
|
renderer,
|
||||||
_userChannelPersistence,
|
InitializeAudio(),
|
||||||
renderer,
|
memoryConfiguration,
|
||||||
deviceDriver,
|
_viewModel.UiHandler,
|
||||||
memoryConfiguration,
|
(SystemLanguage)ConfigurationState.Instance.System.Language.Value,
|
||||||
_parent.UiHandler,
|
(RegionCode)ConfigurationState.Instance.System.Region.Value,
|
||||||
(SystemLanguage)ConfigurationState.Instance.System.Language.Value,
|
ConfigurationState.Instance.Graphics.EnableVsync,
|
||||||
(RegionCode)ConfigurationState.Instance.System.Region.Value,
|
ConfigurationState.Instance.System.EnableDockedMode,
|
||||||
ConfigurationState.Instance.Graphics.EnableVsync,
|
ConfigurationState.Instance.System.EnablePtc,
|
||||||
ConfigurationState.Instance.System.EnableDockedMode,
|
ConfigurationState.Instance.System.EnableInternetAccess,
|
||||||
ConfigurationState.Instance.System.EnablePtc,
|
ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None,
|
||||||
ConfigurationState.Instance.System.EnableInternetAccess,
|
ConfigurationState.Instance.System.FsGlobalAccessLogMode,
|
||||||
fsIntegrityCheckLevel,
|
ConfigurationState.Instance.System.SystemTimeOffset,
|
||||||
ConfigurationState.Instance.System.FsGlobalAccessLogMode,
|
ConfigurationState.Instance.System.TimeZone,
|
||||||
ConfigurationState.Instance.System.SystemTimeOffset,
|
ConfigurationState.Instance.System.MemoryManagerMode,
|
||||||
ConfigurationState.Instance.System.TimeZone,
|
ConfigurationState.Instance.System.IgnoreMissingServices,
|
||||||
ConfigurationState.Instance.System.MemoryManagerMode,
|
ConfigurationState.Instance.Graphics.AspectRatio,
|
||||||
ConfigurationState.Instance.System.IgnoreMissingServices,
|
ConfigurationState.Instance.System.AudioVolume);
|
||||||
ConfigurationState.Instance.Graphics.AspectRatio,
|
|
||||||
ConfigurationState.Instance.System.AudioVolume);
|
|
||||||
|
|
||||||
Device = new Switch(configuration);
|
Device = new Switch(configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IHardwareDeviceDriver InitializeAudio()
|
||||||
|
{
|
||||||
|
var availableBackends = new List<AudioBackend>()
|
||||||
|
{
|
||||||
|
AudioBackend.SDL2,
|
||||||
|
AudioBackend.SoundIo,
|
||||||
|
AudioBackend.OpenAl,
|
||||||
|
AudioBackend.Dummy
|
||||||
|
};
|
||||||
|
|
||||||
|
AudioBackend preferredBackend = ConfigurationState.Instance.System.AudioBackend.Value;
|
||||||
|
|
||||||
|
for (int i = 0; i < availableBackends.Count; i++)
|
||||||
|
{
|
||||||
|
if (availableBackends[i] == preferredBackend)
|
||||||
|
{
|
||||||
|
availableBackends.RemoveAt(i);
|
||||||
|
availableBackends.Insert(0, preferredBackend);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static IHardwareDeviceDriver InitializeAudioBackend<T>(AudioBackend backend, AudioBackend nextBackend) where T : IHardwareDeviceDriver, new()
|
||||||
|
{
|
||||||
|
if (T.IsSupported)
|
||||||
|
{
|
||||||
|
return new T();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.Warning?.Print(LogClass.Audio, $"{backend} is not supported, falling back to {nextBackend}.");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IHardwareDeviceDriver deviceDriver = null;
|
||||||
|
|
||||||
|
for (int i = 0; i < availableBackends.Count; i++)
|
||||||
|
{
|
||||||
|
AudioBackend currentBackend = availableBackends[i];
|
||||||
|
AudioBackend nextBackend = i + 1 < availableBackends.Count ? availableBackends[i + 1] : AudioBackend.Dummy;
|
||||||
|
|
||||||
|
deviceDriver = currentBackend switch
|
||||||
|
{
|
||||||
|
AudioBackend.SDL2 => InitializeAudioBackend<SDL2HardwareDeviceDriver>(AudioBackend.SDL2, nextBackend),
|
||||||
|
AudioBackend.SoundIo => InitializeAudioBackend<SoundIoHardwareDeviceDriver>(AudioBackend.SoundIo, nextBackend),
|
||||||
|
AudioBackend.OpenAl => InitializeAudioBackend<OpenALHardwareDeviceDriver>(AudioBackend.OpenAl, nextBackend),
|
||||||
|
_ => new DummyHardwareDeviceDriver()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (deviceDriver != null)
|
||||||
|
{
|
||||||
|
ConfigurationState.Instance.System.AudioBackend.Value = currentBackend;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindowViewModel.SaveConfig();
|
||||||
|
|
||||||
|
return deviceDriver;
|
||||||
|
}
|
||||||
|
|
||||||
private void Window_SizeChanged(object sender, Size e)
|
private void Window_SizeChanged(object sender, Size e)
|
||||||
{
|
{
|
||||||
Width = (int)e.Width;
|
Width = (int)e.Width;
|
||||||
Height = (int)e.Height;
|
Height = (int)e.Height;
|
||||||
|
|
||||||
SetRendererWindowSize(e);
|
SetRendererWindowSize(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -779,7 +739,7 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
UpdateFrame();
|
UpdateFrame();
|
||||||
|
|
||||||
// Polling becomes expensive if it's not slept
|
// Polling becomes expensive if it's not slept.
|
||||||
Thread.Sleep(1);
|
Thread.Sleep(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -788,25 +748,18 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
Dispatcher.UIThread.InvokeAsync(() =>
|
Dispatcher.UIThread.InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
if (_parent.ViewModel.StartGamesInFullscreen)
|
if (_viewModel.StartGamesInFullscreen)
|
||||||
{
|
{
|
||||||
_parent.WindowState = WindowState.FullScreen;
|
_viewModel.WindowState = WindowState.FullScreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_parent.WindowState == WindowState.FullScreen)
|
if (_viewModel.WindowState == WindowState.FullScreen)
|
||||||
{
|
{
|
||||||
_parent.ViewModel.ShowMenuAndStatusBar = false;
|
_viewModel.ShowMenuAndStatusBar = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
IRenderer renderer = Device.Gpu.Renderer;
|
_renderer = Device.Gpu.Renderer is ThreadedRenderer tr ? tr.BaseRenderer : Device.Gpu.Renderer;
|
||||||
|
|
||||||
if (renderer is ThreadedRenderer tr)
|
|
||||||
{
|
|
||||||
renderer = tr.BaseRenderer;
|
|
||||||
}
|
|
||||||
|
|
||||||
_renderer = renderer;
|
|
||||||
|
|
||||||
_renderer.ScreenCaptured += Renderer_ScreenCaptured;
|
_renderer.ScreenCaptured += Renderer_ScreenCaptured;
|
||||||
|
|
||||||
@@ -819,7 +772,7 @@ namespace Ryujinx.Ava
|
|||||||
Width = (int)Renderer.Bounds.Width;
|
Width = (int)Renderer.Bounds.Width;
|
||||||
Height = (int)Renderer.Bounds.Height;
|
Height = (int)Renderer.Bounds.Height;
|
||||||
|
|
||||||
_renderer.Window.SetSize((int)(Width * _parent.PlatformImpl.RenderScaling), (int)(Height * _parent.PlatformImpl.RenderScaling));
|
_renderer.Window.SetSize((int)(Width * _topLevel.PlatformImpl.RenderScaling), (int)(Height * _topLevel.PlatformImpl.RenderScaling));
|
||||||
|
|
||||||
_chrono.Start();
|
_chrono.Start();
|
||||||
|
|
||||||
@@ -847,7 +800,7 @@ namespace Ryujinx.Ava
|
|||||||
if (!_renderingStarted)
|
if (!_renderingStarted)
|
||||||
{
|
{
|
||||||
_renderingStarted = true;
|
_renderingStarted = true;
|
||||||
_parent.SwitchToGameControl();
|
_viewModel.SwitchToRenderer(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Device.PresentFrame(() => Renderer?.SwapBuffers());
|
Device.PresentFrame(() => Renderer?.SwapBuffers());
|
||||||
@@ -865,13 +818,12 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
public void UpdateStatus()
|
public void UpdateStatus()
|
||||||
{
|
{
|
||||||
// Run a status update only when a frame is to be drawn. This prevents from updating the ui and wasting a render when no frame is queued
|
// Run a status update only when a frame is to be drawn. This prevents from updating the ui and wasting a render when no frame is queued.
|
||||||
string dockedMode = ConfigurationState.Instance.System.EnableDockedMode ? LocaleManager.Instance[LocaleKeys.Docked] : LocaleManager.Instance[LocaleKeys.Handheld];
|
string dockedMode = ConfigurationState.Instance.System.EnableDockedMode ? LocaleManager.Instance[LocaleKeys.Docked] : LocaleManager.Instance[LocaleKeys.Handheld];
|
||||||
float scale = GraphicsConfig.ResScale;
|
|
||||||
|
|
||||||
if (scale != 1)
|
if (GraphicsConfig.ResScale != 1)
|
||||||
{
|
{
|
||||||
dockedMode += $" ({scale}x)";
|
dockedMode += $" ({GraphicsConfig.ResScale}x)";
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusUpdatedEvent?.Invoke(this, new StatusUpdatedEventArgs(
|
StatusUpdatedEvent?.Invoke(this, new StatusUpdatedEventArgs(
|
||||||
@@ -888,7 +840,6 @@ namespace Ryujinx.Ava
|
|||||||
public async Task ShowExitPrompt()
|
public async Task ShowExitPrompt()
|
||||||
{
|
{
|
||||||
bool shouldExit = !ConfigurationState.Instance.ShowConfirmExit;
|
bool shouldExit = !ConfigurationState.Instance.ShowConfirmExit;
|
||||||
|
|
||||||
if (!shouldExit)
|
if (!shouldExit)
|
||||||
{
|
{
|
||||||
if (_dialogShown)
|
if (_dialogShown)
|
||||||
@@ -897,6 +848,7 @@ namespace Ryujinx.Ava
|
|||||||
}
|
}
|
||||||
|
|
||||||
_dialogShown = true;
|
_dialogShown = true;
|
||||||
|
|
||||||
shouldExit = await ContentDialogHelper.CreateStopEmulationDialog();
|
shouldExit = await ContentDialogHelper.CreateStopEmulationDialog();
|
||||||
|
|
||||||
_dialogShown = false;
|
_dialogShown = false;
|
||||||
@@ -914,7 +866,7 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
{
|
{
|
||||||
_parent.Cursor = _isMouseInRenderer ? InvisibleCursor : Cursor.Default;
|
_viewModel.Cursor = _isCursorInRenderer ? InvisibleCursor : Cursor.Default;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -925,7 +877,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
{
|
{
|
||||||
_parent.Cursor = cursorMoveDelta >= CursorHideIdleTime * Stopwatch.Frequency ? InvisibleCursor : Cursor.Default;
|
_viewModel.Cursor = cursorMoveDelta >= CursorHideIdleTime * Stopwatch.Frequency ? InvisibleCursor : Cursor.Default;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -938,13 +890,13 @@ namespace Ryujinx.Ava
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_parent.IsActive)
|
if (_viewModel.IsActive)
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
{
|
{
|
||||||
HandleScreenState();
|
HandleScreenState();
|
||||||
|
|
||||||
if (_keyboardInterface.GetKeyboardStateSnapshot().IsPressed(Key.Delete) && _parent.WindowState != WindowState.FullScreen)
|
if (_keyboardInterface.GetKeyboardStateSnapshot().IsPressed(Key.Delete) && _viewModel.WindowState != WindowState.FullScreen)
|
||||||
{
|
{
|
||||||
Device.Application.DiskCacheLoadState?.Cancel();
|
Device.Application.DiskCacheLoadState?.Cancel();
|
||||||
}
|
}
|
||||||
@@ -953,7 +905,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
NpadManager.Update(ConfigurationState.Instance.Graphics.AspectRatio.Value.ToFloat());
|
NpadManager.Update(ConfigurationState.Instance.Graphics.AspectRatio.Value.ToFloat());
|
||||||
|
|
||||||
if (_parent.IsActive)
|
if (_viewModel.IsActive)
|
||||||
{
|
{
|
||||||
KeyboardHotkeyState currentHotkeyState = GetHotkeyState();
|
KeyboardHotkeyState currentHotkeyState = GetHotkeyState();
|
||||||
|
|
||||||
@@ -969,10 +921,10 @@ namespace Ryujinx.Ava
|
|||||||
ScreenshotRequested = true;
|
ScreenshotRequested = true;
|
||||||
break;
|
break;
|
||||||
case KeyboardHotkeyState.ShowUi:
|
case KeyboardHotkeyState.ShowUi:
|
||||||
_parent.ViewModel.ShowMenuAndStatusBar = true;
|
_viewModel.ShowMenuAndStatusBar = true;
|
||||||
break;
|
break;
|
||||||
case KeyboardHotkeyState.Pause:
|
case KeyboardHotkeyState.Pause:
|
||||||
if (_parent.ViewModel.IsPaused)
|
if (_viewModel.IsPaused)
|
||||||
{
|
{
|
||||||
Resume();
|
Resume();
|
||||||
}
|
}
|
||||||
@@ -991,7 +943,7 @@ namespace Ryujinx.Ava
|
|||||||
Device.SetVolume(0);
|
Device.SetVolume(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
_parent.ViewModel.Volume = Device.GetVolume();
|
_viewModel.Volume = Device.GetVolume();
|
||||||
break;
|
break;
|
||||||
case KeyboardHotkeyState.ResScaleUp:
|
case KeyboardHotkeyState.ResScaleUp:
|
||||||
GraphicsConfig.ResScale = GraphicsConfig.ResScale % MaxResolutionScale + 1;
|
GraphicsConfig.ResScale = GraphicsConfig.ResScale % MaxResolutionScale + 1;
|
||||||
@@ -1004,13 +956,13 @@ namespace Ryujinx.Ava
|
|||||||
_newVolume = MathF.Round((Device.GetVolume() + VolumeDelta), 2);
|
_newVolume = MathF.Round((Device.GetVolume() + VolumeDelta), 2);
|
||||||
Device.SetVolume(_newVolume);
|
Device.SetVolume(_newVolume);
|
||||||
|
|
||||||
_parent.ViewModel.Volume = Device.GetVolume();
|
_viewModel.Volume = Device.GetVolume();
|
||||||
break;
|
break;
|
||||||
case KeyboardHotkeyState.VolumeDown:
|
case KeyboardHotkeyState.VolumeDown:
|
||||||
_newVolume = MathF.Round((Device.GetVolume() - VolumeDelta), 2);
|
_newVolume = MathF.Round((Device.GetVolume() - VolumeDelta), 2);
|
||||||
Device.SetVolume(_newVolume);
|
Device.SetVolume(_newVolume);
|
||||||
|
|
||||||
_parent.ViewModel.Volume = Device.GetVolume();
|
_viewModel.Volume = Device.GetVolume();
|
||||||
break;
|
break;
|
||||||
case KeyboardHotkeyState.None:
|
case KeyboardHotkeyState.None:
|
||||||
(_keyboardInterface as AvaloniaKeyboard).Clear();
|
(_keyboardInterface as AvaloniaKeyboard).Clear();
|
||||||
@@ -1027,10 +979,10 @@ namespace Ryujinx.Ava
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Touchscreen
|
// Touchscreen.
|
||||||
bool hasTouch = false;
|
bool hasTouch = false;
|
||||||
|
|
||||||
if (_parent.IsActive && !ConfigurationState.Instance.Hid.EnableMouse)
|
if (_viewModel.IsActive && !ConfigurationState.Instance.Hid.EnableMouse)
|
||||||
{
|
{
|
||||||
hasTouch = TouchScreenManager.Update(true, (_inputManager.MouseDriver as AvaloniaMouseDriver).IsButtonPressed(MouseButton.Button1), ConfigurationState.Instance.Graphics.AspectRatio.Value.ToFloat());
|
hasTouch = TouchScreenManager.Update(true, (_inputManager.MouseDriver as AvaloniaMouseDriver).IsButtonPressed(MouseButton.Button1), ConfigurationState.Instance.Graphics.AspectRatio.Value.ToFloat());
|
||||||
}
|
}
|
||||||
|
@@ -41,10 +41,10 @@
|
|||||||
"GameListHeaderPath": "Pfad",
|
"GameListHeaderPath": "Pfad",
|
||||||
"GameListContextMenuOpenUserSaveDirectory": "Spielstand-Verzeichnis öffnen",
|
"GameListContextMenuOpenUserSaveDirectory": "Spielstand-Verzeichnis öffnen",
|
||||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Öffnet das Verzeichnis, welches den Benutzer-Spielstand beinhaltet",
|
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Öffnet das Verzeichnis, welches den Benutzer-Spielstand beinhaltet",
|
||||||
"GameListContextMenuOpenUserDeviceDirectory": "Benutzer-Geräte-Verzeichnis öffnen",
|
"GameListContextMenuOpenDeviceSaveDirectory": "Benutzer-Geräte-Verzeichnis öffnen",
|
||||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "Öffnet das Verzeichnis, welches den Geräte-Spielstände beinhaltet",
|
"GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Öffnet das Verzeichnis, welches den Geräte-Spielstände beinhaltet",
|
||||||
"GameListContextMenuOpenUserBcatDirectory": "Benutzer-BCAT-Vezeichnis öffnen",
|
"GameListContextMenuOpenBcatSaveDirectory": "Benutzer-BCAT-Vezeichnis öffnen",
|
||||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "Öffnet das Verzeichnis, welches den BCAT Cache des Spiels beinhaltet",
|
"GameListContextMenuOpenBcatSaveDirectoryToolTip": "Öffnet das Verzeichnis, welches den BCAT Cache des Spiels beinhaltet",
|
||||||
"GameListContextMenuManageTitleUpdates": "Verwalten von Spiel Updates",
|
"GameListContextMenuManageTitleUpdates": "Verwalten von Spiel Updates",
|
||||||
"GameListContextMenuManageTitleUpdatesToolTip": "Öffnet den Spiel-Update-Manager",
|
"GameListContextMenuManageTitleUpdatesToolTip": "Öffnet den Spiel-Update-Manager",
|
||||||
"GameListContextMenuManageDlc": "Verwalten von DLC",
|
"GameListContextMenuManageDlc": "Verwalten von DLC",
|
||||||
|
@@ -41,10 +41,10 @@
|
|||||||
"GameListHeaderPath": "Τοποθεσία",
|
"GameListHeaderPath": "Τοποθεσία",
|
||||||
"GameListContextMenuOpenUserSaveDirectory": "Άνοιγμα Τοποθεσίας Αποθήκευσης Χρήστη",
|
"GameListContextMenuOpenUserSaveDirectory": "Άνοιγμα Τοποθεσίας Αποθήκευσης Χρήστη",
|
||||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Ανοίγει την τοποθεσία που περιέχει την Αποθήκευση Χρήστη της εφαρμογής",
|
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Ανοίγει την τοποθεσία που περιέχει την Αποθήκευση Χρήστη της εφαρμογής",
|
||||||
"GameListContextMenuOpenUserDeviceDirectory": "Άνοιγμα Τοποθεσίας Συσκευής Χρήστη",
|
"GameListContextMenuOpenDeviceSaveDirectory": "Άνοιγμα Τοποθεσίας Συσκευής Χρήστη",
|
||||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "Ανοίγει την τοποθεσία που περιέχει την Αποθήκευση Συσκευής της εφαρμογής",
|
"GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Ανοίγει την τοποθεσία που περιέχει την Αποθήκευση Συσκευής της εφαρμογής",
|
||||||
"GameListContextMenuOpenUserBcatDirectory": "Άνοιγμα Τοποθεσίας BCAT",
|
"GameListContextMenuOpenBcatSaveDirectory": "Άνοιγμα Τοποθεσίας BCAT",
|
||||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "Ανοίγει την τοποθεσία που περιέχει την Αποθήκευση BCAT της εφαρμογής",
|
"GameListContextMenuOpenBcatSaveDirectoryToolTip": "Ανοίγει την τοποθεσία που περιέχει την Αποθήκευση BCAT της εφαρμογής",
|
||||||
"GameListContextMenuManageTitleUpdates": "Διαχείριση Ενημερώσεων Παιχνιδιού",
|
"GameListContextMenuManageTitleUpdates": "Διαχείριση Ενημερώσεων Παιχνιδιού",
|
||||||
"GameListContextMenuManageTitleUpdatesToolTip": "Ανοίγει το παράθυρο διαχείρισης Ενημερώσεων Παιχνιδιού",
|
"GameListContextMenuManageTitleUpdatesToolTip": "Ανοίγει το παράθυρο διαχείρισης Ενημερώσεων Παιχνιδιού",
|
||||||
"GameListContextMenuManageDlc": "Διαχείριση DLC",
|
"GameListContextMenuManageDlc": "Διαχείριση DLC",
|
||||||
|
@@ -41,10 +41,10 @@
|
|||||||
"GameListHeaderPath": "Path",
|
"GameListHeaderPath": "Path",
|
||||||
"GameListContextMenuOpenUserSaveDirectory": "Open User Save Directory",
|
"GameListContextMenuOpenUserSaveDirectory": "Open User Save Directory",
|
||||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Opens the directory which contains Application's User Save",
|
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Opens the directory which contains Application's User Save",
|
||||||
"GameListContextMenuOpenUserDeviceDirectory": "Open User Device Directory",
|
"GameListContextMenuOpenDeviceSaveDirectory": "Open Device Save Directory",
|
||||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "Opens the directory which contains Application's Device Save",
|
"GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Opens the directory which contains Application's Device Save",
|
||||||
"GameListContextMenuOpenUserBcatDirectory": "Open User BCAT Directory",
|
"GameListContextMenuOpenBcatSaveDirectory": "Open BCAT Save Directory",
|
||||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "Opens the directory which contains Application's BCAT Save",
|
"GameListContextMenuOpenBcatSaveDirectoryToolTip": "Opens the directory which contains Application's BCAT Save",
|
||||||
"GameListContextMenuManageTitleUpdates": "Manage Title Updates",
|
"GameListContextMenuManageTitleUpdates": "Manage Title Updates",
|
||||||
"GameListContextMenuManageTitleUpdatesToolTip": "Opens the Title Update management window",
|
"GameListContextMenuManageTitleUpdatesToolTip": "Opens the Title Update management window",
|
||||||
"GameListContextMenuManageDlc": "Manage DLC",
|
"GameListContextMenuManageDlc": "Manage DLC",
|
||||||
|
@@ -41,10 +41,10 @@
|
|||||||
"GameListHeaderPath": "Directorio",
|
"GameListHeaderPath": "Directorio",
|
||||||
"GameListContextMenuOpenUserSaveDirectory": "Abrir carpeta de guardado de este usuario",
|
"GameListContextMenuOpenUserSaveDirectory": "Abrir carpeta de guardado de este usuario",
|
||||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Abre la carpeta que contiene la partida guardada del usuario para esta aplicación",
|
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Abre la carpeta que contiene la partida guardada del usuario para esta aplicación",
|
||||||
"GameListContextMenuOpenUserDeviceDirectory": "Abrir carpeta de guardado del sistema para el usuario actual",
|
"GameListContextMenuOpenDeviceSaveDirectory": "Abrir carpeta de guardado del sistema para el usuario actual",
|
||||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "Abre la carpeta que contiene la partida guardada del sistema para esta aplicación",
|
"GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Abre la carpeta que contiene la partida guardada del sistema para esta aplicación",
|
||||||
"GameListContextMenuOpenUserBcatDirectory": "Abrir carpeta de guardado BCAT del usuario",
|
"GameListContextMenuOpenBcatSaveDirectory": "Abrir carpeta de guardado BCAT del usuario",
|
||||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "Abrir la carpeta que contiene el guardado BCAT de esta aplicación",
|
"GameListContextMenuOpenBcatSaveDirectoryToolTip": "Abrir la carpeta que contiene el guardado BCAT de esta aplicación",
|
||||||
"GameListContextMenuManageTitleUpdates": "Gestionar actualizaciones del juego",
|
"GameListContextMenuManageTitleUpdates": "Gestionar actualizaciones del juego",
|
||||||
"GameListContextMenuManageTitleUpdatesToolTip": "Abrir la ventana de gestión de actualizaciones de esta aplicación",
|
"GameListContextMenuManageTitleUpdatesToolTip": "Abrir la ventana de gestión de actualizaciones de esta aplicación",
|
||||||
"GameListContextMenuManageDlc": "Gestionar DLC",
|
"GameListContextMenuManageDlc": "Gestionar DLC",
|
||||||
|
@@ -41,10 +41,10 @@
|
|||||||
"GameListHeaderPath": "Chemin",
|
"GameListHeaderPath": "Chemin",
|
||||||
"GameListContextMenuOpenUserSaveDirectory": "Ouvrir le dossier de sauvegarde utilisateur",
|
"GameListContextMenuOpenUserSaveDirectory": "Ouvrir le dossier de sauvegarde utilisateur",
|
||||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Ouvre le dossier contenant la sauvegarde utilisateur du jeu",
|
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Ouvre le dossier contenant la sauvegarde utilisateur du jeu",
|
||||||
"GameListContextMenuOpenUserDeviceDirectory": "Ouvrir le dossier de sauvegarde console",
|
"GameListContextMenuOpenDeviceSaveDirectory": "Ouvrir le dossier de sauvegarde console",
|
||||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "Ouvre le dossier contenant la sauvegarde console du jeu",
|
"GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Ouvre le dossier contenant la sauvegarde console du jeu",
|
||||||
"GameListContextMenuOpenUserBcatDirectory": "Ouvrir le dossier de sauvegarde BCAT",
|
"GameListContextMenuOpenBcatSaveDirectory": "Ouvrir le dossier de sauvegarde BCAT",
|
||||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "Ouvre le dossier contenant la sauvegarde BCAT du jeu",
|
"GameListContextMenuOpenBcatSaveDirectoryToolTip": "Ouvre le dossier contenant la sauvegarde BCAT du jeu",
|
||||||
"GameListContextMenuManageTitleUpdates": "Gérer les mises à jour",
|
"GameListContextMenuManageTitleUpdates": "Gérer les mises à jour",
|
||||||
"GameListContextMenuManageTitleUpdatesToolTip": "Ouvre la fenêtre de gestion des mises à jour",
|
"GameListContextMenuManageTitleUpdatesToolTip": "Ouvre la fenêtre de gestion des mises à jour",
|
||||||
"GameListContextMenuManageDlc": "Gérer les DLC",
|
"GameListContextMenuManageDlc": "Gérer les DLC",
|
||||||
|
@@ -41,10 +41,10 @@
|
|||||||
"GameListHeaderPath": "Percorso",
|
"GameListHeaderPath": "Percorso",
|
||||||
"GameListContextMenuOpenUserSaveDirectory": "Apri la cartella salvataggi dell'utente",
|
"GameListContextMenuOpenUserSaveDirectory": "Apri la cartella salvataggi dell'utente",
|
||||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Apre la cartella che contiene i salvataggi di gioco dell'utente",
|
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Apre la cartella che contiene i salvataggi di gioco dell'utente",
|
||||||
"GameListContextMenuOpenUserDeviceDirectory": "Apri la cartella dispositivo dell'utente",
|
"GameListContextMenuOpenDeviceSaveDirectory": "Apri la cartella dispositivo dell'utente",
|
||||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "Apre la cartella che contiene i salvataggi di gioco del dispositivo",
|
"GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Apre la cartella che contiene i salvataggi di gioco del dispositivo",
|
||||||
"GameListContextMenuOpenUserBcatDirectory": "Apri la cartella BCAT dell'utente",
|
"GameListContextMenuOpenBcatSaveDirectory": "Apri la cartella BCAT dell'utente",
|
||||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "Apre la cartella che contiene i salvataggi BCAT dell'applicazione",
|
"GameListContextMenuOpenBcatSaveDirectoryToolTip": "Apre la cartella che contiene i salvataggi BCAT dell'applicazione",
|
||||||
"GameListContextMenuManageTitleUpdates": "Gestisci aggiornamenti del gioco",
|
"GameListContextMenuManageTitleUpdates": "Gestisci aggiornamenti del gioco",
|
||||||
"GameListContextMenuManageTitleUpdatesToolTip": "Apre la finestra di gestione aggiornamenti del gioco",
|
"GameListContextMenuManageTitleUpdatesToolTip": "Apre la finestra di gestione aggiornamenti del gioco",
|
||||||
"GameListContextMenuManageDlc": "Gestici DLC",
|
"GameListContextMenuManageDlc": "Gestici DLC",
|
||||||
|
@@ -41,10 +41,10 @@
|
|||||||
"GameListHeaderPath": "パス",
|
"GameListHeaderPath": "パス",
|
||||||
"GameListContextMenuOpenUserSaveDirectory": "セーブディレクトリを開く",
|
"GameListContextMenuOpenUserSaveDirectory": "セーブディレクトリを開く",
|
||||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "アプリケーションのユーザセーブデータを格納するディレクトリを開きます",
|
"GameListContextMenuOpenUserSaveDirectoryToolTip": "アプリケーションのユーザセーブデータを格納するディレクトリを開きます",
|
||||||
"GameListContextMenuOpenUserDeviceDirectory": "デバイスディレクトリを開く",
|
"GameListContextMenuOpenDeviceSaveDirectory": "デバイスディレクトリを開く",
|
||||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "アプリケーションのデバイスセーブデータを格納するディレクトリを開きます",
|
"GameListContextMenuOpenDeviceSaveDirectoryToolTip": "アプリケーションのデバイスセーブデータを格納するディレクトリを開きます",
|
||||||
"GameListContextMenuOpenUserBcatDirectory": "BCATディレクトリを開く",
|
"GameListContextMenuOpenBcatSaveDirectory": "BCATディレクトリを開く",
|
||||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "アプリケーションの BCAT セーブデータを格納するディレクトリを開きます",
|
"GameListContextMenuOpenBcatSaveDirectoryToolTip": "アプリケーションの BCAT セーブデータを格納するディレクトリを開きます",
|
||||||
"GameListContextMenuManageTitleUpdates": "アップデートを管理",
|
"GameListContextMenuManageTitleUpdates": "アップデートを管理",
|
||||||
"GameListContextMenuManageTitleUpdatesToolTip": "タイトルのアップデート管理ウインドウを開きます",
|
"GameListContextMenuManageTitleUpdatesToolTip": "タイトルのアップデート管理ウインドウを開きます",
|
||||||
"GameListContextMenuManageDlc": "DLCを管理",
|
"GameListContextMenuManageDlc": "DLCを管理",
|
||||||
|
@@ -41,10 +41,10 @@
|
|||||||
"GameListHeaderPath": "경로",
|
"GameListHeaderPath": "경로",
|
||||||
"GameListContextMenuOpenUserSaveDirectory": "사용자 저장 디렉토리 열기\n",
|
"GameListContextMenuOpenUserSaveDirectory": "사용자 저장 디렉토리 열기\n",
|
||||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "응용 프로그램의 사용자 저장이 포함된 디렉토리 열기\n",
|
"GameListContextMenuOpenUserSaveDirectoryToolTip": "응용 프로그램의 사용자 저장이 포함된 디렉토리 열기\n",
|
||||||
"GameListContextMenuOpenUserDeviceDirectory": "사용자 장치 디렉토리 열기",
|
"GameListContextMenuOpenDeviceSaveDirectory": "사용자 장치 디렉토리 열기",
|
||||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "응용 프로그램의 장치 저장이 포함된 디렉토리 열기\n",
|
"GameListContextMenuOpenDeviceSaveDirectoryToolTip": "응용 프로그램의 장치 저장이 포함된 디렉토리 열기\n",
|
||||||
"GameListContextMenuOpenUserBcatDirectory": "사용자의 BCAT 디렉토리 열기\n",
|
"GameListContextMenuOpenBcatSaveDirectory": "사용자의 BCAT 디렉토리 열기\n",
|
||||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "응용 프로그램의 BCAT 저장이 포함된 디렉토리 열기\n",
|
"GameListContextMenuOpenBcatSaveDirectoryToolTip": "응용 프로그램의 BCAT 저장이 포함된 디렉토리 열기\n",
|
||||||
"GameListContextMenuManageTitleUpdates": "타이틀 업데이트 관리\n",
|
"GameListContextMenuManageTitleUpdates": "타이틀 업데이트 관리\n",
|
||||||
"GameListContextMenuManageTitleUpdatesToolTip": "타이틀 업데이트 관리 창 열기",
|
"GameListContextMenuManageTitleUpdatesToolTip": "타이틀 업데이트 관리 창 열기",
|
||||||
"GameListContextMenuManageDlc": "DLC 관리",
|
"GameListContextMenuManageDlc": "DLC 관리",
|
||||||
|
@@ -41,10 +41,10 @@
|
|||||||
"GameListHeaderPath": "Ścieżka",
|
"GameListHeaderPath": "Ścieżka",
|
||||||
"GameListContextMenuOpenUserSaveDirectory": "Otwórz Katalog Zapisów Użytkownika",
|
"GameListContextMenuOpenUserSaveDirectory": "Otwórz Katalog Zapisów Użytkownika",
|
||||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Otwiera katalog, który zawiera Zapis Użytkownika Aplikacji",
|
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Otwiera katalog, który zawiera Zapis Użytkownika Aplikacji",
|
||||||
"GameListContextMenuOpenUserDeviceDirectory": "Otwórz Katalog Urządzeń Użytkownika",
|
"GameListContextMenuOpenDeviceSaveDirectory": "Otwórz Katalog Urządzeń Użytkownika",
|
||||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "Otwiera katalog, który zawiera Zapis Urządzenia Aplikacji",
|
"GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Otwiera katalog, który zawiera Zapis Urządzenia Aplikacji",
|
||||||
"GameListContextMenuOpenUserBcatDirectory": "Otwórz Katalog BCAT Użytkownika",
|
"GameListContextMenuOpenBcatSaveDirectory": "Otwórz Katalog BCAT Użytkownika",
|
||||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "Otwiera katalog, który zawiera Zapis BCAT Aplikacji",
|
"GameListContextMenuOpenBcatSaveDirectoryToolTip": "Otwiera katalog, który zawiera Zapis BCAT Aplikacji",
|
||||||
"GameListContextMenuManageTitleUpdates": "Zarządzaj Aktualizacjami Tytułów",
|
"GameListContextMenuManageTitleUpdates": "Zarządzaj Aktualizacjami Tytułów",
|
||||||
"GameListContextMenuManageTitleUpdatesToolTip": "Otwiera okno zarządzania Aktualizacjami Tytułu",
|
"GameListContextMenuManageTitleUpdatesToolTip": "Otwiera okno zarządzania Aktualizacjami Tytułu",
|
||||||
"GameListContextMenuManageDlc": "Zarządzaj DLC",
|
"GameListContextMenuManageDlc": "Zarządzaj DLC",
|
||||||
|
@@ -41,10 +41,10 @@
|
|||||||
"GameListHeaderPath": "Caminho",
|
"GameListHeaderPath": "Caminho",
|
||||||
"GameListContextMenuOpenUserSaveDirectory": "Abrir diretório de saves do usuário",
|
"GameListContextMenuOpenUserSaveDirectory": "Abrir diretório de saves do usuário",
|
||||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Abre o diretório que contém jogos salvos para o usuário atual",
|
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Abre o diretório que contém jogos salvos para o usuário atual",
|
||||||
"GameListContextMenuOpenUserDeviceDirectory": "Abrir diretório de saves de dispositivo do usuário",
|
"GameListContextMenuOpenDeviceSaveDirectory": "Abrir diretório de saves de dispositivo do usuário",
|
||||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "Abre o diretório que contém saves do dispositivo para o usuário atual",
|
"GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Abre o diretório que contém saves do dispositivo para o usuário atual",
|
||||||
"GameListContextMenuOpenUserBcatDirectory": "Abrir diretório de saves BCAT do usuário",
|
"GameListContextMenuOpenBcatSaveDirectory": "Abrir diretório de saves BCAT do usuário",
|
||||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "Abre o diretório que contém saves BCAT para o usuário atual",
|
"GameListContextMenuOpenBcatSaveDirectoryToolTip": "Abre o diretório que contém saves BCAT para o usuário atual",
|
||||||
"GameListContextMenuManageTitleUpdates": "Gerenciar atualizações do jogo",
|
"GameListContextMenuManageTitleUpdates": "Gerenciar atualizações do jogo",
|
||||||
"GameListContextMenuManageTitleUpdatesToolTip": "Abre a janela de gerenciamento de atualizações",
|
"GameListContextMenuManageTitleUpdatesToolTip": "Abre a janela de gerenciamento de atualizações",
|
||||||
"GameListContextMenuManageDlc": "Gerenciar DLCs",
|
"GameListContextMenuManageDlc": "Gerenciar DLCs",
|
||||||
|
@@ -41,10 +41,10 @@
|
|||||||
"GameListHeaderPath": "Путь",
|
"GameListHeaderPath": "Путь",
|
||||||
"GameListContextMenuOpenUserSaveDirectory": "Открыть каталог сохранений пользователя",
|
"GameListContextMenuOpenUserSaveDirectory": "Открыть каталог сохранений пользователя",
|
||||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Открывает каталог, содержащий пользовательское сохранение приложения",
|
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Открывает каталог, содержащий пользовательское сохранение приложения",
|
||||||
"GameListContextMenuOpenUserDeviceDirectory": "Открыть каталог пользовательских устройств",
|
"GameListContextMenuOpenDeviceSaveDirectory": "Открыть каталог пользовательских устройств",
|
||||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "Открывает каталог, содержащий сохранение устройства приложения",
|
"GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Открывает каталог, содержащий сохранение устройства приложения",
|
||||||
"GameListContextMenuOpenUserBcatDirectory": "Открыть каталог пользователей BCAT",
|
"GameListContextMenuOpenBcatSaveDirectory": "Открыть каталог пользователей BCAT",
|
||||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "Открывает каталог, содержащий BCAT сохранения приложения.",
|
"GameListContextMenuOpenBcatSaveDirectoryToolTip": "Открывает каталог, содержащий BCAT сохранения приложения.",
|
||||||
"GameListContextMenuManageTitleUpdates": "Управление обновлениями заголовков",
|
"GameListContextMenuManageTitleUpdates": "Управление обновлениями заголовков",
|
||||||
"GameListContextMenuManageTitleUpdatesToolTip": "Открывает окно управления обновлением заголовков",
|
"GameListContextMenuManageTitleUpdatesToolTip": "Открывает окно управления обновлением заголовков",
|
||||||
"GameListContextMenuManageDlc": "Управление DLC",
|
"GameListContextMenuManageDlc": "Управление DLC",
|
||||||
|
@@ -41,10 +41,10 @@
|
|||||||
"GameListHeaderPath": "Yol",
|
"GameListHeaderPath": "Yol",
|
||||||
"GameListContextMenuOpenUserSaveDirectory": "Kullanıcı Kayıt Dosyası Dizinini Aç",
|
"GameListContextMenuOpenUserSaveDirectory": "Kullanıcı Kayıt Dosyası Dizinini Aç",
|
||||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Uygulamanın Kullanıcı Kaydı'nın bulunduğu dizini açar",
|
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Uygulamanın Kullanıcı Kaydı'nın bulunduğu dizini açar",
|
||||||
"GameListContextMenuOpenUserDeviceDirectory": "Kullanıcı Cihaz Dizinini Aç",
|
"GameListContextMenuOpenDeviceSaveDirectory": "Kullanıcı Cihaz Dizinini Aç",
|
||||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "Uygulamanın Kullanıcı Cihaz Kaydı'nın bulunduğu dizini açar",
|
"GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Uygulamanın Kullanıcı Cihaz Kaydı'nın bulunduğu dizini açar",
|
||||||
"GameListContextMenuOpenUserBcatDirectory": "Kullanıcı BCAT Dizinini Aç",
|
"GameListContextMenuOpenBcatSaveDirectory": "Kullanıcı BCAT Dizinini Aç",
|
||||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "Uygulamanın Kullanıcı BCAT Kaydı'nın bulunduğu dizini açar",
|
"GameListContextMenuOpenBcatSaveDirectoryToolTip": "Uygulamanın Kullanıcı BCAT Kaydı'nın bulunduğu dizini açar",
|
||||||
"GameListContextMenuManageTitleUpdates": "Oyun Güncellemelerini Yönet",
|
"GameListContextMenuManageTitleUpdates": "Oyun Güncellemelerini Yönet",
|
||||||
"GameListContextMenuManageTitleUpdatesToolTip": "Oyun Güncelleme Yönetim Penceresini Açar",
|
"GameListContextMenuManageTitleUpdatesToolTip": "Oyun Güncelleme Yönetim Penceresini Açar",
|
||||||
"GameListContextMenuManageDlc": "DLC'leri Yönet",
|
"GameListContextMenuManageDlc": "DLC'leri Yönet",
|
||||||
|
@@ -41,10 +41,10 @@
|
|||||||
"GameListHeaderPath": "Шлях",
|
"GameListHeaderPath": "Шлях",
|
||||||
"GameListContextMenuOpenUserSaveDirectory": "Відкрити каталог збереження користувача",
|
"GameListContextMenuOpenUserSaveDirectory": "Відкрити каталог збереження користувача",
|
||||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Відкриває каталог, який містить збереження користувача програми",
|
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Відкриває каталог, який містить збереження користувача програми",
|
||||||
"GameListContextMenuOpenUserDeviceDirectory": "Відкрити каталог пристроїв користувача",
|
"GameListContextMenuOpenDeviceSaveDirectory": "Відкрити каталог пристроїв користувача",
|
||||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "Відкриває каталог, який містить збереження пристрою програми",
|
"GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Відкриває каталог, який містить збереження пристрою програми",
|
||||||
"GameListContextMenuOpenUserBcatDirectory": "Відкрити каталог користувача BCAT",
|
"GameListContextMenuOpenBcatSaveDirectory": "Відкрити каталог користувача BCAT",
|
||||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "Відкриває каталог, який містить BCAT-збереження програми",
|
"GameListContextMenuOpenBcatSaveDirectoryToolTip": "Відкриває каталог, який містить BCAT-збереження програми",
|
||||||
"GameListContextMenuManageTitleUpdates": "Керування оновленнями заголовків",
|
"GameListContextMenuManageTitleUpdates": "Керування оновленнями заголовків",
|
||||||
"GameListContextMenuManageTitleUpdatesToolTip": "Відкриває вікно керування оновленням заголовка",
|
"GameListContextMenuManageTitleUpdatesToolTip": "Відкриває вікно керування оновленням заголовка",
|
||||||
"GameListContextMenuManageDlc": "Керування DLC",
|
"GameListContextMenuManageDlc": "Керування DLC",
|
||||||
|
@@ -41,10 +41,10 @@
|
|||||||
"GameListHeaderPath": "路径",
|
"GameListHeaderPath": "路径",
|
||||||
"GameListContextMenuOpenUserSaveDirectory": "打开应用存档目录",
|
"GameListContextMenuOpenUserSaveDirectory": "打开应用存档目录",
|
||||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "打开储存游戏存档的目录",
|
"GameListContextMenuOpenUserSaveDirectoryToolTip": "打开储存游戏存档的目录",
|
||||||
"GameListContextMenuOpenUserDeviceDirectory": "打开应用系统目录",
|
"GameListContextMenuOpenDeviceSaveDirectory": "打开应用系统目录",
|
||||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "打开包含游戏系统设置的目录",
|
"GameListContextMenuOpenDeviceSaveDirectoryToolTip": "打开包含游戏系统设置的目录",
|
||||||
"GameListContextMenuOpenUserBcatDirectory": "打开 BCAT 目录",
|
"GameListContextMenuOpenBcatSaveDirectory": "打开 BCAT 目录",
|
||||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "打开包含游戏 BCAT 数据的目录",
|
"GameListContextMenuOpenBcatSaveDirectoryToolTip": "打开包含游戏 BCAT 数据的目录",
|
||||||
"GameListContextMenuManageTitleUpdates": "管理游戏更新",
|
"GameListContextMenuManageTitleUpdates": "管理游戏更新",
|
||||||
"GameListContextMenuManageTitleUpdatesToolTip": "打开更新管理器",
|
"GameListContextMenuManageTitleUpdatesToolTip": "打开更新管理器",
|
||||||
"GameListContextMenuManageDlc": "管理 DLC",
|
"GameListContextMenuManageDlc": "管理 DLC",
|
||||||
|
@@ -41,10 +41,10 @@
|
|||||||
"GameListHeaderPath": "路徑",
|
"GameListHeaderPath": "路徑",
|
||||||
"GameListContextMenuOpenUserSaveDirectory": "開啟使用者存檔資料夾",
|
"GameListContextMenuOpenUserSaveDirectory": "開啟使用者存檔資料夾",
|
||||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "開啟儲存遊戲存檔的資料夾",
|
"GameListContextMenuOpenUserSaveDirectoryToolTip": "開啟儲存遊戲存檔的資料夾",
|
||||||
"GameListContextMenuOpenUserDeviceDirectory": "開啟系統資料夾",
|
"GameListContextMenuOpenDeviceSaveDirectory": "開啟系統資料夾",
|
||||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "開啟包含遊戲系統設定的資料夾",
|
"GameListContextMenuOpenDeviceSaveDirectoryToolTip": "開啟包含遊戲系統設定的資料夾",
|
||||||
"GameListContextMenuOpenUserBcatDirectory": "開啟 BCAT 資料夾",
|
"GameListContextMenuOpenBcatSaveDirectory": "開啟 BCAT 資料夾",
|
||||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "開啟包含遊戲 BCAT 資料的資料夾",
|
"GameListContextMenuOpenBcatSaveDirectoryToolTip": "開啟包含遊戲 BCAT 資料的資料夾",
|
||||||
"GameListContextMenuManageTitleUpdates": "管理遊戲更新",
|
"GameListContextMenuManageTitleUpdates": "管理遊戲更新",
|
||||||
"GameListContextMenuManageTitleUpdatesToolTip": "開啟更新管理視窗",
|
"GameListContextMenuManageTitleUpdatesToolTip": "開啟更新管理視窗",
|
||||||
"GameListContextMenuManageDlc": "管理 DLC",
|
"GameListContextMenuManageDlc": "管理 DLC",
|
||||||
|
@@ -269,6 +269,8 @@
|
|||||||
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
|
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
|
||||||
<Color x:Key="ThemeContentBackgroundColor">#FF2D2D2D</Color>
|
<Color x:Key="ThemeContentBackgroundColor">#FF2D2D2D</Color>
|
||||||
<Color x:Key="ThemeControlBorderColor">#FF505050</Color>
|
<Color x:Key="ThemeControlBorderColor">#FF505050</Color>
|
||||||
|
<Color x:Key="VsyncEnabled">#FF2EEAC9</Color>
|
||||||
|
<Color x:Key="VsyncDisabled">#FFFF4554</Color>
|
||||||
<x:Double x:Key="ScrollBarThickness">15</x:Double>
|
<x:Double x:Key="ScrollBarThickness">15</x:Double>
|
||||||
<x:Double x:Key="FontSizeSmall">8</x:Double>
|
<x:Double x:Key="FontSizeSmall">8</x:Double>
|
||||||
<x:Double x:Key="FontSizeNormal">10</x:Double>
|
<x:Double x:Key="FontSizeNormal">10</x:Double>
|
||||||
|
111
Ryujinx.Ava/Helper/LoggerAdapter.cs
Normal file
111
Ryujinx.Ava/Helper/LoggerAdapter.cs
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
using Avalonia.Utilities;
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Helper
|
||||||
|
{
|
||||||
|
using AvaLogger = Avalonia.Logging.Logger;
|
||||||
|
using AvaLogLevel = Avalonia.Logging.LogEventLevel;
|
||||||
|
using RyuLogger = Ryujinx.Common.Logging.Logger;
|
||||||
|
using RyuLogClass = Ryujinx.Common.Logging.LogClass;
|
||||||
|
|
||||||
|
internal class LoggerAdapter : Avalonia.Logging.ILogSink
|
||||||
|
{
|
||||||
|
public static void Register()
|
||||||
|
{
|
||||||
|
AvaLogger.Sink = new LoggerAdapter();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RyuLogger.Log? GetLog(AvaLogLevel level)
|
||||||
|
{
|
||||||
|
return level switch
|
||||||
|
{
|
||||||
|
AvaLogLevel.Verbose => RyuLogger.Trace,
|
||||||
|
AvaLogLevel.Debug => RyuLogger.Debug,
|
||||||
|
AvaLogLevel.Information => RyuLogger.Info,
|
||||||
|
AvaLogLevel.Warning => RyuLogger.Warning,
|
||||||
|
AvaLogLevel.Error => RyuLogger.Error,
|
||||||
|
AvaLogLevel.Fatal => RyuLogger.Notice,
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(level), level, null)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsEnabled(AvaLogLevel level, string area)
|
||||||
|
{
|
||||||
|
return GetLog(level) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log(AvaLogLevel level, string area, object source, string messageTemplate)
|
||||||
|
{
|
||||||
|
GetLog(level)?.PrintMsg(RyuLogClass.Ui, Format(area, messageTemplate, source, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log<T0>(AvaLogLevel level, string area, object source, string messageTemplate, T0 propertyValue0)
|
||||||
|
{
|
||||||
|
GetLog(level)?.PrintMsg(RyuLogClass.Ui, Format(area, messageTemplate, source, new object[] { propertyValue0 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log<T0, T1>(AvaLogLevel level, string area, object source, string messageTemplate, T0 propertyValue0, T1 propertyValue1)
|
||||||
|
{
|
||||||
|
GetLog(level)?.PrintMsg(RyuLogClass.Ui, Format(area, messageTemplate, source, new object[] { propertyValue0, propertyValue1 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log<T0, T1, T2>(AvaLogLevel level, string area, object source, string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2)
|
||||||
|
{
|
||||||
|
GetLog(level)?.PrintMsg(RyuLogClass.Ui, Format(area, messageTemplate, source, new object[] { propertyValue0, propertyValue1, propertyValue2 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log(AvaLogLevel level, string area, object source, string messageTemplate, params object[] propertyValues)
|
||||||
|
{
|
||||||
|
GetLog(level)?.PrintMsg(RyuLogClass.Ui, Format(area, messageTemplate, source, propertyValues));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string Format(string area, string template, object source, object[] v)
|
||||||
|
{
|
||||||
|
var result = new StringBuilder();
|
||||||
|
var r = new CharacterReader(template.AsSpan());
|
||||||
|
var i = 0;
|
||||||
|
|
||||||
|
result.Append('[');
|
||||||
|
result.Append(area);
|
||||||
|
result.Append("] ");
|
||||||
|
|
||||||
|
while (!r.End)
|
||||||
|
{
|
||||||
|
var c = r.Take();
|
||||||
|
|
||||||
|
if (c != '{')
|
||||||
|
{
|
||||||
|
result.Append(c);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (r.Peek != '{')
|
||||||
|
{
|
||||||
|
result.Append('\'');
|
||||||
|
result.Append(i < v.Length ? v[i++] : null);
|
||||||
|
result.Append('\'');
|
||||||
|
r.TakeUntil('}');
|
||||||
|
r.Take();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.Append('{');
|
||||||
|
r.Take();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source != null)
|
||||||
|
{
|
||||||
|
result.Append(" (");
|
||||||
|
result.Append(source.GetType().Name);
|
||||||
|
result.Append(" #");
|
||||||
|
result.Append(source.GetHashCode());
|
||||||
|
result.Append(')');
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -11,10 +11,10 @@ namespace Ryujinx.Ava.Input
|
|||||||
{
|
{
|
||||||
internal class AvaloniaMouseDriver : IGamepadDriver
|
internal class AvaloniaMouseDriver : IGamepadDriver
|
||||||
{
|
{
|
||||||
private Control _widget;
|
private Control _widget;
|
||||||
private bool _isDisposed;
|
private bool _isDisposed;
|
||||||
private Size _size;
|
private Size _size;
|
||||||
private readonly Window _window;
|
private readonly TopLevel _window;
|
||||||
|
|
||||||
public bool[] PressedButtons { get; }
|
public bool[] PressedButtons { get; }
|
||||||
public Vector2 CurrentPosition { get; private set; }
|
public Vector2 CurrentPosition { get; private set; }
|
||||||
@@ -23,7 +23,7 @@ namespace Ryujinx.Ava.Input
|
|||||||
public string DriverName => "AvaloniaMouseDriver";
|
public string DriverName => "AvaloniaMouseDriver";
|
||||||
public ReadOnlySpan<string> GamepadsIds => new[] { "0" };
|
public ReadOnlySpan<string> GamepadsIds => new[] { "0" };
|
||||||
|
|
||||||
public AvaloniaMouseDriver(Window window, Control parent)
|
public AvaloniaMouseDriver(TopLevel window, Control parent)
|
||||||
{
|
{
|
||||||
_widget = parent;
|
_widget = parent;
|
||||||
_window = window;
|
_window = window;
|
||||||
|
@@ -56,7 +56,7 @@ namespace Ryujinx.Modules
|
|||||||
}
|
}
|
||||||
|
|
||||||
Running = true;
|
Running = true;
|
||||||
mainWindow.CanUpdate = false;
|
mainWindow.ViewModel.CanUpdate = false;
|
||||||
|
|
||||||
// Detect current platform
|
// Detect current platform
|
||||||
if (OperatingSystem.IsMacOS())
|
if (OperatingSystem.IsMacOS())
|
||||||
@@ -95,7 +95,7 @@ namespace Ryujinx.Modules
|
|||||||
{
|
{
|
||||||
using (HttpClient jsonClient = ConstructHttpClient())
|
using (HttpClient jsonClient = ConstructHttpClient())
|
||||||
{
|
{
|
||||||
string buildInfoURL = $"{GitHubApiURL}/repos/{ReleaseInformations.ReleaseChannelOwner}/{ReleaseInformations.ReleaseChannelRepo}/releases/latest";
|
string buildInfoURL = $"{GitHubApiURL}/repos/{ReleaseInformation.ReleaseChannelOwner}/{ReleaseInformation.ReleaseChannelRepo}/releases/latest";
|
||||||
|
|
||||||
string fetchedJson = await jsonClient.GetStringAsync(buildInfoURL);
|
string fetchedJson = await jsonClient.GetStringAsync(buildInfoURL);
|
||||||
JObject jsonRoot = JObject.Parse(fetchedJson);
|
JObject jsonRoot = JObject.Parse(fetchedJson);
|
||||||
@@ -182,7 +182,7 @@ namespace Ryujinx.Modules
|
|||||||
}
|
}
|
||||||
|
|
||||||
Running = false;
|
Running = false;
|
||||||
mainWindow.CanUpdate = true;
|
mainWindow.ViewModel.CanUpdate = true;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -625,7 +625,7 @@ namespace Ryujinx.Modules
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Program.Version.Contains("dirty") || !ReleaseInformations.IsValid())
|
if (Program.Version.Contains("dirty") || !ReleaseInformation.IsValid())
|
||||||
{
|
{
|
||||||
if (showWarnings)
|
if (showWarnings)
|
||||||
{
|
{
|
||||||
@@ -640,7 +640,7 @@ namespace Ryujinx.Modules
|
|||||||
#else
|
#else
|
||||||
if (showWarnings)
|
if (showWarnings)
|
||||||
{
|
{
|
||||||
if (ReleaseInformations.IsFlatHubBuild())
|
if (ReleaseInformation.IsFlatHubBuild())
|
||||||
{
|
{
|
||||||
ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance[LocaleKeys.UpdaterDisabledWarningTitle], LocaleManager.Instance[LocaleKeys.DialogUpdaterFlatpakNotSupportedMessage]);
|
ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance[LocaleKeys.UpdaterDisabledWarningTitle], LocaleManager.Instance[LocaleKeys.DialogUpdaterFlatpakNotSupportedMessage]);
|
||||||
}
|
}
|
||||||
|
@@ -1,20 +1,23 @@
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
using Ryujinx.Ava.UI.Helper;
|
||||||
using Ryujinx.Ava.UI.Windows;
|
using Ryujinx.Ava.UI.Windows;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.GraphicsDriver;
|
using Ryujinx.Common.GraphicsDriver;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Common.SystemInterop;
|
|
||||||
using Ryujinx.Common.SystemInfo;
|
using Ryujinx.Common.SystemInfo;
|
||||||
|
using Ryujinx.Common.SystemInterop;
|
||||||
using Ryujinx.Modules;
|
using Ryujinx.Modules;
|
||||||
using Ryujinx.SDL2.Common;
|
using Ryujinx.SDL2.Common;
|
||||||
using Ryujinx.Ui.Common;
|
using Ryujinx.Ui.Common;
|
||||||
using Ryujinx.Ui.Common.Configuration;
|
using Ryujinx.Ui.Common.Configuration;
|
||||||
using Ryujinx.Ui.Common.Helper;
|
using Ryujinx.Ui.Common.Helper;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Ryujinx.Ava
|
namespace Ryujinx.Ava
|
||||||
@@ -32,9 +35,51 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
private const uint MB_ICONWARNING = 0x30;
|
private const uint MB_ICONWARNING = 0x30;
|
||||||
|
|
||||||
|
[SupportedOSPlatform("linux")]
|
||||||
|
static void RegisterMimeTypes()
|
||||||
|
{
|
||||||
|
if (ReleaseInformation.IsFlatHubBuild())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string mimeDbPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".local", "share", "mime");
|
||||||
|
|
||||||
|
if (!File.Exists(Path.Combine(mimeDbPath, "packages", "Ryujinx.xml")))
|
||||||
|
{
|
||||||
|
string mimeTypesFile = Path.Combine(ReleaseInformation.GetBaseApplicationDirectory(), "mime", "Ryujinx.xml");
|
||||||
|
using Process mimeProcess = new();
|
||||||
|
|
||||||
|
mimeProcess.StartInfo.FileName = "xdg-mime";
|
||||||
|
mimeProcess.StartInfo.Arguments = $"install --novendor --mode user {mimeTypesFile}";
|
||||||
|
|
||||||
|
mimeProcess.Start();
|
||||||
|
mimeProcess.WaitForExit();
|
||||||
|
|
||||||
|
if (mimeProcess.ExitCode != 0)
|
||||||
|
{
|
||||||
|
Logger.Error?.PrintMsg(LogClass.Application, $"Unable to install mime types. Make sure xdg-utils is installed. Process exited with code: {mimeProcess.ExitCode}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using Process updateMimeProcess = new();
|
||||||
|
|
||||||
|
updateMimeProcess.StartInfo.FileName = "update-mime-database";
|
||||||
|
updateMimeProcess.StartInfo.Arguments = mimeDbPath;
|
||||||
|
|
||||||
|
updateMimeProcess.Start();
|
||||||
|
updateMimeProcess.WaitForExit();
|
||||||
|
|
||||||
|
if (updateMimeProcess.ExitCode != 0)
|
||||||
|
{
|
||||||
|
Logger.Error?.PrintMsg(LogClass.Application, $"Could not update local mime database. Process exited with code: {updateMimeProcess.ExitCode}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
Version = ReleaseInformations.GetVersion();
|
Version = ReleaseInformation.GetVersion();
|
||||||
|
|
||||||
if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134))
|
if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134))
|
||||||
{
|
{
|
||||||
@@ -45,6 +90,8 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
Initialize(args);
|
Initialize(args);
|
||||||
|
|
||||||
|
LoggerAdapter.Register();
|
||||||
|
|
||||||
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
|
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,8 +113,7 @@ namespace Ryujinx.Ava
|
|||||||
AllowEglInitialization = false,
|
AllowEglInitialization = false,
|
||||||
CompositionBackdropCornerRadius = 8.0f,
|
CompositionBackdropCornerRadius = 8.0f,
|
||||||
})
|
})
|
||||||
.UseSkia()
|
.UseSkia();
|
||||||
.LogToTrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Initialize(string[] args)
|
private static void Initialize(string[] args)
|
||||||
@@ -93,6 +139,12 @@ namespace Ryujinx.Ava
|
|||||||
// Initialize the logger system.
|
// Initialize the logger system.
|
||||||
LoggerModule.Initialize();
|
LoggerModule.Initialize();
|
||||||
|
|
||||||
|
// Register mime types on linux.
|
||||||
|
if (OperatingSystem.IsLinux())
|
||||||
|
{
|
||||||
|
RegisterMimeTypes();
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize Discord integration.
|
// Initialize Discord integration.
|
||||||
DiscordIntegrationModule.Initialize();
|
DiscordIntegrationModule.Initialize();
|
||||||
|
|
||||||
@@ -175,6 +227,12 @@ namespace Ryujinx.Ava
|
|||||||
ConfigurationState.Instance.Graphics.GraphicsBackend.Value = GraphicsBackend.Vulkan;
|
ConfigurationState.Instance.Graphics.GraphicsBackend.Value = GraphicsBackend.Vulkan;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if docked mode was overriden.
|
||||||
|
if (CommandLineState.OverrideDockedMode.HasValue)
|
||||||
|
{
|
||||||
|
ConfigurationState.Instance.System.EnableDockedMode.Value = CommandLineState.OverrideDockedMode.Value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void PrintSystemInfo()
|
private static void PrintSystemInfo()
|
||||||
|
@@ -76,6 +76,16 @@
|
|||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(RuntimeIdentifier)' == 'linux-x64'">
|
||||||
|
<Content Include="..\distribution\linux\Ryujinx.sh">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="..\distribution\linux\mime\Ryujinx.xml">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
<TargetPath>mime\Ryujinx.xml</TargetPath>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AvaloniaResource Include="Ui\**\*.xaml">
|
<AvaloniaResource Include="Ui\**\*.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
|
@@ -144,9 +144,9 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
public void ExecuteProgram(Switch device, ProgramSpecifyKind kind, ulong value)
|
public void ExecuteProgram(Switch device, ProgramSpecifyKind kind, ulong value)
|
||||||
{
|
{
|
||||||
device.Configuration.UserChannelPersistence.ExecuteProgram(kind, value);
|
device.Configuration.UserChannelPersistence.ExecuteProgram(kind, value);
|
||||||
if (_parent.AppHost != null)
|
if (_parent.ViewModel.AppHost != null)
|
||||||
{
|
{
|
||||||
_parent.AppHost.Stop();
|
_parent.ViewModel.AppHost.Stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -136,7 +136,7 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
{
|
{
|
||||||
_hiddenTextBox.Clear();
|
_hiddenTextBox.Clear();
|
||||||
_parent.RendererControl.Focus();
|
_parent.ViewModel.RendererControl.Focus();
|
||||||
|
|
||||||
_parent = null;
|
_parent = null;
|
||||||
});
|
});
|
||||||
|
@@ -13,8 +13,8 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
DefaultBackgroundColor = BrushToThemeColor(parent.Background);
|
DefaultBackgroundColor = BrushToThemeColor(parent.Background);
|
||||||
DefaultForegroundColor = BrushToThemeColor(parent.Foreground);
|
DefaultForegroundColor = BrushToThemeColor(parent.Foreground);
|
||||||
DefaultBorderColor = BrushToThemeColor(parent.BorderBrush);
|
DefaultBorderColor = BrushToThemeColor(parent.BorderBrush);
|
||||||
SelectionBackgroundColor = BrushToThemeColor(parent.SearchBox.SelectionBrush);
|
SelectionBackgroundColor = BrushToThemeColor(parent.ViewControls.SearchBox.SelectionBrush);
|
||||||
SelectionForegroundColor = BrushToThemeColor(parent.SearchBox.SelectionForegroundBrush);
|
SelectionForegroundColor = BrushToThemeColor(parent.ViewControls.SearchBox.SelectionForegroundBrush);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string FontFamily { get; }
|
public string FontFamily { get; }
|
||||||
|
@@ -26,12 +26,12 @@
|
|||||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserSaveDirectoryToolTip}" />
|
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserSaveDirectoryToolTip}" />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{Binding OpenDeviceSaveDirectory}"
|
Command="{Binding OpenDeviceSaveDirectory}"
|
||||||
Header="{locale:Locale GameListContextMenuOpenUserDeviceDirectory}"
|
Header="{locale:Locale GameListContextMenuOpenDeviceSaveDirectory}"
|
||||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserDeviceDirectoryToolTip}" />
|
ToolTip.Tip="{locale:Locale GameListContextMenuOpenDeviceSaveDirectoryToolTip}" />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{Binding OpenBcatSaveDirectory}"
|
Command="{Binding OpenBcatSaveDirectory}"
|
||||||
Header="{locale:Locale GameListContextMenuOpenUserBcatDirectory}"
|
Header="{locale:Locale GameListContextMenuOpenBcatSaveDirectory}"
|
||||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserBcatDirectoryToolTip}" />
|
ToolTip.Tip="{locale:Locale GameListContextMenuOpenBcatSaveDirectoryToolTip}" />
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{Binding OpenTitleUpdateManager}"
|
Command="{Binding OpenTitleUpdateManager}"
|
||||||
@@ -139,6 +139,9 @@
|
|||||||
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
|
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
|
||||||
<Setter Property="Background" Value="{DynamicResource AppListHoverBackgroundColor}" />
|
<Setter Property="Background" Value="{DynamicResource AppListHoverBackgroundColor}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem:selected /template/ Border#SelectionIndicator">
|
||||||
|
<Setter Property="MinHeight" Value="{Binding $parent[UserControl].DataContext.GridItemSelectorSize}" />
|
||||||
|
</Style>
|
||||||
</ListBox.Styles>
|
</ListBox.Styles>
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
|
@@ -38,9 +38,9 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
{
|
{
|
||||||
if (sender is ListBox listBox)
|
if (sender is ListBox listBox)
|
||||||
{
|
{
|
||||||
var selected = listBox.SelectedItem as ApplicationData;
|
_selectedApplication = listBox.SelectedItem as ApplicationData;
|
||||||
|
|
||||||
_selectedApplication = selected;
|
(DataContext as MainWindowViewModel).GridSelectedApplication = _selectedApplication;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -25,12 +25,12 @@
|
|||||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserSaveDirectoryToolTip}" />
|
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserSaveDirectoryToolTip}" />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{Binding OpenDeviceSaveDirectory}"
|
Command="{Binding OpenDeviceSaveDirectory}"
|
||||||
Header="{locale:Locale GameListContextMenuOpenUserDeviceDirectory}"
|
Header="{locale:Locale GameListContextMenuOpenDeviceSaveDirectory}"
|
||||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserDeviceDirectoryToolTip}" />
|
ToolTip.Tip="{locale:Locale GameListContextMenuOpenDeviceSaveDirectoryToolTip}" />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{Binding OpenBcatSaveDirectory}"
|
Command="{Binding OpenBcatSaveDirectory}"
|
||||||
Header="{locale:Locale GameListContextMenuOpenUserBcatDirectory}"
|
Header="{locale:Locale GameListContextMenuOpenBcatSaveDirectory}"
|
||||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserBcatDirectoryToolTip}" />
|
ToolTip.Tip="{locale:Locale GameListContextMenuOpenBcatSaveDirectoryToolTip}" />
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{Binding OpenTitleUpdateManager}"
|
Command="{Binding OpenTitleUpdateManager}"
|
||||||
@@ -137,12 +137,12 @@
|
|||||||
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
|
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
|
||||||
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
|
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="ListBoxItem:selected /template/ Border#SelectionIndicator">
|
|
||||||
<Setter Property="MinHeight" Value="100" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
|
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
|
||||||
<Setter Property="Background" Value="{DynamicResource AppListHoverBackgroundColor}" />
|
<Setter Property="Background" Value="{DynamicResource AppListHoverBackgroundColor}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem:selected /template/ Border#SelectionIndicator">
|
||||||
|
<Setter Property="MinHeight" Value="{Binding $parent[UserControl].DataContext.ListItemSelectorSize}" />
|
||||||
|
</Style>
|
||||||
</ListBox.Styles>
|
</ListBox.Styles>
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
|
@@ -38,9 +38,9 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
{
|
{
|
||||||
if (sender is ListBox listBox)
|
if (sender is ListBox listBox)
|
||||||
{
|
{
|
||||||
var selected = listBox.SelectedItem as ApplicationData;
|
_selectedApplication = listBox.SelectedItem as ApplicationData;
|
||||||
|
|
||||||
_selectedApplication = selected;
|
(DataContext as MainWindowViewModel).ListSelectedApplication = _selectedApplication;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -19,7 +19,56 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
{
|
{
|
||||||
private static bool _isChoiceDialogOpen;
|
private static bool _isChoiceDialogOpen;
|
||||||
|
|
||||||
private async static Task<UserResult> ShowContentDialog(
|
public async static Task<UserResult> ShowContentDialog(
|
||||||
|
string title,
|
||||||
|
object content,
|
||||||
|
string primaryButton,
|
||||||
|
string secondaryButton,
|
||||||
|
string closeButton,
|
||||||
|
UserResult primaryButtonResult = UserResult.Ok,
|
||||||
|
ManualResetEvent deferResetEvent = null,
|
||||||
|
Func<Window, Task> doWhileDeferred = null,
|
||||||
|
TypedEventHandler<ContentDialog, ContentDialogButtonClickEventArgs> deferCloseAction = null)
|
||||||
|
{
|
||||||
|
UserResult result = UserResult.None;
|
||||||
|
|
||||||
|
ContentDialog contentDialog = new()
|
||||||
|
{
|
||||||
|
Title = title,
|
||||||
|
PrimaryButtonText = primaryButton,
|
||||||
|
SecondaryButtonText = secondaryButton,
|
||||||
|
CloseButtonText = closeButton,
|
||||||
|
Content = content
|
||||||
|
};
|
||||||
|
|
||||||
|
contentDialog.PrimaryButtonCommand = MiniCommand.Create(() =>
|
||||||
|
{
|
||||||
|
result = primaryButtonResult;
|
||||||
|
});
|
||||||
|
|
||||||
|
contentDialog.SecondaryButtonCommand = MiniCommand.Create(() =>
|
||||||
|
{
|
||||||
|
result = UserResult.No;
|
||||||
|
contentDialog.PrimaryButtonClick -= deferCloseAction;
|
||||||
|
});
|
||||||
|
|
||||||
|
contentDialog.CloseButtonCommand = MiniCommand.Create(() =>
|
||||||
|
{
|
||||||
|
result = UserResult.Cancel;
|
||||||
|
contentDialog.PrimaryButtonClick -= deferCloseAction;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (deferResetEvent != null)
|
||||||
|
{
|
||||||
|
contentDialog.PrimaryButtonClick += deferCloseAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
await ShowAsync(contentDialog);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async static Task<UserResult> ShowTextDialog(
|
||||||
string title,
|
string title,
|
||||||
string primaryText,
|
string primaryText,
|
||||||
string secondaryText,
|
string secondaryText,
|
||||||
@@ -32,119 +81,9 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
Func<Window, Task> doWhileDeferred = null,
|
Func<Window, Task> doWhileDeferred = null,
|
||||||
TypedEventHandler<ContentDialog, ContentDialogButtonClickEventArgs> deferCloseAction = null)
|
TypedEventHandler<ContentDialog, ContentDialogButtonClickEventArgs> deferCloseAction = null)
|
||||||
{
|
{
|
||||||
UserResult result = UserResult.None;
|
Grid content = CreateTextDialogContent(primaryText, secondaryText, iconSymbol);
|
||||||
|
|
||||||
bool useOverlay = false;
|
return await ShowContentDialog(title, content, primaryButton, secondaryButton, closeButton, primaryButtonResult, deferResetEvent, doWhileDeferred, deferCloseAction);
|
||||||
Window mainWindow = null;
|
|
||||||
|
|
||||||
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime al)
|
|
||||||
{
|
|
||||||
foreach (var item in al.Windows)
|
|
||||||
{
|
|
||||||
if (item.IsActive && item is MainWindow window && window.ViewModel.IsGameRunning)
|
|
||||||
{
|
|
||||||
mainWindow = window;
|
|
||||||
useOverlay = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ContentDialog contentDialog = null;
|
|
||||||
ContentDialogOverlayWindow overlay = null;
|
|
||||||
|
|
||||||
if (useOverlay)
|
|
||||||
{
|
|
||||||
overlay = new ContentDialogOverlayWindow()
|
|
||||||
{
|
|
||||||
Height = mainWindow.Bounds.Height,
|
|
||||||
Width = mainWindow.Bounds.Width,
|
|
||||||
Position = mainWindow.PointToScreen(new Point())
|
|
||||||
};
|
|
||||||
|
|
||||||
mainWindow.PositionChanged += OverlayOnPositionChanged;
|
|
||||||
|
|
||||||
void OverlayOnPositionChanged(object sender, PixelPointEventArgs e)
|
|
||||||
{
|
|
||||||
overlay.Position = mainWindow.PointToScreen(new Point());
|
|
||||||
}
|
|
||||||
|
|
||||||
contentDialog = overlay.ContentDialog;
|
|
||||||
|
|
||||||
bool opened = false;
|
|
||||||
|
|
||||||
overlay.Opened += OverlayOnActivated;
|
|
||||||
|
|
||||||
async void OverlayOnActivated(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if (opened)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
opened = true;
|
|
||||||
|
|
||||||
overlay.Position = mainWindow.PointToScreen(new Point());
|
|
||||||
|
|
||||||
await ShowDialog();
|
|
||||||
}
|
|
||||||
|
|
||||||
await overlay.ShowDialog(mainWindow);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
contentDialog = new ContentDialog();
|
|
||||||
|
|
||||||
await ShowDialog();
|
|
||||||
}
|
|
||||||
|
|
||||||
async Task ShowDialog()
|
|
||||||
{
|
|
||||||
contentDialog.Title = title;
|
|
||||||
contentDialog.PrimaryButtonText = primaryButton;
|
|
||||||
contentDialog.SecondaryButtonText = secondaryButton;
|
|
||||||
contentDialog.CloseButtonText = closeButton;
|
|
||||||
contentDialog.Content = CreateDialogTextContent(primaryText, secondaryText, iconSymbol);
|
|
||||||
|
|
||||||
contentDialog.PrimaryButtonCommand = MiniCommand.Create(() =>
|
|
||||||
{
|
|
||||||
result = primaryButtonResult;
|
|
||||||
});
|
|
||||||
contentDialog.SecondaryButtonCommand = MiniCommand.Create(() =>
|
|
||||||
{
|
|
||||||
result = UserResult.No;
|
|
||||||
contentDialog.PrimaryButtonClick -= deferCloseAction;
|
|
||||||
});
|
|
||||||
contentDialog.CloseButtonCommand = MiniCommand.Create(() =>
|
|
||||||
{
|
|
||||||
result = UserResult.Cancel;
|
|
||||||
contentDialog.PrimaryButtonClick -= deferCloseAction;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (deferResetEvent != null)
|
|
||||||
{
|
|
||||||
contentDialog.PrimaryButtonClick += deferCloseAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (useOverlay)
|
|
||||||
{
|
|
||||||
await contentDialog.ShowAsync(overlay, ContentDialogPlacement.Popup);
|
|
||||||
|
|
||||||
overlay!.Close();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await contentDialog.ShowAsync(ContentDialogPlacement.Popup);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (useOverlay)
|
|
||||||
{
|
|
||||||
overlay.Content = null;
|
|
||||||
overlay.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async static Task<UserResult> ShowDeferredContentDialog(
|
public async static Task<UserResult> ShowDeferredContentDialog(
|
||||||
@@ -162,7 +101,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
bool startedDeferring = false;
|
bool startedDeferring = false;
|
||||||
UserResult result = UserResult.None;
|
UserResult result = UserResult.None;
|
||||||
|
|
||||||
return await ShowContentDialog(
|
return await ShowTextDialog(
|
||||||
title,
|
title,
|
||||||
primaryText,
|
primaryText,
|
||||||
secondaryText,
|
secondaryText,
|
||||||
@@ -192,8 +131,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
|
|
||||||
sender.PrimaryButtonClick -= DeferClose;
|
sender.PrimaryButtonClick -= DeferClose;
|
||||||
|
|
||||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
_ = Task.Run(() =>
|
||||||
Task.Run(() =>
|
|
||||||
{
|
{
|
||||||
deferResetEvent.WaitOne();
|
deferResetEvent.WaitOne();
|
||||||
|
|
||||||
@@ -202,7 +140,6 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
deferral.Complete();
|
deferral.Complete();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
|
||||||
|
|
||||||
if (doWhileDeferred != null)
|
if (doWhileDeferred != null)
|
||||||
{
|
{
|
||||||
@@ -213,34 +150,42 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Grid CreateDialogTextContent(string primaryText, string secondaryText, int symbol)
|
private static Grid CreateTextDialogContent(string primaryText, string secondaryText, int symbol)
|
||||||
{
|
{
|
||||||
Grid content = new Grid();
|
Grid content = new()
|
||||||
content.RowDefinitions = new RowDefinitions() { new RowDefinition(), new RowDefinition() };
|
{
|
||||||
content.ColumnDefinitions = new ColumnDefinitions() { new ColumnDefinition(GridLength.Auto), new ColumnDefinition() };
|
RowDefinitions = new RowDefinitions() { new RowDefinition(), new RowDefinition() },
|
||||||
|
ColumnDefinitions = new ColumnDefinitions() { new ColumnDefinition(GridLength.Auto), new ColumnDefinition() },
|
||||||
|
|
||||||
content.MinHeight = 80;
|
MinHeight = 80
|
||||||
|
};
|
||||||
|
|
||||||
|
SymbolIcon icon = new()
|
||||||
|
{
|
||||||
|
Symbol = (Symbol)symbol,
|
||||||
|
Margin = new Thickness(10),
|
||||||
|
FontSize = 40,
|
||||||
|
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center
|
||||||
|
};
|
||||||
|
|
||||||
SymbolIcon icon = new SymbolIcon { Symbol = (Symbol)symbol, Margin = new Thickness(10) };
|
|
||||||
icon.FontSize = 40;
|
|
||||||
icon.VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center;
|
|
||||||
Grid.SetColumn(icon, 0);
|
Grid.SetColumn(icon, 0);
|
||||||
Grid.SetRowSpan(icon, 2);
|
Grid.SetRowSpan(icon, 2);
|
||||||
Grid.SetRow(icon, 0);
|
Grid.SetRow(icon, 0);
|
||||||
|
|
||||||
TextBlock primaryLabel = new TextBlock()
|
TextBlock primaryLabel = new()
|
||||||
{
|
{
|
||||||
Text = primaryText,
|
Text = primaryText,
|
||||||
Margin = new Thickness(5),
|
Margin = new Thickness(5),
|
||||||
TextWrapping = TextWrapping.Wrap,
|
TextWrapping = TextWrapping.Wrap,
|
||||||
MaxWidth = 450
|
MaxWidth = 450
|
||||||
};
|
};
|
||||||
TextBlock secondaryLabel = new TextBlock()
|
|
||||||
|
TextBlock secondaryLabel = new()
|
||||||
{
|
{
|
||||||
Text = secondaryText,
|
Text = secondaryText,
|
||||||
Margin = new Thickness(5),
|
Margin = new Thickness(5),
|
||||||
TextWrapping = TextWrapping.Wrap,
|
TextWrapping = TextWrapping.Wrap,
|
||||||
MaxWidth = 450
|
MaxWidth = 450
|
||||||
};
|
};
|
||||||
|
|
||||||
Grid.SetColumn(primaryLabel, 1);
|
Grid.SetColumn(primaryLabel, 1);
|
||||||
@@ -262,7 +207,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
string closeButton,
|
string closeButton,
|
||||||
string title)
|
string title)
|
||||||
{
|
{
|
||||||
return await ShowContentDialog(
|
return await ShowTextDialog(
|
||||||
title,
|
title,
|
||||||
primary,
|
primary,
|
||||||
secondaryText,
|
secondaryText,
|
||||||
@@ -280,7 +225,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
string title,
|
string title,
|
||||||
UserResult primaryButtonResult = UserResult.Yes)
|
UserResult primaryButtonResult = UserResult.Yes)
|
||||||
{
|
{
|
||||||
return await ShowContentDialog(
|
return await ShowTextDialog(
|
||||||
string.IsNullOrWhiteSpace(title) ? LocaleManager.Instance[LocaleKeys.DialogConfirmationTitle] : title,
|
string.IsNullOrWhiteSpace(title) ? LocaleManager.Instance[LocaleKeys.DialogConfirmationTitle] : title,
|
||||||
primaryText,
|
primaryText,
|
||||||
secondaryText,
|
secondaryText,
|
||||||
@@ -298,7 +243,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
|
|
||||||
internal static async Task CreateUpdaterInfoDialog(string primary, string secondaryText)
|
internal static async Task CreateUpdaterInfoDialog(string primary, string secondaryText)
|
||||||
{
|
{
|
||||||
await ShowContentDialog(
|
await ShowTextDialog(
|
||||||
LocaleManager.Instance[LocaleKeys.DialogUpdaterTitle],
|
LocaleManager.Instance[LocaleKeys.DialogUpdaterTitle],
|
||||||
primary,
|
primary,
|
||||||
secondaryText,
|
secondaryText,
|
||||||
@@ -310,7 +255,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
|
|
||||||
internal static async Task CreateWarningDialog(string primary, string secondaryText)
|
internal static async Task CreateWarningDialog(string primary, string secondaryText)
|
||||||
{
|
{
|
||||||
await ShowContentDialog(
|
await ShowTextDialog(
|
||||||
LocaleManager.Instance[LocaleKeys.DialogWarningTitle],
|
LocaleManager.Instance[LocaleKeys.DialogWarningTitle],
|
||||||
primary,
|
primary,
|
||||||
secondaryText,
|
secondaryText,
|
||||||
@@ -324,7 +269,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
{
|
{
|
||||||
Logger.Error?.Print(LogClass.Application, errorMessage);
|
Logger.Error?.Print(LogClass.Application, errorMessage);
|
||||||
|
|
||||||
await ShowContentDialog(
|
await ShowTextDialog(
|
||||||
LocaleManager.Instance[LocaleKeys.DialogErrorTitle],
|
LocaleManager.Instance[LocaleKeys.DialogErrorTitle],
|
||||||
LocaleManager.Instance[LocaleKeys.DialogErrorMessage],
|
LocaleManager.Instance[LocaleKeys.DialogErrorMessage],
|
||||||
errorMessage,
|
errorMessage,
|
||||||
@@ -343,16 +288,15 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
|
|
||||||
_isChoiceDialogOpen = true;
|
_isChoiceDialogOpen = true;
|
||||||
|
|
||||||
UserResult response =
|
UserResult response = await ShowTextDialog(
|
||||||
await ShowContentDialog(
|
title,
|
||||||
title,
|
primary,
|
||||||
primary,
|
secondaryText,
|
||||||
secondaryText,
|
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
"",
|
||||||
"",
|
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
(int)Symbol.Help,
|
||||||
(int)Symbol.Help,
|
UserResult.Yes);
|
||||||
UserResult.Yes);
|
|
||||||
|
|
||||||
_isChoiceDialogOpen = false;
|
_isChoiceDialogOpen = false;
|
||||||
|
|
||||||
@@ -396,5 +340,98 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
|
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<ContentDialogResult> ShowAsync(ContentDialog contentDialog)
|
||||||
|
{
|
||||||
|
ContentDialogResult result;
|
||||||
|
|
||||||
|
ContentDialogOverlayWindow contentDialogOverlayWindow = null;
|
||||||
|
|
||||||
|
Window parent = GetMainWindow();
|
||||||
|
|
||||||
|
if (parent != null && parent.IsActive && parent is MainWindow window && window.ViewModel.IsGameRunning)
|
||||||
|
{
|
||||||
|
contentDialogOverlayWindow = new()
|
||||||
|
{
|
||||||
|
Height = parent.Bounds.Height,
|
||||||
|
Width = parent.Bounds.Width,
|
||||||
|
Position = parent.PointToScreen(new Point()),
|
||||||
|
ShowInTaskbar = false
|
||||||
|
};
|
||||||
|
|
||||||
|
parent.PositionChanged += OverlayOnPositionChanged;
|
||||||
|
|
||||||
|
void OverlayOnPositionChanged(object sender, PixelPointEventArgs e)
|
||||||
|
{
|
||||||
|
contentDialogOverlayWindow.Position = parent.PointToScreen(new Point());
|
||||||
|
}
|
||||||
|
|
||||||
|
contentDialogOverlayWindow.ContentDialog = contentDialog;
|
||||||
|
|
||||||
|
bool opened = false;
|
||||||
|
|
||||||
|
contentDialogOverlayWindow.Opened += OverlayOnActivated;
|
||||||
|
|
||||||
|
async void OverlayOnActivated(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (opened)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
opened = true;
|
||||||
|
|
||||||
|
contentDialogOverlayWindow.Position = parent.PointToScreen(new Point());
|
||||||
|
|
||||||
|
result = await ShowDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
result = await contentDialogOverlayWindow.ShowDialog<ContentDialogResult>(parent);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = await ShowDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task<ContentDialogResult> ShowDialog()
|
||||||
|
{
|
||||||
|
if (contentDialogOverlayWindow is not null)
|
||||||
|
{
|
||||||
|
result = await contentDialog.ShowAsync(contentDialogOverlayWindow);
|
||||||
|
|
||||||
|
contentDialogOverlayWindow!.Close();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = await contentDialog.ShowAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contentDialogOverlayWindow is not null)
|
||||||
|
{
|
||||||
|
contentDialogOverlayWindow.Content = null;
|
||||||
|
contentDialogOverlayWindow.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Window GetMainWindow()
|
||||||
|
{
|
||||||
|
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime al)
|
||||||
|
{
|
||||||
|
foreach (Window item in al.Windows)
|
||||||
|
{
|
||||||
|
if (item.IsActive && item is MainWindow window)
|
||||||
|
{
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
136
Ryujinx.Ava/UI/ViewModels/AboutWindowViewModel.cs
Normal file
136
Ryujinx.Ava/UI/ViewModels/AboutWindowViewModel.cs
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Media.Imaging;
|
||||||
|
using Avalonia.Threading;
|
||||||
|
using Ryujinx.Ava.Common.Locale;
|
||||||
|
using Ryujinx.Common.Utilities;
|
||||||
|
using Ryujinx.Ui.Common.Configuration;
|
||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.NetworkInformation;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.ViewModels
|
||||||
|
{
|
||||||
|
public class AboutWindowViewModel : BaseModel
|
||||||
|
{
|
||||||
|
private Bitmap _githubLogo;
|
||||||
|
private Bitmap _discordLogo;
|
||||||
|
private Bitmap _patreonLogo;
|
||||||
|
private Bitmap _twitterLogo;
|
||||||
|
|
||||||
|
private string _version;
|
||||||
|
private string _supporters;
|
||||||
|
|
||||||
|
public Bitmap GithubLogo
|
||||||
|
{
|
||||||
|
get => _githubLogo;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_githubLogo = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bitmap DiscordLogo
|
||||||
|
{
|
||||||
|
get => _discordLogo;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_discordLogo = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bitmap PatreonLogo
|
||||||
|
{
|
||||||
|
get => _patreonLogo;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_patreonLogo = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bitmap TwitterLogo
|
||||||
|
{
|
||||||
|
get => _twitterLogo;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_twitterLogo = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Supporters
|
||||||
|
{
|
||||||
|
get => _supporters;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_supporters = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Version
|
||||||
|
{
|
||||||
|
get => _version;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_version = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Developers
|
||||||
|
{
|
||||||
|
get => string.Format(LocaleManager.Instance[LocaleKeys.AboutPageDeveloperListMore], "gdkchan, Ac_K, marysaka, rip in peri peri, LDj3SNuD, emmaus, Thealexbarney, GoffyDude, TSRBerry, IsaacMarovitz");
|
||||||
|
}
|
||||||
|
|
||||||
|
public AboutWindowViewModel()
|
||||||
|
{
|
||||||
|
Version = Program.Version;
|
||||||
|
|
||||||
|
var assets = AvaloniaLocator.Current.GetService<Avalonia.Platform.IAssetLoader>();
|
||||||
|
|
||||||
|
if (ConfigurationState.Instance.Ui.BaseStyle.Value == "Light")
|
||||||
|
{
|
||||||
|
GithubLogo = new Bitmap(assets.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_GitHub_Light.png?assembly=Ryujinx.Ui.Common")));
|
||||||
|
DiscordLogo = new Bitmap(assets.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Discord_Light.png?assembly=Ryujinx.Ui.Common")));
|
||||||
|
PatreonLogo = new Bitmap(assets.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Patreon_Light.png?assembly=Ryujinx.Ui.Common")));
|
||||||
|
TwitterLogo = new Bitmap(assets.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Twitter_Light.png?assembly=Ryujinx.Ui.Common")));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GithubLogo = new Bitmap(assets.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_GitHub_Dark.png?assembly=Ryujinx.Ui.Common")));
|
||||||
|
DiscordLogo = new Bitmap(assets.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Discord_Dark.png?assembly=Ryujinx.Ui.Common")));
|
||||||
|
PatreonLogo = new Bitmap(assets.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Patreon_Dark.png?assembly=Ryujinx.Ui.Common")));
|
||||||
|
TwitterLogo = new Bitmap(assets.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Twitter_Dark.png?assembly=Ryujinx.Ui.Common")));
|
||||||
|
}
|
||||||
|
|
||||||
|
Dispatcher.UIThread.InvokeAsync(DownloadPatronsJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DownloadPatronsJson()
|
||||||
|
{
|
||||||
|
if (!NetworkInterface.GetIsNetworkAvailable())
|
||||||
|
{
|
||||||
|
Supporters = LocaleManager.Instance[LocaleKeys.ConnectionError];
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpClient httpClient = new();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string patreonJsonString = await httpClient.GetStringAsync("https://patreon.ryujinx.org/");
|
||||||
|
|
||||||
|
Supporters = string.Join(", ", JsonHelper.Deserialize<string[]>(patreonJsonString)) + "\n\n";
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Supporters = LocaleManager.Instance[LocaleKeys.ApiError];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -244,9 +244,9 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
_mainWindow.InputManager.GamepadDriver.OnGamepadConnected += HandleOnGamepadConnected;
|
_mainWindow.InputManager.GamepadDriver.OnGamepadConnected += HandleOnGamepadConnected;
|
||||||
_mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected += HandleOnGamepadDisconnected;
|
_mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected += HandleOnGamepadDisconnected;
|
||||||
if (_mainWindow.AppHost != null)
|
if (_mainWindow.ViewModel.AppHost != null)
|
||||||
{
|
{
|
||||||
_mainWindow.AppHost.NpadManager.BlockInputUpdates();
|
_mainWindow.ViewModel.AppHost.NpadManager.BlockInputUpdates();
|
||||||
}
|
}
|
||||||
|
|
||||||
_isLoaded = false;
|
_isLoaded = false;
|
||||||
@@ -862,7 +862,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_mainWindow.AppHost?.NpadManager.ReloadConfiguration(newConfig, ConfigurationState.Instance.Hid.EnableKeyboard, ConfigurationState.Instance.Hid.EnableMouse);
|
_mainWindow.ViewModel.AppHost?.NpadManager.ReloadConfiguration(newConfig, ConfigurationState.Instance.Hid.EnableKeyboard, ConfigurationState.Instance.Hid.EnableMouse);
|
||||||
|
|
||||||
// Atomically replace and signal input change.
|
// Atomically replace and signal input change.
|
||||||
// NOTE: Do not modify InputConfig.Value directly as other code depends on the on-change event.
|
// NOTE: Do not modify InputConfig.Value directly as other code depends on the on-change event.
|
||||||
@@ -891,7 +891,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
_mainWindow.InputManager.GamepadDriver.OnGamepadConnected -= HandleOnGamepadConnected;
|
_mainWindow.InputManager.GamepadDriver.OnGamepadConnected -= HandleOnGamepadConnected;
|
||||||
_mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected -= HandleOnGamepadDisconnected;
|
_mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected -= HandleOnGamepadDisconnected;
|
||||||
|
|
||||||
_mainWindow.AppHost?.NpadManager.UnblockInputUpdates();
|
_mainWindow.ViewModel.AppHost?.NpadManager.UnblockInputUpdates();
|
||||||
|
|
||||||
SelectedGamepad?.Dispose();
|
SelectedGamepad?.Dispose();
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,3 @@
|
|||||||
using Avalonia;
|
|
||||||
using Avalonia.Collections;
|
using Avalonia.Collections;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
@@ -8,8 +7,6 @@ using Ryujinx.Audio.Backends.OpenAL;
|
|||||||
using Ryujinx.Audio.Backends.SDL2;
|
using Ryujinx.Audio.Backends.SDL2;
|
||||||
using Ryujinx.Audio.Backends.SoundIo;
|
using Ryujinx.Audio.Backends.SoundIo;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.Input;
|
|
||||||
using Ryujinx.Ava.UI.Controls;
|
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
using Ryujinx.Ava.UI.Windows;
|
using Ryujinx.Ava.UI.Windows;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
@@ -19,7 +16,6 @@ using Ryujinx.Common.Logging;
|
|||||||
using Ryujinx.Graphics.Vulkan;
|
using Ryujinx.Graphics.Vulkan;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
||||||
using Ryujinx.Input;
|
|
||||||
using Ryujinx.Ui.Common.Configuration;
|
using Ryujinx.Ui.Common.Configuration;
|
||||||
using Ryujinx.Ui.Common.Configuration.System;
|
using Ryujinx.Ui.Common.Configuration.System;
|
||||||
using System;
|
using System;
|
||||||
@@ -30,11 +26,10 @@ using TimeZone = Ryujinx.Ava.UI.Models.TimeZone;
|
|||||||
|
|
||||||
namespace Ryujinx.Ava.UI.ViewModels
|
namespace Ryujinx.Ava.UI.ViewModels
|
||||||
{
|
{
|
||||||
internal class SettingsViewModel : BaseModel
|
public class SettingsViewModel : BaseModel
|
||||||
{
|
{
|
||||||
private readonly VirtualFileSystem _virtualFileSystem;
|
private readonly VirtualFileSystem _virtualFileSystem;
|
||||||
private readonly ContentManager _contentManager;
|
private readonly ContentManager _contentManager;
|
||||||
private readonly StyleableWindow _owner;
|
|
||||||
private TimeZoneContentManager _timeZoneContentManager;
|
private TimeZoneContentManager _timeZoneContentManager;
|
||||||
|
|
||||||
private readonly List<string> _validTzRegions;
|
private readonly List<string> _validTzRegions;
|
||||||
@@ -44,10 +39,14 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
private int _graphicsBackendMultithreadingIndex;
|
private int _graphicsBackendMultithreadingIndex;
|
||||||
private float _volume;
|
private float _volume;
|
||||||
private bool _isVulkanAvailable = true;
|
private bool _isVulkanAvailable = true;
|
||||||
private bool _directoryChanged = false;
|
private bool _directoryChanged;
|
||||||
private List<string> _gpuIds = new List<string>();
|
private List<string> _gpuIds = new();
|
||||||
private KeyboardHotkeys _keyboardHotkeys;
|
private KeyboardHotkeys _keyboardHotkeys;
|
||||||
private int _graphicsBackendIndex;
|
private int _graphicsBackendIndex;
|
||||||
|
private string _customThemePath;
|
||||||
|
|
||||||
|
public event Action CloseWindow;
|
||||||
|
public event Action SaveSettingsEvent;
|
||||||
|
|
||||||
public int ResolutionScale
|
public int ResolutionScale
|
||||||
{
|
{
|
||||||
@@ -67,19 +66,16 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
{
|
{
|
||||||
_graphicsBackendMultithreadingIndex = value;
|
_graphicsBackendMultithreadingIndex = value;
|
||||||
|
|
||||||
if (_owner != null)
|
if (_graphicsBackendMultithreadingIndex != (int)ConfigurationState.Instance.Graphics.BackendThreading.Value)
|
||||||
{
|
{
|
||||||
if (_graphicsBackendMultithreadingIndex != (int)ConfigurationState.Instance.Graphics.BackendThreading.Value)
|
Dispatcher.UIThread.Post(async () =>
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(async () =>
|
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningMessage],
|
||||||
{
|
"",
|
||||||
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningMessage],
|
"",
|
||||||
"",
|
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
||||||
"",
|
LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningTitle]);
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
});
|
||||||
LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningTitle]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
@@ -160,7 +156,20 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
public string TimeZone { get; set; }
|
public string TimeZone { get; set; }
|
||||||
public string ShaderDumpPath { get; set; }
|
public string ShaderDumpPath { get; set; }
|
||||||
public string CustomThemePath { get; set; }
|
|
||||||
|
public string CustomThemePath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _customThemePath;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_customThemePath = value;
|
||||||
|
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int Language { get; set; }
|
public int Language { get; set; }
|
||||||
public int Region { get; set; }
|
public int Region { get; set; }
|
||||||
@@ -191,7 +200,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
{
|
{
|
||||||
_volume = value;
|
_volume = value;
|
||||||
|
|
||||||
ConfigurationState.Instance.System.AudioVolume.Value = (float)(_volume / 100);
|
ConfigurationState.Instance.System.AudioVolume.Value = _volume / 100;
|
||||||
|
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
}
|
}
|
||||||
@@ -199,7 +208,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
public DateTimeOffset DateOffset { get; set; }
|
public DateTimeOffset DateOffset { get; set; }
|
||||||
public TimeSpan TimeOffset { get; set; }
|
public TimeSpan TimeOffset { get; set; }
|
||||||
public AvaloniaList<TimeZone> TimeZones { get; set; }
|
private AvaloniaList<TimeZone> TimeZones { get; set; }
|
||||||
public AvaloniaList<string> GameDirectories { get; set; }
|
public AvaloniaList<string> GameDirectories { get; set; }
|
||||||
public ObservableCollection<ComboBoxItem> AvailableGpus { get; set; }
|
public ObservableCollection<ComboBoxItem> AvailableGpus { get; set; }
|
||||||
|
|
||||||
@@ -214,17 +223,13 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IGamepadDriver AvaloniaKeyboardDriver { get; }
|
public SettingsViewModel(VirtualFileSystem virtualFileSystem, ContentManager contentManager) : this()
|
||||||
|
|
||||||
public SettingsViewModel(VirtualFileSystem virtualFileSystem, ContentManager contentManager, StyleableWindow owner) : this()
|
|
||||||
{
|
{
|
||||||
_virtualFileSystem = virtualFileSystem;
|
_virtualFileSystem = virtualFileSystem;
|
||||||
_contentManager = contentManager;
|
_contentManager = contentManager;
|
||||||
_owner = owner;
|
|
||||||
if (Program.PreviewerDetached)
|
if (Program.PreviewerDetached)
|
||||||
{
|
{
|
||||||
LoadTimeZones();
|
LoadTimeZones();
|
||||||
AvaloniaKeyboardDriver = new AvaloniaKeyboardDriver(owner);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,10 +256,10 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
IsSDL2Enabled = SDL2HardwareDeviceDriver.IsSupported;
|
IsSDL2Enabled = SDL2HardwareDeviceDriver.IsSupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe void LoadAvailableGpus()
|
private void LoadAvailableGpus()
|
||||||
{
|
{
|
||||||
_gpuIds = new List<string>();
|
_gpuIds = new List<string>();
|
||||||
List<string> names = new List<string>();
|
List<string> names = new();
|
||||||
var devices = VulkanRenderer.GetPhysicalDevices();
|
var devices = VulkanRenderer.GetPhysicalDevices();
|
||||||
|
|
||||||
if (devices.Length == 0)
|
if (devices.Length == 0)
|
||||||
@@ -272,7 +277,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
|
|
||||||
AvailableGpus.Clear();
|
AvailableGpus.Clear();
|
||||||
AvailableGpus.AddRange(names.Select(x => new ComboBoxItem() { Content = x }));
|
AvailableGpus.AddRange(names.Select(x => new ComboBoxItem { Content = x }));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadTimeZones()
|
public void LoadTimeZones()
|
||||||
@@ -302,25 +307,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void BrowseTheme()
|
|
||||||
{
|
|
||||||
var dialog = new OpenFileDialog()
|
|
||||||
{
|
|
||||||
Title = LocaleManager.Instance[LocaleKeys.SettingsSelectThemeFileDialogTitle],
|
|
||||||
AllowMultiple = false
|
|
||||||
};
|
|
||||||
|
|
||||||
dialog.Filters.Add(new FileDialogFilter() { Extensions = { "xaml" }, Name = LocaleManager.Instance[LocaleKeys.SettingsXamlThemeFile] });
|
|
||||||
|
|
||||||
var file = await dialog.ShowAsync(_owner);
|
|
||||||
|
|
||||||
if (file != null && file.Length > 0)
|
|
||||||
{
|
|
||||||
CustomThemePath = file[0];
|
|
||||||
OnPropertyChanged(nameof(CustomThemePath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LoadCurrentConfiguration()
|
public void LoadCurrentConfiguration()
|
||||||
{
|
{
|
||||||
ConfigurationState config = ConfigurationState.Instance;
|
ConfigurationState config = ConfigurationState.Instance;
|
||||||
@@ -478,15 +464,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
MainWindow.UpdateGraphicsConfig();
|
MainWindow.UpdateGraphicsConfig();
|
||||||
|
|
||||||
if (_owner is SettingsWindow owner)
|
SaveSettingsEvent?.Invoke();
|
||||||
{
|
|
||||||
owner.ControllerSettings?.SaveCurrentProfile();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_owner.Owner is MainWindow window && _directoryChanged)
|
|
||||||
{
|
|
||||||
window.ViewModel.LoadApplications();
|
|
||||||
}
|
|
||||||
|
|
||||||
_directoryChanged = false;
|
_directoryChanged = false;
|
||||||
}
|
}
|
||||||
@@ -504,13 +482,13 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
public void OkButton()
|
public void OkButton()
|
||||||
{
|
{
|
||||||
SaveSettings();
|
SaveSettings();
|
||||||
_owner.Close();
|
CloseWindow?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CancelButton()
|
public void CancelButton()
|
||||||
{
|
{
|
||||||
RevertIfNotSaved();
|
RevertIfNotSaved();
|
||||||
_owner.Close();
|
CloseWindow?.Invoke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
216
Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml
Normal file
216
Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
<UserControl
|
||||||
|
xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
|
x:DataType="viewModels:MainWindowViewModel"
|
||||||
|
x:Class="Ryujinx.Ava.UI.Views.Main.MainMenuBarView"
|
||||||
|
x:CompileBindings="True">
|
||||||
|
<Design.DataContext>
|
||||||
|
<viewModels:MainWindowViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
<DockPanel HorizontalAlignment="Stretch">
|
||||||
|
<Menu
|
||||||
|
Name="Menu"
|
||||||
|
Height="35"
|
||||||
|
Margin="0"
|
||||||
|
HorizontalAlignment="Left">
|
||||||
|
<Menu.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<DockPanel Margin="0" HorizontalAlignment="Stretch" />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</Menu.ItemsPanel>
|
||||||
|
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarFile}">
|
||||||
|
<MenuItem
|
||||||
|
Command="{ReflectionBinding OpenFile}"
|
||||||
|
Header="{locale:Locale MenuBarFileOpenFromFile}"
|
||||||
|
IsEnabled="{Binding EnableNonGameRunningControls}"
|
||||||
|
ToolTip.Tip="{locale:Locale LoadApplicationFileTooltip}" />
|
||||||
|
<MenuItem
|
||||||
|
Command="{ReflectionBinding OpenFolder}"
|
||||||
|
Header="{locale:Locale MenuBarFileOpenUnpacked}"
|
||||||
|
IsEnabled="{Binding EnableNonGameRunningControls}"
|
||||||
|
ToolTip.Tip="{locale:Locale LoadApplicationFolderTooltip}" />
|
||||||
|
<MenuItem Header="{locale:Locale MenuBarFileOpenApplet}" IsEnabled="{Binding IsAppletMenuActive}">
|
||||||
|
<MenuItem
|
||||||
|
Click="OpenMiiApplet"
|
||||||
|
Header="Mii Edit Applet"
|
||||||
|
ToolTip.Tip="{locale:Locale MenuBarFileOpenAppletOpenMiiAppletToolTip}" />
|
||||||
|
</MenuItem>
|
||||||
|
<Separator />
|
||||||
|
<MenuItem
|
||||||
|
Command="{ReflectionBinding OpenRyujinxFolder}"
|
||||||
|
Header="{locale:Locale MenuBarFileOpenEmuFolder}"
|
||||||
|
ToolTip.Tip="{locale:Locale OpenRyujinxFolderTooltip}" />
|
||||||
|
<MenuItem
|
||||||
|
Command="{ReflectionBinding OpenLogsFolder}"
|
||||||
|
Header="{locale:Locale MenuBarFileOpenLogsFolder}"
|
||||||
|
ToolTip.Tip="{locale:Locale OpenRyujinxLogsTooltip}" />
|
||||||
|
<Separator />
|
||||||
|
<MenuItem
|
||||||
|
Click="CloseWindow"
|
||||||
|
Header="{locale:Locale MenuBarFileExit}"
|
||||||
|
ToolTip.Tip="{locale:Locale ExitTooltip}" />
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarOptions}">
|
||||||
|
<MenuItem
|
||||||
|
Command="{ReflectionBinding ToggleFullscreen}"
|
||||||
|
Header="{locale:Locale MenuBarOptionsToggleFullscreen}"
|
||||||
|
InputGesture="F11" />
|
||||||
|
<MenuItem>
|
||||||
|
<MenuItem.Icon>
|
||||||
|
<CheckBox IsChecked="{Binding StartGamesInFullscreen, Mode=TwoWay}"
|
||||||
|
MinWidth="250">
|
||||||
|
<TextBlock Text="{locale:Locale MenuBarOptionsStartGamesInFullscreen}"/>
|
||||||
|
</CheckBox>
|
||||||
|
</MenuItem.Icon>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem IsVisible="{Binding ShowConsoleVisible}">
|
||||||
|
<MenuItem.Icon>
|
||||||
|
<CheckBox IsChecked="{Binding ShowConsole, Mode=TwoWay}"
|
||||||
|
MinWidth="250">
|
||||||
|
<TextBlock Text="{locale:Locale MenuBarOptionsShowConsole}"/>
|
||||||
|
</CheckBox>
|
||||||
|
</MenuItem.Icon>
|
||||||
|
</MenuItem>
|
||||||
|
<Separator />
|
||||||
|
<MenuItem Header="{locale:Locale MenuBarOptionsChangeLanguage}">
|
||||||
|
<MenuItem
|
||||||
|
Command="{ReflectionBinding ChangeLanguage}"
|
||||||
|
CommandParameter="de_DE"
|
||||||
|
Header="Deutsch" />
|
||||||
|
<MenuItem
|
||||||
|
Command="{ReflectionBinding ChangeLanguage}"
|
||||||
|
CommandParameter="en_US"
|
||||||
|
Header="English (US)" />
|
||||||
|
<MenuItem
|
||||||
|
Command="{ReflectionBinding ChangeLanguage}"
|
||||||
|
CommandParameter="es_ES"
|
||||||
|
Header="Español (ES)" />
|
||||||
|
<MenuItem
|
||||||
|
Command="{ReflectionBinding ChangeLanguage}"
|
||||||
|
CommandParameter="fr_FR"
|
||||||
|
Header="Français" />
|
||||||
|
<MenuItem
|
||||||
|
Command="{ReflectionBinding ChangeLanguage}"
|
||||||
|
CommandParameter="it_IT"
|
||||||
|
Header="Italiano" />
|
||||||
|
<MenuItem
|
||||||
|
Command="{ReflectionBinding ChangeLanguage}"
|
||||||
|
CommandParameter="pt_BR"
|
||||||
|
Header="Português (BR)" />
|
||||||
|
<MenuItem
|
||||||
|
Command="{ReflectionBinding ChangeLanguage}"
|
||||||
|
CommandParameter="tr_TR"
|
||||||
|
Header="Türkçe" />
|
||||||
|
<MenuItem
|
||||||
|
Command="{ReflectionBinding ChangeLanguage}"
|
||||||
|
CommandParameter="el_GR"
|
||||||
|
Header="Ελληνικά" />
|
||||||
|
<MenuItem
|
||||||
|
Command="{ReflectionBinding ChangeLanguage}"
|
||||||
|
CommandParameter="pl_PL"
|
||||||
|
Header="Polski" />
|
||||||
|
<MenuItem
|
||||||
|
Command="{ReflectionBinding ChangeLanguage}"
|
||||||
|
CommandParameter="ru_RU"
|
||||||
|
Header="Русский" />
|
||||||
|
<MenuItem
|
||||||
|
Command="{ReflectionBinding ChangeLanguage}"
|
||||||
|
CommandParameter="zh_CN"
|
||||||
|
Header="简体中文" />
|
||||||
|
<MenuItem
|
||||||
|
Command="{ReflectionBinding ChangeLanguage}"
|
||||||
|
CommandParameter="zh_TW"
|
||||||
|
Header="繁體中文" />
|
||||||
|
<MenuItem
|
||||||
|
Command="{ReflectionBinding ChangeLanguage}"
|
||||||
|
CommandParameter="ja_JP"
|
||||||
|
Header="日本語" />
|
||||||
|
<MenuItem
|
||||||
|
Command="{ReflectionBinding ChangeLanguage}"
|
||||||
|
CommandParameter="ko_KR"
|
||||||
|
Header="한국어" />
|
||||||
|
</MenuItem>
|
||||||
|
<Separator />
|
||||||
|
<MenuItem
|
||||||
|
Click="OpenSettings"
|
||||||
|
Header="{locale:Locale MenuBarOptionsSettings}"
|
||||||
|
ToolTip.Tip="{locale:Locale OpenSettingsTooltip}" />
|
||||||
|
<MenuItem
|
||||||
|
Command="{ReflectionBinding ManageProfiles}"
|
||||||
|
Header="{locale:Locale MenuBarOptionsManageUserProfiles}"
|
||||||
|
IsEnabled="{Binding EnableNonGameRunningControls}"
|
||||||
|
ToolTip.Tip="{locale:Locale OpenProfileManagerTooltip}" />
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem
|
||||||
|
Name="ActionsMenuItem"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Header="{locale:Locale MenuBarActions}"
|
||||||
|
IsEnabled="{Binding IsGameRunning}">
|
||||||
|
<MenuItem
|
||||||
|
Click="PauseEmulation_Click"
|
||||||
|
Header="{locale:Locale MenuBarOptionsPauseEmulation}"
|
||||||
|
InputGesture="{Binding PauseKey}"
|
||||||
|
IsEnabled="{Binding !IsPaused}"
|
||||||
|
IsVisible="{Binding !IsPaused}" />
|
||||||
|
<MenuItem
|
||||||
|
Click="ResumeEmulation_Click"
|
||||||
|
Header="{locale:Locale MenuBarOptionsResumeEmulation}"
|
||||||
|
InputGesture="{Binding PauseKey}"
|
||||||
|
IsEnabled="{Binding IsPaused}"
|
||||||
|
IsVisible="{Binding IsPaused}" />
|
||||||
|
<MenuItem
|
||||||
|
Click="StopEmulation_Click"
|
||||||
|
Header="{locale:Locale MenuBarOptionsStopEmulation}"
|
||||||
|
InputGesture="Escape"
|
||||||
|
IsEnabled="{Binding IsGameRunning}"
|
||||||
|
ToolTip.Tip="{locale:Locale StopEmulationTooltip}" />
|
||||||
|
<MenuItem Command="{ReflectionBinding SimulateWakeUpMessage}" Header="{locale:Locale MenuBarOptionsSimulateWakeUpMessage}" />
|
||||||
|
<Separator />
|
||||||
|
<MenuItem
|
||||||
|
Name="ScanAmiiboMenuItem"
|
||||||
|
AttachedToVisualTree="ScanAmiiboMenuItem_AttachedToVisualTree"
|
||||||
|
Click="OpenAmiiboWindow"
|
||||||
|
Header="{locale:Locale MenuBarActionsScanAmiibo}"
|
||||||
|
IsEnabled="{Binding IsAmiiboRequested}" />
|
||||||
|
<MenuItem
|
||||||
|
Command="{ReflectionBinding TakeScreenshot}"
|
||||||
|
Header="{locale:Locale MenuBarFileToolsTakeScreenshot}"
|
||||||
|
InputGesture="{Binding ScreenshotKey}"
|
||||||
|
IsEnabled="{Binding IsGameRunning}" />
|
||||||
|
<MenuItem
|
||||||
|
Command="{ReflectionBinding HideUi}"
|
||||||
|
Header="{locale:Locale MenuBarFileToolsHideUi}"
|
||||||
|
InputGesture="{Binding ShowUiKey}"
|
||||||
|
IsEnabled="{Binding IsGameRunning}" />
|
||||||
|
<MenuItem
|
||||||
|
Click="OpenCheatManagerForCurrentApp"
|
||||||
|
Header="{locale:Locale GameListContextMenuManageCheat}"
|
||||||
|
IsEnabled="{Binding IsGameRunning}" />
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarTools}">
|
||||||
|
<MenuItem Header="{locale:Locale MenuBarToolsInstallFirmware}" IsEnabled="{Binding EnableNonGameRunningControls}">
|
||||||
|
<MenuItem Command="{ReflectionBinding InstallFirmwareFromFile}" Header="{locale:Locale MenuBarFileToolsInstallFirmwareFromFile}" />
|
||||||
|
<MenuItem Command="{ReflectionBinding InstallFirmwareFromFolder}" Header="{locale:Locale MenuBarFileToolsInstallFirmwareFromDirectory}" />
|
||||||
|
</MenuItem>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarHelp}">
|
||||||
|
<MenuItem
|
||||||
|
Name="UpdateMenuItem"
|
||||||
|
IsEnabled="{Binding CanUpdate}"
|
||||||
|
Click="CheckForUpdates"
|
||||||
|
Header="{locale:Locale MenuBarHelpCheckForUpdates}"
|
||||||
|
ToolTip.Tip="{locale:Locale CheckUpdatesTooltip}" />
|
||||||
|
<Separator />
|
||||||
|
<MenuItem
|
||||||
|
Click="OpenAboutWindow"
|
||||||
|
Header="{locale:Locale MenuBarHelpAbout}"
|
||||||
|
ToolTip.Tip="{locale:Locale OpenAboutTooltip}" />
|
||||||
|
</MenuItem>
|
||||||
|
</Menu>
|
||||||
|
</DockPanel>
|
||||||
|
</UserControl>
|
143
Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs
Normal file
143
Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
|
using Ryujinx.Ava.UI.Windows;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LibHac.FsSystem;
|
||||||
|
using LibHac.Ncm;
|
||||||
|
using Ryujinx.HLE.HOS;
|
||||||
|
using Ryujinx.Modules;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Views.Main
|
||||||
|
{
|
||||||
|
public partial class MainMenuBarView : UserControl
|
||||||
|
{
|
||||||
|
public MainWindow Window { get; private set; }
|
||||||
|
public MainWindowViewModel ViewModel { get; private set; }
|
||||||
|
|
||||||
|
public MainMenuBarView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnAttachedToVisualTree(e);
|
||||||
|
|
||||||
|
if (this.VisualRoot is MainWindow window)
|
||||||
|
{
|
||||||
|
Window = window;
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewModel = Window.ViewModel;
|
||||||
|
DataContext = ViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void StopEmulation_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
await Window.ViewModel.AppHost?.ShowExitPrompt();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void PauseEmulation_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
await Task.Run(() =>
|
||||||
|
{
|
||||||
|
Window.ViewModel.AppHost?.Pause();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void ResumeEmulation_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
await Task.Run(() =>
|
||||||
|
{
|
||||||
|
Window.ViewModel.AppHost?.Resume();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void OpenSettings(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Window.SettingsWindow = new(Window.VirtualFileSystem, Window.ContentManager);
|
||||||
|
|
||||||
|
await Window.SettingsWindow.ShowDialog(Window);
|
||||||
|
|
||||||
|
ViewModel.LoadConfigurableHotKeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OpenMiiApplet(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
string contentPath = ViewModel.ContentManager.GetInstalledContentPath(0x0100000000001009, StorageId.BuiltInSystem, NcaContentType.Program);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(contentPath))
|
||||||
|
{
|
||||||
|
ViewModel.LoadApplication(contentPath, false, "Mii Applet");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void OpenAmiiboWindow(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (!ViewModel.IsAmiiboRequested)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ViewModel.AppHost.Device.System.SearchingForAmiibo(out int deviceId))
|
||||||
|
{
|
||||||
|
string titleId = ViewModel.AppHost.Device.Application.TitleIdText.ToUpper();
|
||||||
|
AmiiboWindow window = new(ViewModel.ShowAll, ViewModel.LastScannedAmiiboId, titleId);
|
||||||
|
|
||||||
|
await window.ShowDialog(Window);
|
||||||
|
|
||||||
|
if (window.IsScanned)
|
||||||
|
{
|
||||||
|
ViewModel.ShowAll = window.ViewModel.ShowAllAmiibo;
|
||||||
|
ViewModel.LastScannedAmiiboId = window.ScannedAmiibo.GetId();
|
||||||
|
|
||||||
|
ViewModel.AppHost.Device.System.ScanAmiibo(deviceId, ViewModel.LastScannedAmiiboId, window.ViewModel.UseRandomUuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void OpenCheatManagerForCurrentApp(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (!ViewModel.IsGameRunning)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplicationLoader application = ViewModel.AppHost.Device.Application;
|
||||||
|
if (application != null)
|
||||||
|
{
|
||||||
|
await new CheatWindow(Window.VirtualFileSystem, application.TitleIdText, application.TitleName).ShowDialog(Window);
|
||||||
|
|
||||||
|
ViewModel.AppHost.Device.EnableCheats();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ScanAmiiboMenuItem_AttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is MenuItem)
|
||||||
|
{
|
||||||
|
ViewModel.IsAmiiboRequested = Window.ViewModel.AppHost.Device.System.SearchingForAmiibo(out _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void CheckForUpdates(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (Updater.CanUpdate(true, Window))
|
||||||
|
{
|
||||||
|
await Updater.BeginParse(Window, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void OpenAboutWindow(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
await AboutWindow.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CloseWindow(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Window.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
232
Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml
Normal file
232
Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
<UserControl
|
||||||
|
xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Ryujinx.Ava.UI.Views.Main.MainStatusBarView"
|
||||||
|
x:CompileBindings="True"
|
||||||
|
x:DataType="viewModels:MainWindowViewModel">
|
||||||
|
<Design.DataContext>
|
||||||
|
<viewModels:MainWindowViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
<Grid
|
||||||
|
Name="StatusBar"
|
||||||
|
Margin="0"
|
||||||
|
MinHeight="22"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Bottom"
|
||||||
|
Background="{DynamicResource ThemeContentBackgroundColor}"
|
||||||
|
DockPanel.Dock="Bottom"
|
||||||
|
IsVisible="{Binding ShowMenuAndStatusBar}">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<StackPanel
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="5"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
IsVisible="{Binding EnableNonGameRunningControls}">
|
||||||
|
<Grid Margin="0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Button
|
||||||
|
Width="25"
|
||||||
|
Height="25"
|
||||||
|
MinWidth="0"
|
||||||
|
Margin="0,0,5,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Background="Transparent"
|
||||||
|
Command="{ReflectionBinding LoadApplications}">
|
||||||
|
<ui:SymbolIcon
|
||||||
|
Width="50"
|
||||||
|
Height="100"
|
||||||
|
Symbol="Refresh" />
|
||||||
|
</Button>
|
||||||
|
<TextBlock
|
||||||
|
Name="LoadStatus"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="0,0,5,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
IsVisible="{Binding EnableNonGameRunningControls}"
|
||||||
|
Text="{locale:Locale StatusBarGamesLoaded}" />
|
||||||
|
<ProgressBar
|
||||||
|
Name="LoadProgressBar"
|
||||||
|
Grid.Column="2"
|
||||||
|
Height="6"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Foreground="{DynamicResource HighlightColor}"
|
||||||
|
IsVisible="{Binding StatusBarVisible}"
|
||||||
|
Maximum="{Binding StatusBarProgressMaximum}"
|
||||||
|
Value="{Binding StatusBarProgressValue}" />
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="0,2"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
IsVisible="{Binding IsGameRunning}"
|
||||||
|
MaxHeight="18"
|
||||||
|
Orientation="Horizontal">
|
||||||
|
<TextBlock
|
||||||
|
Name="VsyncStatus"
|
||||||
|
Margin="5,0,5,0"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Foreground="{Binding VsyncColor}"
|
||||||
|
IsVisible="{Binding !ShowLoadProgress}"
|
||||||
|
PointerReleased="VsyncStatus_PointerReleased"
|
||||||
|
Text="VSync"
|
||||||
|
TextAlignment="Left" />
|
||||||
|
<Border
|
||||||
|
Width="2"
|
||||||
|
Height="12"
|
||||||
|
Margin="0"
|
||||||
|
BorderBrush="Gray"
|
||||||
|
BorderThickness="1"
|
||||||
|
IsVisible="{Binding !ShowLoadProgress}" />
|
||||||
|
<TextBlock
|
||||||
|
Name="DockedStatus"
|
||||||
|
Margin="5,0,5,0"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
IsVisible="{Binding !ShowLoadProgress}"
|
||||||
|
PointerReleased="DockedStatus_PointerReleased"
|
||||||
|
Text="{Binding DockedStatusText}"
|
||||||
|
TextAlignment="Left" />
|
||||||
|
<Border
|
||||||
|
Width="2"
|
||||||
|
Height="12"
|
||||||
|
Margin="0"
|
||||||
|
BorderBrush="Gray"
|
||||||
|
BorderThickness="1"
|
||||||
|
IsVisible="{Binding !ShowLoadProgress}" />
|
||||||
|
<TextBlock
|
||||||
|
Name="AspectRatioStatus"
|
||||||
|
Margin="5,0,5,0"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
IsVisible="{Binding !ShowLoadProgress}"
|
||||||
|
PointerReleased="AspectRatioStatus_PointerReleased"
|
||||||
|
Text="{Binding AspectRatioStatusText}"
|
||||||
|
TextAlignment="Left" />
|
||||||
|
<Border
|
||||||
|
Width="2"
|
||||||
|
Height="12"
|
||||||
|
Margin="0"
|
||||||
|
BorderBrush="Gray"
|
||||||
|
BorderThickness="1"
|
||||||
|
IsVisible="{Binding !ShowLoadProgress}" />
|
||||||
|
<ui:ToggleSplitButton
|
||||||
|
Name="VolumeStatus"
|
||||||
|
Padding="5,0,5,0"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
VerticalContentAlignment="Center"
|
||||||
|
Background="{DynamicResource ThemeContentBackgroundColor}"
|
||||||
|
BorderThickness="0"
|
||||||
|
Content="{Binding VolumeStatusText}"
|
||||||
|
IsChecked="{Binding VolumeMuted}"
|
||||||
|
IsVisible="{Binding !ShowLoadProgress}">
|
||||||
|
<ui:ToggleSplitButton.Flyout>
|
||||||
|
<Flyout Placement="Bottom" ShowMode="TransientWithDismissOnPointerMoveAway">
|
||||||
|
<Grid Margin="0">
|
||||||
|
<Slider
|
||||||
|
MaxHeight="40"
|
||||||
|
Width="150"
|
||||||
|
Margin="0"
|
||||||
|
Padding="0"
|
||||||
|
IsSnapToTickEnabled="True"
|
||||||
|
LargeChange="0.05"
|
||||||
|
Maximum="1"
|
||||||
|
Minimum="0"
|
||||||
|
SmallChange="0.01"
|
||||||
|
TickFrequency="0.05"
|
||||||
|
ToolTip.Tip="{locale:Locale AudioVolumeTooltip}"
|
||||||
|
Value="{Binding Volume}" />
|
||||||
|
</Grid>
|
||||||
|
</Flyout>
|
||||||
|
</ui:ToggleSplitButton.Flyout>
|
||||||
|
</ui:ToggleSplitButton>
|
||||||
|
<Border
|
||||||
|
Width="2"
|
||||||
|
Height="12"
|
||||||
|
Margin="0"
|
||||||
|
BorderBrush="Gray"
|
||||||
|
BorderThickness="1"
|
||||||
|
IsVisible="{Binding !ShowLoadProgress}" />
|
||||||
|
<TextBlock
|
||||||
|
Margin="5,0,5,0"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
IsVisible="{Binding !ShowLoadProgress}"
|
||||||
|
Text="{Binding GameStatusText}"
|
||||||
|
TextAlignment="Left" />
|
||||||
|
<Border
|
||||||
|
Width="2"
|
||||||
|
Height="12"
|
||||||
|
Margin="0"
|
||||||
|
BorderBrush="Gray"
|
||||||
|
BorderThickness="1"
|
||||||
|
IsVisible="{Binding !ShowLoadProgress}" />
|
||||||
|
<TextBlock
|
||||||
|
Margin="5,0,5,0"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
IsVisible="{Binding !ShowLoadProgress}"
|
||||||
|
Text="{Binding FifoStatusText}"
|
||||||
|
TextAlignment="Left" />
|
||||||
|
<Border
|
||||||
|
Width="2"
|
||||||
|
Height="12"
|
||||||
|
Margin="0"
|
||||||
|
BorderBrush="Gray"
|
||||||
|
BorderThickness="1"
|
||||||
|
IsVisible="{Binding !ShowLoadProgress}" />
|
||||||
|
<TextBlock
|
||||||
|
Margin="5,0,5,0"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
IsVisible="{Binding !ShowLoadProgress}"
|
||||||
|
Text="{Binding BackendText}"
|
||||||
|
TextAlignment="Left" />
|
||||||
|
<Border
|
||||||
|
Width="2"
|
||||||
|
Height="12"
|
||||||
|
Margin="0"
|
||||||
|
BorderBrush="Gray"
|
||||||
|
BorderThickness="1"
|
||||||
|
IsVisible="{Binding !ShowLoadProgress}" />
|
||||||
|
<TextBlock
|
||||||
|
Margin="5,0,5,0"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
IsVisible="{Binding !ShowLoadProgress}"
|
||||||
|
Text="{Binding GpuNameText}"
|
||||||
|
TextAlignment="Left" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel
|
||||||
|
Grid.Column="3"
|
||||||
|
Margin="0,0,5,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
IsVisible="{Binding ShowFirmwareStatus}"
|
||||||
|
Orientation="Horizontal">
|
||||||
|
<TextBlock
|
||||||
|
Name="FirmwareStatus"
|
||||||
|
Margin="0"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{locale:Locale StatusBarSystemVersion}" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
52
Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml.cs
Normal file
52
Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Input;
|
||||||
|
using Ryujinx.Ava.UI.Windows;
|
||||||
|
using Ryujinx.Common.Configuration;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Ui.Common.Configuration;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Views.Main
|
||||||
|
{
|
||||||
|
public partial class MainStatusBarView : UserControl
|
||||||
|
{
|
||||||
|
public MainWindow Window;
|
||||||
|
|
||||||
|
public MainStatusBarView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnAttachedToVisualTree(e);
|
||||||
|
|
||||||
|
if (VisualRoot is MainWindow window)
|
||||||
|
{
|
||||||
|
Window = window;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataContext = Window.ViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void VsyncStatus_PointerReleased(object sender, PointerReleasedEventArgs e)
|
||||||
|
{
|
||||||
|
Window.ViewModel.AppHost.Device.EnableDeviceVsync = !Window.ViewModel.AppHost.Device.EnableDeviceVsync;
|
||||||
|
|
||||||
|
Logger.Info?.Print(LogClass.Application, $"VSync toggled to: {Window.ViewModel.AppHost.Device.EnableDeviceVsync}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DockedStatus_PointerReleased(object sender, PointerReleasedEventArgs e)
|
||||||
|
{
|
||||||
|
ConfigurationState.Instance.System.EnableDockedMode.Value = !ConfigurationState.Instance.System.EnableDockedMode.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AspectRatioStatus_PointerReleased(object sender, PointerReleasedEventArgs e)
|
||||||
|
{
|
||||||
|
AspectRatio aspectRatio = ConfigurationState.Instance.Graphics.AspectRatio.Value;
|
||||||
|
|
||||||
|
ConfigurationState.Instance.Graphics.AspectRatio.Value = (int)aspectRatio + 1 > Enum.GetNames(typeof(AspectRatio)).Length - 1 ? AspectRatio.Fixed4x3 : aspectRatio + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
176
Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml
Normal file
176
Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
<UserControl
|
||||||
|
xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
|
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
||||||
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Ryujinx.Ava.UI.Views.Main.MainViewControls"
|
||||||
|
x:CompileBindings="True"
|
||||||
|
x:DataType="viewModels:MainWindowViewModel">
|
||||||
|
<Design.DataContext>
|
||||||
|
<viewModels:MainWindowViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
<DockPanel
|
||||||
|
Margin="0,0,0,5"
|
||||||
|
HorizontalAlignment="Stretch">
|
||||||
|
<Button
|
||||||
|
Width="40"
|
||||||
|
MinWidth="40"
|
||||||
|
Margin="5,2,0,2"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
Command="{ReflectionBinding SetListMode}"
|
||||||
|
IsEnabled="{Binding IsGrid}">
|
||||||
|
<ui:FontIcon
|
||||||
|
Margin="0"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
FontFamily="avares://FluentAvalonia/Fonts#Symbols"
|
||||||
|
Glyph="{helpers:GlyphValueConverter List}" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
Width="40"
|
||||||
|
MinWidth="40"
|
||||||
|
Margin="5,2,5,2"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
Command="{ReflectionBinding SetGridMode}"
|
||||||
|
IsEnabled="{Binding IsList}">
|
||||||
|
<ui:FontIcon
|
||||||
|
Margin="0"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
FontFamily="avares://FluentAvalonia/Fonts#Symbols"
|
||||||
|
Glyph="{helpers:GlyphValueConverter Grid}" />
|
||||||
|
</Button>
|
||||||
|
<TextBlock
|
||||||
|
Margin="10,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{locale:Locale IconSize}"
|
||||||
|
ToolTip.Tip="{locale:Locale IconSizeTooltip}" />
|
||||||
|
<Slider
|
||||||
|
Width="150"
|
||||||
|
Height="35"
|
||||||
|
Margin="5,-10,5,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
IsSnapToTickEnabled="True"
|
||||||
|
Maximum="4"
|
||||||
|
Minimum="1"
|
||||||
|
TickFrequency="1"
|
||||||
|
ToolTip.Tip="{locale:Locale IconSizeTooltip}"
|
||||||
|
Value="{Binding GridSizeScale}" />
|
||||||
|
<CheckBox
|
||||||
|
Margin="0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
IsChecked="{Binding ShowNames, Mode=TwoWay}"
|
||||||
|
IsVisible="{Binding IsGrid}">
|
||||||
|
<TextBlock Margin="5,3,0,0" Text="{locale:Locale CommonShowNames}" />
|
||||||
|
</CheckBox>
|
||||||
|
<TextBox
|
||||||
|
Name="SearchBox"
|
||||||
|
MinWidth="200"
|
||||||
|
Margin="5,0,5,0"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
VerticalContentAlignment="Center"
|
||||||
|
DockPanel.Dock="Right"
|
||||||
|
KeyUp="SearchBox_OnKeyUp"
|
||||||
|
Text="{Binding SearchText}"
|
||||||
|
Watermark="{locale:Locale MenuSearch}" />
|
||||||
|
<ui:DropDownButton
|
||||||
|
Width="150"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Content="{Binding SortName}"
|
||||||
|
DockPanel.Dock="Right">
|
||||||
|
<ui:DropDownButton.Flyout>
|
||||||
|
<Flyout Placement="Bottom">
|
||||||
|
<StackPanel
|
||||||
|
Margin="0"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Orientation="Vertical">
|
||||||
|
<StackPanel>
|
||||||
|
<RadioButton
|
||||||
|
Checked="Sort_Checked"
|
||||||
|
Content="{locale:Locale CommonFavorite}"
|
||||||
|
GroupName="Sort"
|
||||||
|
IsChecked="{Binding IsSortedByFavorite, Mode=OneTime}"
|
||||||
|
Tag="Favorite" />
|
||||||
|
<RadioButton
|
||||||
|
Checked="Sort_Checked"
|
||||||
|
Content="{locale:Locale GameListHeaderApplication}"
|
||||||
|
GroupName="Sort"
|
||||||
|
IsChecked="{Binding IsSortedByTitle, Mode=OneTime}"
|
||||||
|
Tag="Title" />
|
||||||
|
<RadioButton
|
||||||
|
Checked="Sort_Checked"
|
||||||
|
Content="{locale:Locale GameListHeaderDeveloper}"
|
||||||
|
GroupName="Sort"
|
||||||
|
IsChecked="{Binding IsSortedByDeveloper, Mode=OneTime}"
|
||||||
|
Tag="Developer" />
|
||||||
|
<RadioButton
|
||||||
|
Checked="Sort_Checked"
|
||||||
|
Content="{locale:Locale GameListHeaderTimePlayed}"
|
||||||
|
GroupName="Sort"
|
||||||
|
IsChecked="{Binding IsSortedByTimePlayed, Mode=OneTime}"
|
||||||
|
Tag="TotalTimePlayed" />
|
||||||
|
<RadioButton
|
||||||
|
Checked="Sort_Checked"
|
||||||
|
Content="{locale:Locale GameListHeaderLastPlayed}"
|
||||||
|
GroupName="Sort"
|
||||||
|
IsChecked="{Binding IsSortedByLastPlayed, Mode=OneTime}"
|
||||||
|
Tag="LastPlayed" />
|
||||||
|
<RadioButton
|
||||||
|
Checked="Sort_Checked"
|
||||||
|
Content="{locale:Locale GameListHeaderFileExtension}"
|
||||||
|
GroupName="Sort"
|
||||||
|
IsChecked="{Binding IsSortedByType, Mode=OneTime}"
|
||||||
|
Tag="FileType" />
|
||||||
|
<RadioButton
|
||||||
|
Checked="Sort_Checked"
|
||||||
|
Content="{locale:Locale GameListHeaderFileSize}"
|
||||||
|
GroupName="Sort"
|
||||||
|
IsChecked="{Binding IsSortedBySize, Mode=OneTime}"
|
||||||
|
Tag="FileSize" />
|
||||||
|
<RadioButton
|
||||||
|
Checked="Sort_Checked"
|
||||||
|
Content="{locale:Locale GameListHeaderPath}"
|
||||||
|
GroupName="Sort"
|
||||||
|
IsChecked="{Binding IsSortedByPath, Mode=OneTime}"
|
||||||
|
Tag="Path" />
|
||||||
|
</StackPanel>
|
||||||
|
<Border
|
||||||
|
Width="60"
|
||||||
|
Height="2"
|
||||||
|
Margin="5"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
BorderBrush="White"
|
||||||
|
BorderThickness="0,1,0,0">
|
||||||
|
<Separator Height="0" HorizontalAlignment="Stretch" />
|
||||||
|
</Border>
|
||||||
|
<RadioButton
|
||||||
|
Checked="Order_Checked"
|
||||||
|
Content="{locale:Locale OrderAscending}"
|
||||||
|
GroupName="Order"
|
||||||
|
IsChecked="{Binding IsAscending, Mode=OneTime}"
|
||||||
|
Tag="Ascending" />
|
||||||
|
<RadioButton
|
||||||
|
Checked="Order_Checked"
|
||||||
|
Content="{locale:Locale OrderDescending}"
|
||||||
|
GroupName="Order"
|
||||||
|
IsChecked="{Binding !IsAscending, Mode=OneTime}"
|
||||||
|
Tag="Descending" />
|
||||||
|
</StackPanel>
|
||||||
|
</Flyout>
|
||||||
|
</ui:DropDownButton.Flyout>
|
||||||
|
</ui:DropDownButton>
|
||||||
|
<TextBlock
|
||||||
|
Margin="10,0"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
DockPanel.Dock="Right"
|
||||||
|
Text="{locale:Locale CommonSort}" />
|
||||||
|
</DockPanel>
|
||||||
|
</UserControl>
|
54
Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml.cs
Normal file
54
Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml.cs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Input;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Ryujinx.Ava.Common;
|
||||||
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
|
using Ryujinx.Ava.UI.Windows;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Views.Main
|
||||||
|
{
|
||||||
|
public partial class MainViewControls : UserControl
|
||||||
|
{
|
||||||
|
public MainWindowViewModel ViewModel;
|
||||||
|
|
||||||
|
public MainViewControls()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnAttachedToVisualTree(e);
|
||||||
|
|
||||||
|
if (VisualRoot is MainWindow window)
|
||||||
|
{
|
||||||
|
ViewModel = window.ViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataContext = ViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Sort_Checked(object sender, RoutedEventArgs args)
|
||||||
|
{
|
||||||
|
if (sender is RadioButton button)
|
||||||
|
{
|
||||||
|
ViewModel.Sort(Enum.Parse<ApplicationSort>(button.Tag.ToString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Order_Checked(object sender, RoutedEventArgs args)
|
||||||
|
{
|
||||||
|
if (sender is RadioButton button)
|
||||||
|
{
|
||||||
|
ViewModel.Sort(button.Tag.ToString() != "Descending");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SearchBox_OnKeyUp(object sender, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
ViewModel.SearchText = SearchBox.Text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
81
Ryujinx.Ava/UI/Views/Settings/SettingsAudioView.axaml
Normal file
81
Ryujinx.Ava/UI/Views/Settings/SettingsAudioView.axaml
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsAudioView"
|
||||||
|
xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
x:CompileBindings="True"
|
||||||
|
x:DataType="viewModels:SettingsViewModel">
|
||||||
|
<Design.DataContext>
|
||||||
|
<viewModels:SettingsViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
<ScrollViewer
|
||||||
|
Name="AudioPage"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
HorizontalScrollBarVisibility="Disabled"
|
||||||
|
VerticalScrollBarVisibility="Auto">
|
||||||
|
<Border Classes="settings">
|
||||||
|
<StackPanel
|
||||||
|
Margin="10"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Orientation="Vertical"
|
||||||
|
Spacing="10">
|
||||||
|
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabAudio}" />
|
||||||
|
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center"
|
||||||
|
Text="{locale:Locale SettingsTabSystemAudioBackend}"
|
||||||
|
ToolTip.Tip="{locale:Locale AudioBackendTooltip}"
|
||||||
|
Width="250" />
|
||||||
|
<ComboBox SelectedIndex="{Binding AudioBackend}"
|
||||||
|
Width="350"
|
||||||
|
HorizontalContentAlignment="Left">
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendDummy}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem IsEnabled="{Binding IsOpenAlEnabled}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendOpenAL}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem IsEnabled="{Binding IsSoundIoEnabled}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendSoundIO}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem IsEnabled="{Binding IsSDL2Enabled}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendSDL2}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center"
|
||||||
|
Text="{locale:Locale SettingsTabSystemAudioVolume}"
|
||||||
|
ToolTip.Tip="{locale:Locale AudioVolumeTooltip}"
|
||||||
|
Width="250" />
|
||||||
|
<ui:NumberBox Value="{Binding Volume}"
|
||||||
|
ToolTip.Tip="{locale:Locale AudioVolumeTooltip}"
|
||||||
|
Width="350"
|
||||||
|
SmallChange="1"
|
||||||
|
LargeChange="10"
|
||||||
|
SimpleNumberFormat="F0"
|
||||||
|
SpinButtonPlacementMode="Inline"
|
||||||
|
Minimum="0"
|
||||||
|
Maximum="100" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||||
|
<Slider Value="{Binding Volume}"
|
||||||
|
Margin="250,0,0,0"
|
||||||
|
ToolTip.Tip="{locale:Locale AudioVolumeTooltip}"
|
||||||
|
Minimum="0"
|
||||||
|
Maximum="100"
|
||||||
|
SmallChange="5"
|
||||||
|
TickFrequency="5"
|
||||||
|
IsSnapToTickEnabled="True"
|
||||||
|
LargeChange="10"
|
||||||
|
Width="350" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</ScrollViewer>
|
||||||
|
</UserControl>
|
12
Ryujinx.Ava/UI/Views/Settings/SettingsAudioView.axaml.cs
Normal file
12
Ryujinx.Ava/UI/Views/Settings/SettingsAudioView.axaml.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Views.Settings
|
||||||
|
{
|
||||||
|
public partial class SettingsAudioView : UserControl
|
||||||
|
{
|
||||||
|
public SettingsAudioView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
72
Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml
Normal file
72
Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsCPUView"
|
||||||
|
xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
x:CompileBindings="True"
|
||||||
|
x:DataType="viewModels:SettingsViewModel">
|
||||||
|
<Design.DataContext>
|
||||||
|
<viewModels:SettingsViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
<ScrollViewer
|
||||||
|
Name="CpuPage"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
HorizontalScrollBarVisibility="Disabled"
|
||||||
|
VerticalScrollBarVisibility="Auto">
|
||||||
|
<Border Classes="settings">
|
||||||
|
<StackPanel
|
||||||
|
Margin="10"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Orientation="Vertical"
|
||||||
|
Spacing="10">
|
||||||
|
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabCpuCache}" />
|
||||||
|
<StackPanel
|
||||||
|
Margin="10,0,0,0"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Orientation="Vertical">
|
||||||
|
<CheckBox IsChecked="{Binding EnablePptc}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemEnablePptc}"
|
||||||
|
ToolTip.Tip="{locale:Locale PptcToggleTooltip}" />
|
||||||
|
</CheckBox>
|
||||||
|
</StackPanel>
|
||||||
|
<Separator Height="1" />
|
||||||
|
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabCpuMemory}" />
|
||||||
|
<StackPanel
|
||||||
|
Margin="10,0,0,0"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Orientation="Vertical">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center"
|
||||||
|
Text="{locale:Locale SettingsTabSystemMemoryManagerMode}"
|
||||||
|
ToolTip.Tip="{locale:Locale MemoryManagerTooltip}"
|
||||||
|
Width="250" />
|
||||||
|
<ComboBox SelectedIndex="{Binding MemoryMode}"
|
||||||
|
ToolTip.Tip="{locale:Locale MemoryManagerTooltip}"
|
||||||
|
HorizontalContentAlignment="Left"
|
||||||
|
Width="350">
|
||||||
|
<ComboBoxItem
|
||||||
|
ToolTip.Tip="{locale:Locale MemoryManagerSoftwareTooltip}">
|
||||||
|
<TextBlock
|
||||||
|
Text="{locale:Locale SettingsTabSystemMemoryManagerModeSoftware}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem
|
||||||
|
ToolTip.Tip="{locale:Locale MemoryManagerHostTooltip}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemMemoryManagerModeHost}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem
|
||||||
|
ToolTip.Tip="{locale:Locale MemoryManagerUnsafeTooltip}">
|
||||||
|
<TextBlock
|
||||||
|
Text="{locale:Locale SettingsTabSystemMemoryManagerModeHostUnchecked}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</ScrollViewer>
|
||||||
|
</UserControl>
|
12
Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml.cs
Normal file
12
Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Views.Settings
|
||||||
|
{
|
||||||
|
public partial class SettingsCPUView : UserControl
|
||||||
|
{
|
||||||
|
public SettingsCPUView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
218
Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml
Normal file
218
Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsGraphicsView"
|
||||||
|
xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
x:CompileBindings="True"
|
||||||
|
x:DataType="viewModels:SettingsViewModel">
|
||||||
|
<Design.DataContext>
|
||||||
|
<viewModels:SettingsViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
<ScrollViewer
|
||||||
|
Name="GraphicsPage"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
HorizontalScrollBarVisibility="Disabled"
|
||||||
|
VerticalScrollBarVisibility="Auto">
|
||||||
|
<Border Classes="settings">
|
||||||
|
<StackPanel
|
||||||
|
Margin="10"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Orientation="Vertical"
|
||||||
|
Spacing="10">
|
||||||
|
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGraphicsAPI}" />
|
||||||
|
<StackPanel Margin="10,0,0,0" Orientation="Vertical" Spacing="10">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center"
|
||||||
|
ToolTip.Tip="{locale:Locale SettingsTabGraphicsBackendTooltip}"
|
||||||
|
Text="{locale:Locale SettingsTabGraphicsBackend}"
|
||||||
|
Width="250" />
|
||||||
|
<ComboBox Width="350"
|
||||||
|
HorizontalContentAlignment="Left"
|
||||||
|
ToolTip.Tip="{locale:Locale SettingsTabGraphicsBackendTooltip}"
|
||||||
|
SelectedIndex="{Binding GraphicsBackendIndex}">
|
||||||
|
<ComboBoxItem IsVisible="{Binding IsVulkanAvailable}">
|
||||||
|
<TextBlock Text="Vulkan" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem IsEnabled="{Binding IsOpenGLAvailable}">
|
||||||
|
<TextBlock Text="OpenGL" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal" IsVisible="{Binding IsVulkanSelected}">
|
||||||
|
<TextBlock VerticalAlignment="Center"
|
||||||
|
ToolTip.Tip="{locale:Locale SettingsTabGraphicsPreferredGpuTooltip}"
|
||||||
|
Text="{locale:Locale SettingsTabGraphicsPreferredGpu}"
|
||||||
|
Width="250" />
|
||||||
|
<ComboBox Width="350"
|
||||||
|
HorizontalContentAlignment="Left"
|
||||||
|
ToolTip.Tip="{locale:Locale SettingsTabGraphicsPreferredGpuTooltip}"
|
||||||
|
SelectedIndex="{Binding PreferredGpuIndex}"
|
||||||
|
Items="{Binding AvailableGpus}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
<Separator Height="1" />
|
||||||
|
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGraphicsFeatures}" />
|
||||||
|
<StackPanel Margin="10,0,0,0" Orientation="Vertical" Spacing="10">
|
||||||
|
<StackPanel Orientation="Vertical">
|
||||||
|
<CheckBox IsChecked="{Binding EnableShaderCache}"
|
||||||
|
ToolTip.Tip="{locale:Locale ShaderCacheToggleTooltip}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGraphicsEnableShaderCache}" />
|
||||||
|
</CheckBox>
|
||||||
|
<CheckBox IsChecked="{Binding EnableTextureRecompression}"
|
||||||
|
ToolTip.Tip="{locale:Locale SettingsEnableTextureRecompressionTooltip}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsEnableTextureRecompression}" />
|
||||||
|
</CheckBox>
|
||||||
|
<CheckBox IsChecked="{Binding EnableMacroHLE}"
|
||||||
|
ToolTip.Tip="{locale:Locale SettingsEnableMacroHLETooltip}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsEnableMacroHLE}" />
|
||||||
|
</CheckBox>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center"
|
||||||
|
ToolTip.Tip="{locale:Locale ResolutionScaleTooltip}"
|
||||||
|
Text="{locale:Locale SettingsTabGraphicsResolutionScale}"
|
||||||
|
Width="250" />
|
||||||
|
<ComboBox SelectedIndex="{Binding ResolutionScale}"
|
||||||
|
Width="350"
|
||||||
|
HorizontalContentAlignment="Left"
|
||||||
|
ToolTip.Tip="{locale:Locale ResolutionScaleTooltip}">
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScaleCustom}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScaleNative}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScale2x}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScale3x}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScale4x}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
</ComboBox>
|
||||||
|
<ui:NumberBox
|
||||||
|
Margin="10,0,0,0"
|
||||||
|
ToolTip.Tip="{locale:Locale ResolutionScaleEntryTooltip}"
|
||||||
|
MinWidth="150"
|
||||||
|
SmallChange="0.1"
|
||||||
|
LargeChange="1"
|
||||||
|
SimpleNumberFormat="F2"
|
||||||
|
SpinButtonPlacementMode="Inline"
|
||||||
|
IsVisible="{Binding IsCustomResolutionScaleActive}"
|
||||||
|
Maximum="100"
|
||||||
|
Minimum="0.1"
|
||||||
|
Value="{Binding CustomResolutionScale}" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center"
|
||||||
|
ToolTip.Tip="{locale:Locale AnisotropyTooltip}"
|
||||||
|
Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering}"
|
||||||
|
Width="250" />
|
||||||
|
<ComboBox SelectedIndex="{Binding MaxAnisotropy}"
|
||||||
|
Width="350"
|
||||||
|
HorizontalContentAlignment="Left"
|
||||||
|
ToolTip.Tip="{locale:Locale AnisotropyTooltip}">
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock
|
||||||
|
Text="{locale:Locale SettingsTabGraphicsAnisotropicFilteringAuto}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering2x}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering4x}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering8x}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock
|
||||||
|
Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering16x}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center"
|
||||||
|
ToolTip.Tip="{locale:Locale AspectRatioTooltip}"
|
||||||
|
Text="{locale:Locale SettingsTabGraphicsAspectRatio}"
|
||||||
|
Width="250" />
|
||||||
|
<ComboBox SelectedIndex="{Binding AspectRatio}"
|
||||||
|
Width="350"
|
||||||
|
HorizontalContentAlignment="Left"
|
||||||
|
ToolTip.Tip="{locale:Locale AspectRatioTooltip}">
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio4x3}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio16x9}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio16x10}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio21x9}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio32x9}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatioStretch}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel
|
||||||
|
Margin="10,0,0,0"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Orientation="Vertical"
|
||||||
|
Spacing="10">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center"
|
||||||
|
ToolTip.Tip="{locale:Locale GraphicsBackendThreadingTooltip}"
|
||||||
|
Text="{locale:Locale SettingsTabGraphicsBackendMultithreading}"
|
||||||
|
Width="250" />
|
||||||
|
<ComboBox Width="350"
|
||||||
|
HorizontalContentAlignment="Left"
|
||||||
|
ToolTip.Tip="{locale:Locale GalThreadingTooltip}"
|
||||||
|
SelectedIndex="{Binding GraphicsBackendMultithreadingIndex}">
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale CommonAuto}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale CommonOff}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale CommonOn}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
<Separator Height="1" />
|
||||||
|
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGraphicsDeveloperOptions}" />
|
||||||
|
<StackPanel
|
||||||
|
Margin="10,0,0,0"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Orientation="Vertical"
|
||||||
|
Spacing="10">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center"
|
||||||
|
ToolTip.Tip="{locale:Locale ShaderDumpPathTooltip}"
|
||||||
|
Text="{locale:Locale SettingsTabGraphicsShaderDumpPath}"
|
||||||
|
Width="250" />
|
||||||
|
<TextBox Text="{Binding ShaderDumpPath}"
|
||||||
|
Width="350"
|
||||||
|
ToolTip.Tip="{locale:Locale ShaderDumpPathTooltip}" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</ScrollViewer>
|
||||||
|
</UserControl>
|
12
Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml.cs
Normal file
12
Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Views.Settings
|
||||||
|
{
|
||||||
|
public partial class SettingsGraphicsView : UserControl
|
||||||
|
{
|
||||||
|
public SettingsGraphicsView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
104
Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml
Normal file
104
Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsHotkeysView"
|
||||||
|
xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
|
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
x:CompileBindings="True"
|
||||||
|
x:DataType="viewModels:SettingsViewModel"
|
||||||
|
Focusable="True">
|
||||||
|
<Design.DataContext>
|
||||||
|
<viewModels:SettingsViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
<UserControl.Resources>
|
||||||
|
<helpers:KeyValueConverter x:Key="Key" />
|
||||||
|
</UserControl.Resources>
|
||||||
|
<ScrollViewer
|
||||||
|
Name="HotkeysPage"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
HorizontalScrollBarVisibility="Disabled"
|
||||||
|
VerticalScrollBarVisibility="Auto">
|
||||||
|
<Border Classes="settings">
|
||||||
|
<StackPanel Margin="10" Orientation="Vertical" Spacing="10">
|
||||||
|
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabHotkeysHotkeys}" />
|
||||||
|
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysToggleVsyncHotkey}" Width="230" />
|
||||||
|
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding KeyboardHotkeys.ToggleVsync, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
</ToggleButton>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysScreenshotHotkey}" Width="230" />
|
||||||
|
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding KeyboardHotkeys.Screenshot, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
</ToggleButton>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysShowUiHotkey}" Width="230" />
|
||||||
|
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding KeyboardHotkeys.ShowUi, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
</ToggleButton>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysPauseHotkey}" Width="230" />
|
||||||
|
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding KeyboardHotkeys.Pause, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
</ToggleButton>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysToggleMuteHotkey}" Width="230" />
|
||||||
|
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding KeyboardHotkeys.ToggleMute, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
</ToggleButton>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysResScaleUpHotkey}" Width="230" />
|
||||||
|
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding KeyboardHotkeys.ResScaleUp, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
</ToggleButton>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysResScaleDownHotkey}" Width="230" />
|
||||||
|
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding KeyboardHotkeys.ResScaleDown, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
</ToggleButton>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysVolumeUpHotkey}" Width="230" />
|
||||||
|
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding KeyboardHotkeys.VolumeUp, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
</ToggleButton>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysVolumeDownHotkey}" Width="230" />
|
||||||
|
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding KeyboardHotkeys.VolumeDown, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
</ToggleButton>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</ScrollViewer>
|
||||||
|
</UserControl>
|
81
Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml.cs
Normal file
81
Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml.cs
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.Primitives;
|
||||||
|
using Avalonia.Input;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Ryujinx.Ava.Input;
|
||||||
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
|
using Ryujinx.Input;
|
||||||
|
using Ryujinx.Input.Assigner;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Views.Settings
|
||||||
|
{
|
||||||
|
public partial class SettingsHotkeysView : UserControl
|
||||||
|
{
|
||||||
|
private ButtonKeyAssigner _currentAssigner;
|
||||||
|
private IGamepadDriver AvaloniaKeyboardDriver;
|
||||||
|
|
||||||
|
public SettingsHotkeysView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
AvaloniaKeyboardDriver = new AvaloniaKeyboardDriver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MouseClick(object sender, PointerPressedEventArgs e)
|
||||||
|
{
|
||||||
|
bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed;
|
||||||
|
|
||||||
|
_currentAssigner?.Cancel(shouldUnbind);
|
||||||
|
|
||||||
|
PointerPressed -= MouseClick;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Button_Checked(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is ToggleButton button)
|
||||||
|
{
|
||||||
|
if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentAssigner == null && button.IsChecked != null && (bool)button.IsChecked)
|
||||||
|
{
|
||||||
|
_currentAssigner = new ButtonKeyAssigner(button);
|
||||||
|
|
||||||
|
FocusManager.Instance?.Focus(this, NavigationMethod.Pointer);
|
||||||
|
|
||||||
|
PointerPressed += MouseClick;
|
||||||
|
|
||||||
|
var keyboard = (IKeyboard)AvaloniaKeyboardDriver.GetGamepad(AvaloniaKeyboardDriver.GamepadsIds[0]);
|
||||||
|
IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard);
|
||||||
|
|
||||||
|
_currentAssigner.GetInputAndAssign(assigner);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_currentAssigner != null)
|
||||||
|
{
|
||||||
|
ToggleButton oldButton = _currentAssigner.ToggledButton;
|
||||||
|
|
||||||
|
_currentAssigner.Cancel();
|
||||||
|
_currentAssigner = null;
|
||||||
|
|
||||||
|
button.IsChecked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Button_Unchecked(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
_currentAssigner?.Cancel();
|
||||||
|
_currentAssigner = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_currentAssigner?.Cancel();
|
||||||
|
_currentAssigner = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
46
Ryujinx.Ava/UI/Views/Settings/SettingsInputView.axaml
Normal file
46
Ryujinx.Ava/UI/Views/Settings/SettingsInputView.axaml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsInputView"
|
||||||
|
xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
|
xmlns:window="clr-namespace:Ryujinx.Ava.UI.Windows"
|
||||||
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
x:CompileBindings="True"
|
||||||
|
x:DataType="viewModels:SettingsViewModel">
|
||||||
|
<Design.DataContext>
|
||||||
|
<viewModels:SettingsViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
<ScrollViewer
|
||||||
|
Name="InputPage"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
HorizontalScrollBarVisibility="Disabled"
|
||||||
|
VerticalScrollBarVisibility="Auto">
|
||||||
|
<Border Classes="settings">
|
||||||
|
<StackPanel Margin="4" Orientation="Vertical">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<CheckBox Margin="5,0"
|
||||||
|
ToolTip.Tip="{locale:Locale DockModeToggleTooltip}"
|
||||||
|
IsChecked="{Binding EnableDockedMode}">
|
||||||
|
<TextBlock VerticalAlignment="Center"
|
||||||
|
Text="{locale:Locale SettingsTabInputEnableDockedMode}" />
|
||||||
|
</CheckBox>
|
||||||
|
<CheckBox Margin="5,0"
|
||||||
|
ToolTip.Tip="{locale:Locale DirectKeyboardTooltip}"
|
||||||
|
IsChecked="{Binding EnableKeyboard}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabInputDirectKeyboardAccess}" />
|
||||||
|
</CheckBox>
|
||||||
|
<CheckBox Margin="5,0"
|
||||||
|
ToolTip.Tip="{locale:Locale DirectMouseTooltip}"
|
||||||
|
IsChecked="{Binding EnableMouse}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabInputDirectMouseAccess}" />
|
||||||
|
</CheckBox>
|
||||||
|
</StackPanel>
|
||||||
|
<window:ControllerSettingsWindow Name="ControllerSettings" Margin="0" MinHeight="600" />
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</ScrollViewer>
|
||||||
|
</UserControl>
|
17
Ryujinx.Ava/UI/Views/Settings/SettingsInputView.axaml.cs
Normal file
17
Ryujinx.Ava/UI/Views/Settings/SettingsInputView.axaml.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Views.Settings
|
||||||
|
{
|
||||||
|
public partial class SettingsInputView : UserControl
|
||||||
|
{
|
||||||
|
public SettingsInputView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
ControllerSettings.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
118
Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml
Normal file
118
Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsLoggingView"
|
||||||
|
xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
x:CompileBindings="True"
|
||||||
|
x:DataType="viewModels:SettingsViewModel">
|
||||||
|
<Design.DataContext>
|
||||||
|
<viewModels:SettingsViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
<ScrollViewer
|
||||||
|
Name="LoggingPage"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
HorizontalScrollBarVisibility="Disabled"
|
||||||
|
VerticalScrollBarVisibility="Auto">
|
||||||
|
<Border Classes="settings">
|
||||||
|
<StackPanel
|
||||||
|
Margin="10"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Orientation="Vertical"
|
||||||
|
Spacing="10">
|
||||||
|
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabLoggingLogging}" />
|
||||||
|
<StackPanel Margin="10,0,0,0" Orientation="Vertical">
|
||||||
|
<CheckBox IsChecked="{Binding EnableFileLog}"
|
||||||
|
ToolTip.Tip="{locale:Locale FileLogTooltip}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableLoggingToFile}" />
|
||||||
|
</CheckBox>
|
||||||
|
<CheckBox IsChecked="{Binding EnableStub}"
|
||||||
|
ToolTip.Tip="{locale:Locale StubLogTooltip}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableStubLogs}" />
|
||||||
|
</CheckBox>
|
||||||
|
<CheckBox IsChecked="{Binding EnableInfo}"
|
||||||
|
ToolTip.Tip="{locale:Locale InfoLogTooltip}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableInfoLogs}" />
|
||||||
|
</CheckBox>
|
||||||
|
<CheckBox IsChecked="{Binding EnableWarn}"
|
||||||
|
ToolTip.Tip="{locale:Locale WarnLogTooltip}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableWarningLogs}" />
|
||||||
|
</CheckBox>
|
||||||
|
<CheckBox IsChecked="{Binding EnableError}"
|
||||||
|
ToolTip.Tip="{locale:Locale ErrorLogTooltip}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableErrorLogs}" />
|
||||||
|
</CheckBox>
|
||||||
|
<CheckBox IsChecked="{Binding EnableTrace}"
|
||||||
|
ToolTip.Tip="{locale:Locale TraceLogTooltip}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableTraceLogs}" />
|
||||||
|
</CheckBox>
|
||||||
|
<CheckBox IsChecked="{Binding EnableGuest}"
|
||||||
|
ToolTip.Tip="{locale:Locale GuestLogTooltip}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableGuestLogs}" />
|
||||||
|
</CheckBox>
|
||||||
|
</StackPanel>
|
||||||
|
<Separator Height="1" />
|
||||||
|
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabLoggingDeveloperOptions}" />
|
||||||
|
<StackPanel
|
||||||
|
Margin="10,0,0,0"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Orientation="Vertical"
|
||||||
|
Spacing="10">
|
||||||
|
<StackPanel Orientation="Vertical">
|
||||||
|
<CheckBox IsChecked="{Binding EnableDebug}"
|
||||||
|
ToolTip.Tip="{locale:Locale DebugLogTooltip}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableDebugLogs}" />
|
||||||
|
</CheckBox>
|
||||||
|
<CheckBox IsChecked="{Binding EnableFsAccessLog}"
|
||||||
|
ToolTip.Tip="{locale:Locale FileAccessLogTooltip}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableFsAccessLogs}" />
|
||||||
|
</CheckBox>
|
||||||
|
<StackPanel Margin="0,10,0,0" Orientation="Horizontal" VerticalAlignment="Stretch">
|
||||||
|
<TextBlock VerticalAlignment="Center"
|
||||||
|
ToolTip.Tip="{locale:Locale FSAccessLogModeTooltip}"
|
||||||
|
Text="{locale:Locale SettingsTabLoggingFsGlobalAccessLogMode}"
|
||||||
|
Width="285" />
|
||||||
|
<ui:NumberBox
|
||||||
|
Maximum="3"
|
||||||
|
Minimum="0"
|
||||||
|
Width="150"
|
||||||
|
SpinButtonPlacementMode="Inline"
|
||||||
|
SmallChange="1"
|
||||||
|
LargeChange="1"
|
||||||
|
Value="{Binding FsGlobalAccessLogMode}" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Margin="0,10,0,0" Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center"
|
||||||
|
Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevel}"
|
||||||
|
ToolTip.Tip="{locale:Locale OpenGlLogLevel}"
|
||||||
|
Width="285" />
|
||||||
|
<ComboBox SelectedIndex="{Binding OpenglDebugLevel}"
|
||||||
|
Width="150"
|
||||||
|
HorizontalContentAlignment="Left"
|
||||||
|
ToolTip.Tip="{locale:Locale OpenGlLogLevel}">
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelNone}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelError}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock
|
||||||
|
Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelPerformance}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelAll}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</ScrollViewer>
|
||||||
|
</UserControl>
|
12
Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml.cs
Normal file
12
Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Views.Settings
|
||||||
|
{
|
||||||
|
public partial class SettingsLoggingView : UserControl
|
||||||
|
{
|
||||||
|
public SettingsLoggingView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml
Normal file
35
Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsNetworkView"
|
||||||
|
xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
x:CompileBindings="True"
|
||||||
|
x:DataType="viewModels:SettingsViewModel">
|
||||||
|
<Design.DataContext>
|
||||||
|
<viewModels:SettingsViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
<ScrollViewer
|
||||||
|
Name="NetworkPage"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
HorizontalScrollBarVisibility="Disabled"
|
||||||
|
VerticalScrollBarVisibility="Auto">
|
||||||
|
<Border Classes="settings">
|
||||||
|
<StackPanel
|
||||||
|
Margin="10"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Orientation="Vertical"
|
||||||
|
Spacing="10">
|
||||||
|
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabNetworkConnection}" />
|
||||||
|
<CheckBox Margin="10,0,0,0" IsChecked="{Binding EnableInternetAccess}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemEnableInternetAccess}"
|
||||||
|
ToolTip.Tip="{locale:Locale EnableInternetAccessTooltip}" />
|
||||||
|
</CheckBox>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</ScrollViewer>
|
||||||
|
</UserControl>
|
12
Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml.cs
Normal file
12
Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Views.Settings
|
||||||
|
{
|
||||||
|
public partial class SettingsNetworkView : UserControl
|
||||||
|
{
|
||||||
|
public SettingsNetworkView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
195
Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml
Normal file
195
Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsSystemView"
|
||||||
|
xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
x:CompileBindings="True"
|
||||||
|
x:DataType="viewModels:SettingsViewModel">
|
||||||
|
<Design.DataContext>
|
||||||
|
<viewModels:SettingsViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
<ScrollViewer
|
||||||
|
Name="SystemPage"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
HorizontalScrollBarVisibility="Disabled"
|
||||||
|
VerticalScrollBarVisibility="Auto">
|
||||||
|
<Border Classes="settings">
|
||||||
|
<StackPanel
|
||||||
|
Margin="10"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Orientation="Vertical"
|
||||||
|
Spacing="10">
|
||||||
|
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabSystemCore}" />
|
||||||
|
<StackPanel Margin="10,0,0,0" Orientation="Vertical">
|
||||||
|
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center"
|
||||||
|
Text="{locale:Locale SettingsTabSystemSystemRegion}"
|
||||||
|
Width="250" />
|
||||||
|
<ComboBox SelectedIndex="{Binding Region}"
|
||||||
|
ToolTip.Tip="{locale:Locale RegionTooltip}"
|
||||||
|
HorizontalContentAlignment="Left"
|
||||||
|
Width="350">
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionJapan}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionUSA}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionEurope}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionAustralia}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionChina}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionKorea}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionTaiwan}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center"
|
||||||
|
Text="{locale:Locale SettingsTabSystemSystemLanguage}"
|
||||||
|
ToolTip.Tip="{locale:Locale LanguageTooltip}"
|
||||||
|
Width="250" />
|
||||||
|
<ComboBox SelectedIndex="{Binding Language}"
|
||||||
|
ToolTip.Tip="{locale:Locale LanguageTooltip}"
|
||||||
|
HorizontalContentAlignment="Left"
|
||||||
|
Width="350">
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageJapanese}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock
|
||||||
|
Text="{locale:Locale SettingsTabSystemSystemLanguageAmericanEnglish}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageFrench}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageGerman}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageItalian}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageSpanish}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageChinese}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageKorean}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageDutch}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguagePortuguese}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageRussian}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageTaiwanese}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock
|
||||||
|
Text="{locale:Locale SettingsTabSystemSystemLanguageBritishEnglish}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock
|
||||||
|
Text="{locale:Locale SettingsTabSystemSystemLanguageCanadianFrench}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock
|
||||||
|
Text="{locale:Locale SettingsTabSystemSystemLanguageLatinAmericanSpanish}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock
|
||||||
|
Text="{locale:Locale SettingsTabSystemSystemLanguageSimplifiedChinese}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock
|
||||||
|
Text="{locale:Locale SettingsTabSystemSystemLanguageTraditionalChinese}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock
|
||||||
|
Text="{locale:Locale SettingsTabSystemSystemLanguageBrazilianPortuguese}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center"
|
||||||
|
Text="{locale:Locale SettingsTabSystemSystemTimeZone}"
|
||||||
|
ToolTip.Tip="{locale:Locale TimezoneTooltip}"
|
||||||
|
Width="250" />
|
||||||
|
<AutoCompleteBox
|
||||||
|
Name="TimeZoneBox"
|
||||||
|
Width="350"
|
||||||
|
MaxDropDownHeight="500"
|
||||||
|
FilterMode="Contains"
|
||||||
|
Items="{Binding TimeZones}"
|
||||||
|
SelectionChanged="TimeZoneBox_OnSelectionChanged"
|
||||||
|
Text="{Binding Path=TimeZone, Mode=OneWay}"
|
||||||
|
TextChanged="TimeZoneBox_OnTextChanged"
|
||||||
|
ToolTip.Tip="{locale:Locale TimezoneTooltip}" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center"
|
||||||
|
Text="{locale:Locale SettingsTabSystemSystemTime}"
|
||||||
|
ToolTip.Tip="{locale:Locale TimeTooltip}"
|
||||||
|
Width="250"/>
|
||||||
|
<DatePicker VerticalAlignment="Center" SelectedDate="{Binding DateOffset}"
|
||||||
|
ToolTip.Tip="{locale:Locale TimeTooltip}"
|
||||||
|
Width="350" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Margin="250,0,0,10" Orientation="Horizontal">
|
||||||
|
<TimePicker
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
ClockIdentifier="24HourClock"
|
||||||
|
SelectedTime="{Binding TimeOffset}"
|
||||||
|
Width="350"
|
||||||
|
ToolTip.Tip="{locale:Locale TimeTooltip}" />
|
||||||
|
</StackPanel>
|
||||||
|
<CheckBox IsChecked="{Binding EnableVsync}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemEnableVsync}"
|
||||||
|
ToolTip.Tip="{locale:Locale VSyncToggleTooltip}" />
|
||||||
|
</CheckBox>
|
||||||
|
<CheckBox IsChecked="{Binding EnableFsIntegrityChecks}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemEnableFsIntegrityChecks}"
|
||||||
|
ToolTip.Tip="{locale:Locale FsIntegrityToggleTooltip}" />
|
||||||
|
</CheckBox>
|
||||||
|
</StackPanel>
|
||||||
|
<Separator Height="1" />
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabSystemHacks}" />
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemHacksNote}" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel
|
||||||
|
Margin="10,0,0,0"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Orientation="Vertical">
|
||||||
|
<CheckBox IsChecked="{Binding ExpandDramSize}"
|
||||||
|
ToolTip.Tip="{locale:Locale DRamTooltip}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemExpandDramSize}" />
|
||||||
|
</CheckBox>
|
||||||
|
<CheckBox IsChecked="{Binding IgnoreMissingServices}"
|
||||||
|
ToolTip.Tip="{locale:Locale IgnoreMissingServicesTooltip}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabSystemIgnoreMissingServices}" />
|
||||||
|
</CheckBox>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</ScrollViewer>
|
||||||
|
</UserControl>
|
52
Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml.cs
Normal file
52
Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Data;
|
||||||
|
using Avalonia.Data.Converters;
|
||||||
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using TimeZone = Ryujinx.Ava.UI.Models.TimeZone;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Views.Settings
|
||||||
|
{
|
||||||
|
public partial class SettingsSystemView : UserControl
|
||||||
|
{
|
||||||
|
public SettingsViewModel ViewModel;
|
||||||
|
|
||||||
|
public SettingsSystemView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
FuncMultiValueConverter<string, string> converter = new(parts => string.Format("{0} {1} {2}", parts.ToArray()).Trim());
|
||||||
|
MultiBinding tzMultiBinding = new() { Converter = converter };
|
||||||
|
|
||||||
|
tzMultiBinding.Bindings.Add(new Binding("UtcDifference"));
|
||||||
|
tzMultiBinding.Bindings.Add(new Binding("Location"));
|
||||||
|
tzMultiBinding.Bindings.Add(new Binding("Abbreviation"));
|
||||||
|
|
||||||
|
TimeZoneBox.ValueMemberBinding = tzMultiBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TimeZoneBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.AddedItems != null && e.AddedItems.Count > 0)
|
||||||
|
{
|
||||||
|
if (e.AddedItems[0] is TimeZone timeZone)
|
||||||
|
{
|
||||||
|
e.Handled = true;
|
||||||
|
|
||||||
|
ViewModel.ValidateAndSetTimeZone(timeZone.Location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TimeZoneBox_OnTextChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is AutoCompleteBox box && box.SelectedItem is TimeZone timeZone)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
ViewModel.ValidateAndSetTimeZone(timeZone.Location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
156
Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml
Normal file
156
Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsUIView"
|
||||||
|
xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
x:CompileBindings="True"
|
||||||
|
x:DataType="viewModels:SettingsViewModel">
|
||||||
|
<Design.DataContext>
|
||||||
|
<viewModels:SettingsViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
<ScrollViewer
|
||||||
|
Name="UiPage"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
HorizontalScrollBarVisibility="Disabled"
|
||||||
|
VerticalScrollBarVisibility="Auto">
|
||||||
|
<Border Classes="settings">
|
||||||
|
<StackPanel
|
||||||
|
Margin="10"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Orientation="Vertical"
|
||||||
|
Spacing="10">
|
||||||
|
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGeneralGeneral}" />
|
||||||
|
<StackPanel Margin="10,0,0,0" Orientation="Vertical">
|
||||||
|
<CheckBox IsChecked="{Binding EnableDiscordIntegration}">
|
||||||
|
<TextBlock VerticalAlignment="Center"
|
||||||
|
ToolTip.Tip="{locale:Locale ToggleDiscordTooltip}"
|
||||||
|
Text="{locale:Locale SettingsTabGeneralEnableDiscordRichPresence}" />
|
||||||
|
</CheckBox>
|
||||||
|
<CheckBox IsChecked="{Binding CheckUpdatesOnStart}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGeneralCheckUpdatesOnLaunch}" />
|
||||||
|
</CheckBox>
|
||||||
|
<CheckBox IsChecked="{Binding ShowConfirmExit}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGeneralShowConfirmExitDialog}" />
|
||||||
|
</CheckBox>
|
||||||
|
<CheckBox IsChecked="{Binding HideCursorOnIdle}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGeneralHideCursorOnIdle}" />
|
||||||
|
</CheckBox>
|
||||||
|
</StackPanel>
|
||||||
|
<Separator Height="1" />
|
||||||
|
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGeneralGameDirectories}" />
|
||||||
|
<StackPanel
|
||||||
|
Margin="10,0,0,0"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Orientation="Vertical"
|
||||||
|
Spacing="10">
|
||||||
|
<ListBox
|
||||||
|
Name="GameList"
|
||||||
|
MinHeight="230"
|
||||||
|
Items="{Binding GameDirectories}">
|
||||||
|
<ListBox.Styles>
|
||||||
|
<Style Selector="ListBoxItem">
|
||||||
|
<Setter Property="Padding" Value="10" />
|
||||||
|
<Setter Property="Background" Value="{DynamicResource ListBoxBackground}" />
|
||||||
|
</Style>
|
||||||
|
</ListBox.Styles>
|
||||||
|
</ListBox>
|
||||||
|
<Grid HorizontalAlignment="Stretch">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBox
|
||||||
|
Name="PathBox"
|
||||||
|
Margin="0"
|
||||||
|
ToolTip.Tip="{locale:Locale AddGameDirBoxTooltip}"
|
||||||
|
VerticalAlignment="Stretch" />
|
||||||
|
<Button
|
||||||
|
Name="AddButton"
|
||||||
|
Grid.Column="1"
|
||||||
|
MinWidth="90"
|
||||||
|
Margin="10,0,0,0"
|
||||||
|
ToolTip.Tip="{locale:Locale AddGameDirTooltip}"
|
||||||
|
Click="AddButton_OnClick">
|
||||||
|
<TextBlock HorizontalAlignment="Center"
|
||||||
|
Text="{locale:Locale SettingsTabGeneralAdd}" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
Name="RemoveButton"
|
||||||
|
Grid.Column="2"
|
||||||
|
MinWidth="90"
|
||||||
|
Margin="10,0,0,0"
|
||||||
|
ToolTip.Tip="{locale:Locale RemoveGameDirTooltip}"
|
||||||
|
Click="RemoveButton_OnClick">
|
||||||
|
<TextBlock HorizontalAlignment="Center"
|
||||||
|
Text="{locale:Locale SettingsTabGeneralRemove}" />
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
<Separator Height="1" />
|
||||||
|
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGeneralTheme}" />
|
||||||
|
<Grid Margin="10,0,0,0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition />
|
||||||
|
<RowDefinition />
|
||||||
|
<RowDefinition />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<CheckBox
|
||||||
|
IsChecked="{Binding EnableCustomTheme}"
|
||||||
|
ToolTip.Tip="{locale:Locale CustomThemeCheckTooltip}">
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGeneralThemeEnableCustomTheme}" />
|
||||||
|
</CheckBox>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.Row="1"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Margin="0,10,0,0"
|
||||||
|
Text="{locale:Locale SettingsTabGeneralThemeCustomTheme}"
|
||||||
|
ToolTip.Tip="{locale:Locale CustomThemePathTooltip}" />
|
||||||
|
<TextBox
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="0,10,0,0"
|
||||||
|
Text="{Binding CustomThemePath}" />
|
||||||
|
<Button
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="10,10,0,0"
|
||||||
|
Click="BrowseTheme"
|
||||||
|
ToolTip.Tip="{locale:Locale CustomThemeBrowseTooltip}"
|
||||||
|
Content="{locale:Locale ButtonBrowse}" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.Row="2"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Margin="0,10,0,0"
|
||||||
|
Text="{locale:Locale SettingsTabGeneralThemeBaseStyle}" />
|
||||||
|
<ComboBox
|
||||||
|
Grid.Column="1"
|
||||||
|
Grid.Row="2"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Margin="0,10,0,0"
|
||||||
|
MinWidth="100"
|
||||||
|
SelectedIndex="{Binding BaseStyleIndex}">
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGeneralThemeBaseStyleLight}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGeneralThemeBaseStyleDark}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
</ComboBox>
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</ScrollViewer>
|
||||||
|
</UserControl>
|
82
Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml.cs
Normal file
82
Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml.cs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Ryujinx.Ava.Common.Locale;
|
||||||
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Views.Settings
|
||||||
|
{
|
||||||
|
public partial class SettingsUIView : UserControl
|
||||||
|
{
|
||||||
|
public SettingsViewModel ViewModel;
|
||||||
|
|
||||||
|
public SettingsUIView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void AddButton_OnClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
string path = PathBox.Text;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path) && !ViewModel.GameDirectories.Contains(path))
|
||||||
|
{
|
||||||
|
ViewModel.GameDirectories.Add(path);
|
||||||
|
ViewModel.DirectoryChanged = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
|
{
|
||||||
|
path = await new OpenFolderDialog().ShowAsync(desktop.MainWindow);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(path))
|
||||||
|
{
|
||||||
|
ViewModel.GameDirectories.Add(path);
|
||||||
|
ViewModel.DirectoryChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveButton_OnClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
int oldIndex = GameList.SelectedIndex;
|
||||||
|
|
||||||
|
foreach (string path in new List<string>(GameList.SelectedItems.Cast<string>()))
|
||||||
|
{
|
||||||
|
ViewModel.GameDirectories.Remove(path);
|
||||||
|
ViewModel.DirectoryChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GameList.ItemCount > 0)
|
||||||
|
{
|
||||||
|
GameList.SelectedIndex = oldIndex < GameList.ItemCount ? oldIndex : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void BrowseTheme(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var dialog = new OpenFileDialog()
|
||||||
|
{
|
||||||
|
Title = LocaleManager.Instance[LocaleKeys.SettingsSelectThemeFileDialogTitle],
|
||||||
|
AllowMultiple = false
|
||||||
|
};
|
||||||
|
|
||||||
|
dialog.Filters.Add(new FileDialogFilter() { Extensions = { "xaml" }, Name = LocaleManager.Instance[LocaleKeys.SettingsXamlThemeFile] });
|
||||||
|
|
||||||
|
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
|
{
|
||||||
|
var file = await dialog.ShowAsync(desktop.MainWindow);
|
||||||
|
|
||||||
|
if (file != null && file.Length > 0)
|
||||||
|
{
|
||||||
|
ViewModel.CustomThemePath = file[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,282 +1,247 @@
|
|||||||
<window:StyleableWindow
|
<UserControl
|
||||||
x:Class="Ryujinx.Ava.UI.Windows.AboutWindow"
|
x:Class="Ryujinx.Ava.UI.Windows.AboutWindow"
|
||||||
xmlns="https://github.com/avaloniaui"
|
xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:flex="clr-namespace:Avalonia.Flexbox;assembly=Avalonia.Flexbox"
|
||||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:window="clr-namespace:Ryujinx.Ava.UI.Windows"
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
Width="850"
|
xmlns:viewModel="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
Height="550"
|
Width="550"
|
||||||
MinWidth="500"
|
Height="260"
|
||||||
MinHeight="550"
|
Margin="0,-12,0,0"
|
||||||
d:DesignHeight="350"
|
d:DesignHeight="260"
|
||||||
d:DesignWidth="400"
|
d:DesignWidth="550"
|
||||||
CanResize="False"
|
x:CompileBindings="True"
|
||||||
SizeToContent="Width"
|
x:DataType="viewModel:AboutWindowViewModel"
|
||||||
WindowStartupLocation="CenterOwner"
|
Focusable="True"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d">
|
||||||
Focusable="True">
|
<Design.DataContext>
|
||||||
<Grid
|
<viewModel:AboutWindowViewModel />
|
||||||
Margin="15"
|
</Design.DataContext>
|
||||||
HorizontalAlignment="Stretch"
|
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||||
VerticalAlignment="Stretch">
|
<Grid.ColumnDefinitions>
|
||||||
<Grid.RowDefinitions>
|
<ColumnDefinition Width="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Grid
|
|
||||||
Grid.Row="1"
|
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="20"
|
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Stretch">
|
VerticalAlignment="Stretch">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition />
|
</Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<StackPanel
|
||||||
</Grid.RowDefinitions>
|
Grid.Row="0"
|
||||||
<Grid Grid.Row="0">
|
HorizontalAlignment="Stretch"
|
||||||
<Grid.ColumnDefinitions>
|
VerticalAlignment="Stretch"
|
||||||
<ColumnDefinition />
|
Spacing="10">
|
||||||
<ColumnDefinition />
|
<Grid>
|
||||||
</Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<Grid.RowDefinitions>
|
<ColumnDefinition Width="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<ColumnDefinition Width="*" />
|
||||||
<RowDefinition Height="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
</Grid.ColumnDefinitions>
|
||||||
</Grid.RowDefinitions>
|
<Image
|
||||||
<Image
|
Grid.Column="0"
|
||||||
Grid.Row="0"
|
Height="80"
|
||||||
Grid.RowSpan="3"
|
Source="resm:Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.Ui.Common" />
|
||||||
Grid.Column="0"
|
<flex:FlexPanel
|
||||||
Height="110"
|
Grid.Column="2"
|
||||||
MinWidth="50"
|
HorizontalAlignment="Stretch"
|
||||||
Margin="5,10,20,10"
|
VerticalAlignment="Stretch"
|
||||||
Source="resm:Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.Ui.Common" />
|
Direction="Column"
|
||||||
<TextBlock
|
JustifyContent="SpaceAround"
|
||||||
Grid.Row="0"
|
RowSpacing="2">
|
||||||
Grid.Column="1"
|
<TextBlock
|
||||||
Margin="0,20,0,0"
|
FontSize="28"
|
||||||
FontSize="35"
|
FontWeight="Bold"
|
||||||
Text="Ryujinx"
|
Text="Ryujinx"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Left" />
|
||||||
<TextBlock
|
<TextBlock Text="(REE-YOU-JINX)" TextAlignment="Left" />
|
||||||
Grid.Row="1"
|
</flex:FlexPanel>
|
||||||
Grid.Column="1"
|
</Grid>
|
||||||
Margin="0,0,0,0"
|
<TextBlock
|
||||||
FontSize="16"
|
|
||||||
Text="(REE-YOU-JINX)"
|
|
||||||
TextAlignment="Center" />
|
|
||||||
<Button
|
|
||||||
Grid.Row="2"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="0"
|
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
FontSize="10"
|
||||||
|
LineHeight="12"
|
||||||
|
Text="{Binding Version}"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel
|
||||||
|
Grid.Row="2"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
Spacing="10">
|
||||||
|
<TextBlock
|
||||||
|
Width="200"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
FontSize="10"
|
||||||
|
LineHeight="12"
|
||||||
|
Text="{locale:Locale AboutDisclaimerMessage}"
|
||||||
|
TextAlignment="Center"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
<TextBlock
|
||||||
|
Name="AmiiboLabel"
|
||||||
|
Width="200"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
FontSize="10"
|
||||||
|
LineHeight="12"
|
||||||
|
PointerPressed="AmiiboLabel_OnPointerPressed"
|
||||||
|
Text="{locale:Locale AboutAmiiboDisclaimerMessage}"
|
||||||
|
TextAlignment="Center"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
<StackPanel
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Orientation="Horizontal"
|
||||||
|
Spacing="10">
|
||||||
|
<Button
|
||||||
|
MinWidth="30"
|
||||||
|
MinHeight="30"
|
||||||
|
MaxWidth="30"
|
||||||
|
MaxHeight="30"
|
||||||
|
Padding="8"
|
||||||
|
Background="Transparent"
|
||||||
|
Click="Button_OnClick"
|
||||||
|
CornerRadius="15"
|
||||||
|
Tag="https://www.patreon.com/ryujinx"
|
||||||
|
ToolTip.Tip="{locale:Locale AboutPatreonUrlTooltipMessage}">
|
||||||
|
<Image Source="{Binding PatreonLogo}" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
MinWidth="30"
|
||||||
|
MinHeight="30"
|
||||||
|
MaxWidth="30"
|
||||||
|
MaxHeight="30"
|
||||||
|
Padding="8"
|
||||||
|
Background="Transparent"
|
||||||
|
Click="Button_OnClick"
|
||||||
|
CornerRadius="15"
|
||||||
|
Tag="https://github.com/Ryujinx/Ryujinx"
|
||||||
|
ToolTip.Tip="{locale:Locale AboutGithubUrlTooltipMessage}">
|
||||||
|
<Image Source="{Binding GithubLogo}" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
MinWidth="30"
|
||||||
|
MinHeight="30"
|
||||||
|
MaxWidth="30"
|
||||||
|
MaxHeight="30"
|
||||||
|
Padding="8"
|
||||||
|
Background="Transparent"
|
||||||
|
Click="Button_OnClick"
|
||||||
|
CornerRadius="15"
|
||||||
|
Tag="https://discordapp.com/invite/N2FmfVc"
|
||||||
|
ToolTip.Tip="{locale:Locale AboutDiscordUrlTooltipMessage}">
|
||||||
|
<Image Source="{Binding DiscordLogo}" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
MinWidth="30"
|
||||||
|
MinHeight="30"
|
||||||
|
MaxWidth="30"
|
||||||
|
MaxHeight="30"
|
||||||
|
Padding="8"
|
||||||
|
Background="Transparent"
|
||||||
|
Click="Button_OnClick"
|
||||||
|
CornerRadius="15"
|
||||||
|
Tag="https://twitter.com/RyujinxEmu"
|
||||||
|
ToolTip.Tip="{locale:Locale AboutTwitterUrlTooltipMessage}">
|
||||||
|
<Image Source="{Binding TwitterLogo}" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
MinWidth="30"
|
||||||
|
MinHeight="30"
|
||||||
|
MaxWidth="30"
|
||||||
|
MaxHeight="30"
|
||||||
|
Padding="8"
|
||||||
|
Background="Transparent"
|
||||||
|
Click="Button_OnClick"
|
||||||
|
CornerRadius="15"
|
||||||
|
Tag="https://www.ryujinx.org"
|
||||||
|
ToolTip.Tip="{locale:Locale AboutUrlTooltipMessage}">
|
||||||
|
<ui:SymbolIcon Foreground="{DynamicResource ThemeForegroundColor}" Symbol="Link" />
|
||||||
|
</Button>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
<Border
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="1"
|
||||||
|
Margin="20,0"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
BorderBrush="{DynamicResource ThemeControlBorderColor}"
|
||||||
|
BorderThickness="1,0,0,0" />
|
||||||
|
<Grid
|
||||||
|
Grid.Column="2"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<StackPanel
|
||||||
|
Grid.Row="0"
|
||||||
|
Margin="0,10,0,0"
|
||||||
|
Spacing="2">
|
||||||
|
<TextBlock
|
||||||
|
FontSize="15"
|
||||||
|
FontWeight="Bold"
|
||||||
|
Text="{locale:Locale AboutRyujinxAboutTitle}" />
|
||||||
|
<TextBlock
|
||||||
|
FontSize="10"
|
||||||
|
Text="{locale:Locale AboutRyujinxAboutContent}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel
|
||||||
|
Grid.Row="1"
|
||||||
|
Margin="0,10,0,0"
|
||||||
|
Spacing="2">
|
||||||
|
<TextBlock
|
||||||
|
FontSize="15"
|
||||||
|
FontWeight="Bold"
|
||||||
|
Text="{locale:Locale AboutRyujinxMaintainersTitle}" />
|
||||||
|
<TextBlock
|
||||||
|
FontSize="10"
|
||||||
|
Text="{Binding Developers}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
<Button
|
||||||
|
Padding="5"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
Click="Button_OnClick"
|
Click="Button_OnClick"
|
||||||
Tag="https://www.ryujinx.org/">
|
Tag="https://github.com/Ryujinx/Ryujinx/graphs/contributors?type=a">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="www.ryujinx.org"
|
FontSize="10"
|
||||||
TextAlignment="Center"
|
Text="{locale:Locale AboutRyujinxContributorsButtonHeader}"
|
||||||
TextDecorations="Underline"
|
TextAlignment="Right"
|
||||||
ToolTip.Tip="{locale:Locale AboutUrlTooltipMessage}" />
|
ToolTip.Tip="{locale:Locale AboutRyujinxMaintainersContentTooltipMessage}" />
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</StackPanel>
|
||||||
<TextBlock
|
<StackPanel
|
||||||
Grid.Row="1"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{Binding Version}"
|
|
||||||
TextAlignment="Center" />
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="2"
|
|
||||||
Margin="20"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
MaxLines="2"
|
|
||||||
Text="{locale:Locale AboutDisclaimerMessage}"
|
|
||||||
TextAlignment="Center" />
|
|
||||||
<TextBlock
|
|
||||||
Name="AmiiboLabel"
|
|
||||||
Grid.Row="3"
|
|
||||||
Margin="20"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
MaxLines="2"
|
|
||||||
PointerPressed="AmiiboLabel_OnPointerPressed"
|
|
||||||
Text="{locale:Locale AboutAmiiboDisclaimerMessage}"
|
|
||||||
TextAlignment="Center" />
|
|
||||||
<StackPanel
|
|
||||||
Grid.Row="4"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
Orientation="Horizontal"
|
|
||||||
Spacing="10">
|
|
||||||
<StackPanel Orientation="Vertical" ToolTip.Tip="{locale:Locale AboutPatreonUrlTooltipMessage}">
|
|
||||||
<Button
|
|
||||||
Height="65"
|
|
||||||
Background="Transparent"
|
|
||||||
Click="Button_OnClick"
|
|
||||||
Tag="https://www.patreon.com/ryujinx">
|
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<Image Source="resm:Ryujinx.Ui.Common.Resources.Logo_Patreon.png?assembly=Ryujinx.Ui.Common" />
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="1"
|
|
||||||
Margin="0,5,0,0"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
Text="Patreon" />
|
|
||||||
</Grid>
|
|
||||||
</Button>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Orientation="Vertical" ToolTip.Tip="{locale:Locale AboutGithubUrlTooltipMessage}">
|
|
||||||
<Button
|
|
||||||
Height="65"
|
|
||||||
Background="Transparent"
|
|
||||||
Click="Button_OnClick"
|
|
||||||
Tag="https://github.com/Ryujinx/Ryujinx">
|
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<Image Source="resm:Ryujinx.Ui.Common.Resources.Logo_GitHub.png?assembly=Ryujinx.Ui.Common" />
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="1"
|
|
||||||
Margin="0,5,0,0"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
Text="GitHub" />
|
|
||||||
</Grid>
|
|
||||||
</Button>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Orientation="Vertical" ToolTip.Tip="{locale:Locale AboutDiscordUrlTooltipMessage}">
|
|
||||||
<Button
|
|
||||||
Height="65"
|
|
||||||
Background="Transparent"
|
|
||||||
Click="Button_OnClick"
|
|
||||||
Tag="https://discordapp.com/invite/N2FmfVc">
|
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<Image Source="resm:Ryujinx.Ui.Common.Resources.Logo_Discord.png?assembly=Ryujinx.Ui.Common" />
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="1"
|
|
||||||
Margin="0,5,0,0"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
Text="Discord" />
|
|
||||||
</Grid>
|
|
||||||
</Button>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Orientation="Vertical" ToolTip.Tip="{locale:Locale AboutTwitterUrlTooltipMessage}">
|
|
||||||
<Button
|
|
||||||
Height="65"
|
|
||||||
Background="Transparent"
|
|
||||||
Click="Button_OnClick"
|
|
||||||
Tag="https://twitter.com/RyujinxEmu">
|
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<Image Source="resm:Ryujinx.Ui.Common.Resources.Logo_Twitter.png?assembly=Ryujinx.Ui.Common" />
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="1"
|
|
||||||
Margin="0,5,0,0"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
Text="Twitter" />
|
|
||||||
</Grid>
|
|
||||||
</Button>
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
<Border
|
|
||||||
Grid.Row="1"
|
|
||||||
Grid.Column="1"
|
|
||||||
Width="2"
|
|
||||||
Margin="5"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
BorderBrush="White"
|
|
||||||
BorderThickness="1,0,0,0">
|
|
||||||
<Separator Width="0" />
|
|
||||||
</Border>
|
|
||||||
<Grid
|
|
||||||
Grid.Row="1"
|
|
||||||
Grid.Column="2"
|
|
||||||
Margin="20"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<TextBlock
|
|
||||||
FontWeight="Bold"
|
|
||||||
Text="{locale:Locale AboutRyujinxAboutTitle}"
|
|
||||||
TextDecorations="Underline" />
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="1"
|
|
||||||
Margin="20,5,5,5"
|
|
||||||
LineHeight="20"
|
|
||||||
Text="{locale:Locale AboutRyujinxAboutContent}" />
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Margin="0,10,0,0"
|
Margin="0,10,0,0"
|
||||||
FontWeight="Bold"
|
Spacing="2">
|
||||||
Text="{locale:Locale AboutRyujinxMaintainersTitle}"
|
<TextBlock
|
||||||
TextDecorations="Underline" />
|
FontSize="15"
|
||||||
<TextBlock
|
FontWeight="Bold"
|
||||||
Grid.Row="3"
|
Text="{locale:Locale AboutRyujinxSupprtersTitle}" />
|
||||||
Margin="20,5,5,5"
|
<ScrollViewer
|
||||||
LineHeight="20"
|
Height="70"
|
||||||
Text="{Binding Developers}" />
|
HorizontalScrollBarVisibility="Disabled"
|
||||||
<Button
|
VerticalScrollBarVisibility="Visible">
|
||||||
Grid.Row="4"
|
<TextBlock
|
||||||
HorizontalAlignment="Right"
|
Name="SupportersTextBlock"
|
||||||
Background="Transparent"
|
VerticalAlignment="Top"
|
||||||
Click="Button_OnClick"
|
FontSize="10"
|
||||||
Tag="https://github.com/Ryujinx/Ryujinx/graphs/contributors?type=a">
|
Text="{Binding Supporters}"
|
||||||
<TextBlock
|
TextWrapping="Wrap" />
|
||||||
Text="{locale:Locale AboutRyujinxContributorsButtonHeader}"
|
</ScrollViewer>
|
||||||
TextAlignment="Right"
|
</StackPanel>
|
||||||
TextDecorations="Underline"
|
</Grid>
|
||||||
ToolTip.Tip="{locale:Locale AboutRyujinxMaintainersContentTooltipMessage}" />
|
</Grid>
|
||||||
</Button>
|
</UserControl>
|
||||||
<TextBlock
|
|
||||||
Grid.Row="5"
|
|
||||||
Margin="0,0,0,0"
|
|
||||||
FontWeight="Bold"
|
|
||||||
Text="{locale:Locale AboutRyujinxSupprtersTitle}"
|
|
||||||
TextDecorations="Underline" />
|
|
||||||
<Border
|
|
||||||
Grid.Row="6"
|
|
||||||
Width="460"
|
|
||||||
Height="200"
|
|
||||||
Margin="20,5"
|
|
||||||
Padding="5"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
BorderBrush="White"
|
|
||||||
BorderThickness="1">
|
|
||||||
<TextBlock
|
|
||||||
Name="SupportersTextBlock"
|
|
||||||
VerticalAlignment="Top"
|
|
||||||
Text="{Binding Supporters}"
|
|
||||||
TextWrapping="Wrap" />
|
|
||||||
</Border>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</window:StyleableWindow>
|
|
@@ -1,38 +1,47 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Styling;
|
||||||
|
using FluentAvalonia.UI.Controls;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Common.Utilities;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
using Ryujinx.Ui.Common.Helper;
|
using Ryujinx.Ui.Common.Helper;
|
||||||
using System.Net.Http;
|
|
||||||
using System.Net.NetworkInformation;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Button = Avalonia.Controls.Button;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Windows
|
namespace Ryujinx.Ava.UI.Windows
|
||||||
{
|
{
|
||||||
public partial class AboutWindow : StyleableWindow
|
public partial class AboutWindow : UserControl
|
||||||
{
|
{
|
||||||
public AboutWindow()
|
public AboutWindow()
|
||||||
{
|
{
|
||||||
if (Program.PreviewerDetached)
|
DataContext = new AboutWindowViewModel();
|
||||||
{
|
|
||||||
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance[LocaleKeys.MenuBarHelpAbout];
|
|
||||||
}
|
|
||||||
|
|
||||||
Version = Program.Version;
|
|
||||||
|
|
||||||
DataContext = this;
|
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
_ = DownloadPatronsJson();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Supporters { get; set; }
|
public static async Task Show()
|
||||||
public string Version { get; set; }
|
{
|
||||||
|
ContentDialog contentDialog = new()
|
||||||
|
{
|
||||||
|
PrimaryButtonText = "",
|
||||||
|
SecondaryButtonText = "",
|
||||||
|
CloseButtonText = LocaleManager.Instance[LocaleKeys.UserProfilesClose],
|
||||||
|
Content = new AboutWindow()
|
||||||
|
};
|
||||||
|
|
||||||
public string Developers => string.Format(LocaleManager.Instance[LocaleKeys.AboutPageDeveloperListMore], "gdkchan, Ac_K, Thog, rip in peri peri, LDj3SNuD, emmaus, Thealexbarney, Xpl0itR, GoffyDude, »jD«");
|
Style closeButton = new(x => x.Name("CloseButton"));
|
||||||
|
closeButton.Setters.Add(new Setter(WidthProperty, 80d));
|
||||||
|
|
||||||
|
Style closeButtonParent = new(x => x.Name("CommandSpace"));
|
||||||
|
closeButtonParent.Setters.Add(new Setter(HorizontalAlignmentProperty, Avalonia.Layout.HorizontalAlignment.Right));
|
||||||
|
|
||||||
|
contentDialog.Styles.Add(closeButton);
|
||||||
|
contentDialog.Styles.Add(closeButtonParent);
|
||||||
|
|
||||||
|
await ContentDialogHelper.ShowAsync(contentDialog);
|
||||||
|
}
|
||||||
|
|
||||||
private void Button_OnClick(object sender, RoutedEventArgs e)
|
private void Button_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
@@ -42,31 +51,6 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DownloadPatronsJson()
|
|
||||||
{
|
|
||||||
if (!NetworkInterface.GetIsNetworkAvailable())
|
|
||||||
{
|
|
||||||
Supporters = LocaleManager.Instance[LocaleKeys.ConnectionError];
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpClient httpClient = new();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string patreonJsonString = await httpClient.GetStringAsync("https://patreon.ryujinx.org/");
|
|
||||||
|
|
||||||
Supporters = string.Join(", ", JsonHelper.Deserialize<string[]>(patreonJsonString));
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
Supporters = LocaleManager.Instance[LocaleKeys.ApiError];
|
|
||||||
}
|
|
||||||
|
|
||||||
await Dispatcher.UIThread.InvokeAsync(() => SupportersTextBlock.Text = Supporters);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AmiiboLabel_OnPointerPressed(object sender, PointerPressedEventArgs e)
|
private void AmiiboLabel_OnPointerPressed(object sender, PointerPressedEventArgs e)
|
||||||
{
|
{
|
||||||
if (sender is TextBlock)
|
if (sender is TextBlock)
|
||||||
|
@@ -17,9 +17,9 @@
|
|||||||
<Design.DataContext>
|
<Design.DataContext>
|
||||||
<viewModels:AvatarProfileViewModel />
|
<viewModels:AvatarProfileViewModel />
|
||||||
</Design.DataContext>
|
</Design.DataContext>
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
|
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid Margin="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
<Grid Margin="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
@@ -2,15 +2,16 @@
|
|||||||
x:Class="Ryujinx.Ava.UI.Windows.MainWindow"
|
x:Class="Ryujinx.Ava.UI.Windows.MainWindow"
|
||||||
xmlns="https://github.com/avaloniaui"
|
xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
|
||||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
|
||||||
xmlns:window="clr-namespace:Ryujinx.Ava.UI.Windows"
|
xmlns:window="clr-namespace:Ryujinx.Ava.UI.Windows"
|
||||||
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
||||||
Title="Ryujinx"
|
xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls"
|
||||||
|
xmlns:main="clr-namespace:Ryujinx.Ava.UI.Views.Main"
|
||||||
|
Cursor="{Binding Cursor}"
|
||||||
|
Title="{Binding Title}"
|
||||||
|
WindowState="{Binding WindowState}"
|
||||||
Width="1280"
|
Width="1280"
|
||||||
Height="777"
|
Height="777"
|
||||||
MinWidth="1092"
|
MinWidth="1092"
|
||||||
@@ -66,206 +67,8 @@
|
|||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
IsVisible="{Binding ShowMenuAndStatusBar}"
|
IsVisible="{Binding ShowMenuAndStatusBar}"
|
||||||
Orientation="Vertical">
|
Orientation="Vertical">
|
||||||
<DockPanel HorizontalAlignment="Stretch">
|
<main:MainMenuBarView
|
||||||
<Menu
|
Name="MenuBarView" />
|
||||||
Name="Menu"
|
|
||||||
Height="35"
|
|
||||||
Margin="0"
|
|
||||||
HorizontalAlignment="Left">
|
|
||||||
<Menu.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<DockPanel Margin="0" HorizontalAlignment="Stretch" />
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</Menu.ItemsPanel>
|
|
||||||
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarFile}">
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding OpenFile}"
|
|
||||||
Header="{locale:Locale MenuBarFileOpenFromFile}"
|
|
||||||
IsEnabled="{Binding EnableNonGameRunningControls}"
|
|
||||||
ToolTip.Tip="{locale:Locale LoadApplicationFileTooltip}" />
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding OpenFolder}"
|
|
||||||
Header="{locale:Locale MenuBarFileOpenUnpacked}"
|
|
||||||
IsEnabled="{Binding EnableNonGameRunningControls}"
|
|
||||||
ToolTip.Tip="{locale:Locale LoadApplicationFolderTooltip}" />
|
|
||||||
<MenuItem Header="{locale:Locale MenuBarFileOpenApplet}" IsEnabled="{Binding IsAppletMenuActive}">
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding OpenMiiApplet}"
|
|
||||||
Header="Mii Edit Applet"
|
|
||||||
ToolTip.Tip="{locale:Locale MenuBarFileOpenAppletOpenMiiAppletToolTip}" />
|
|
||||||
</MenuItem>
|
|
||||||
<Separator />
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding OpenRyujinxFolder}"
|
|
||||||
Header="{locale:Locale MenuBarFileOpenEmuFolder}"
|
|
||||||
ToolTip.Tip="{locale:Locale OpenRyujinxFolderTooltip}" />
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding OpenLogsFolder}"
|
|
||||||
Header="{locale:Locale MenuBarFileOpenLogsFolder}"
|
|
||||||
ToolTip.Tip="{locale:Locale OpenRyujinxLogsTooltip}" />
|
|
||||||
<Separator />
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding CloseWindow}"
|
|
||||||
Header="{locale:Locale MenuBarFileExit}"
|
|
||||||
ToolTip.Tip="{locale:Locale ExitTooltip}" />
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarOptions}">
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding ToggleFullscreen}"
|
|
||||||
Header="{locale:Locale MenuBarOptionsToggleFullscreen}"
|
|
||||||
InputGesture="F11" />
|
|
||||||
<MenuItem>
|
|
||||||
<MenuItem.Icon>
|
|
||||||
<CheckBox IsChecked="{Binding StartGamesInFullscreen, Mode=TwoWay}"
|
|
||||||
MinWidth="250">
|
|
||||||
<TextBlock Text="{locale:Locale MenuBarOptionsStartGamesInFullscreen}"/>
|
|
||||||
</CheckBox>
|
|
||||||
</MenuItem.Icon>
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem IsVisible="{Binding ShowConsoleVisible}">
|
|
||||||
<MenuItem.Icon>
|
|
||||||
<CheckBox IsChecked="{Binding ShowConsole, Mode=TwoWay}"
|
|
||||||
MinWidth="250">
|
|
||||||
<TextBlock Text="{locale:Locale MenuBarOptionsShowConsole}"/>
|
|
||||||
</CheckBox>
|
|
||||||
</MenuItem.Icon>
|
|
||||||
</MenuItem>
|
|
||||||
<Separator />
|
|
||||||
<MenuItem Header="{locale:Locale MenuBarOptionsChangeLanguage}">
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding ChangeLanguage}"
|
|
||||||
CommandParameter="de_DE"
|
|
||||||
Header="Deutsch" />
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding ChangeLanguage}"
|
|
||||||
CommandParameter="en_US"
|
|
||||||
Header="English (US)" />
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding ChangeLanguage}"
|
|
||||||
CommandParameter="es_ES"
|
|
||||||
Header="Español (ES)" />
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding ChangeLanguage}"
|
|
||||||
CommandParameter="fr_FR"
|
|
||||||
Header="Français" />
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding ChangeLanguage}"
|
|
||||||
CommandParameter="it_IT"
|
|
||||||
Header="Italiano" />
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding ChangeLanguage}"
|
|
||||||
CommandParameter="pt_BR"
|
|
||||||
Header="Português (BR)" />
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding ChangeLanguage}"
|
|
||||||
CommandParameter="tr_TR"
|
|
||||||
Header="Türkçe" />
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding ChangeLanguage}"
|
|
||||||
CommandParameter="el_GR"
|
|
||||||
Header="Ελληνικά" />
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding ChangeLanguage}"
|
|
||||||
CommandParameter="pl_PL"
|
|
||||||
Header="Polski" />
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding ChangeLanguage}"
|
|
||||||
CommandParameter="ru_RU"
|
|
||||||
Header="Русский" />
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding ChangeLanguage}"
|
|
||||||
CommandParameter="zh_CN"
|
|
||||||
Header="简体中文" />
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding ChangeLanguage}"
|
|
||||||
CommandParameter="zh_TW"
|
|
||||||
Header="繁體中文" />
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding ChangeLanguage}"
|
|
||||||
CommandParameter="ja_JP"
|
|
||||||
Header="日本語" />
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding ChangeLanguage}"
|
|
||||||
CommandParameter="ko_KR"
|
|
||||||
Header="한국어" />
|
|
||||||
</MenuItem>
|
|
||||||
<Separator />
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding OpenSettings}"
|
|
||||||
Header="{locale:Locale MenuBarOptionsSettings}"
|
|
||||||
ToolTip.Tip="{locale:Locale OpenSettingsTooltip}" />
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding ManageProfiles}"
|
|
||||||
Header="{locale:Locale MenuBarOptionsManageUserProfiles}"
|
|
||||||
IsEnabled="{Binding EnableNonGameRunningControls}"
|
|
||||||
ToolTip.Tip="{locale:Locale OpenProfileManagerTooltip}" />
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem
|
|
||||||
Name="ActionsMenuItem"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Header="{locale:Locale MenuBarActions}"
|
|
||||||
IsEnabled="{Binding IsGameRunning}">
|
|
||||||
<MenuItem
|
|
||||||
Click="PauseEmulation_Click"
|
|
||||||
Header="{locale:Locale MenuBarOptionsPauseEmulation}"
|
|
||||||
InputGesture="{Binding PauseKey}"
|
|
||||||
IsEnabled="{Binding !IsPaused}"
|
|
||||||
IsVisible="{Binding !IsPaused}" />
|
|
||||||
<MenuItem
|
|
||||||
Click="ResumeEmulation_Click"
|
|
||||||
Header="{locale:Locale MenuBarOptionsResumeEmulation}"
|
|
||||||
InputGesture="{Binding PauseKey}"
|
|
||||||
IsEnabled="{Binding IsPaused}"
|
|
||||||
IsVisible="{Binding IsPaused}" />
|
|
||||||
<MenuItem
|
|
||||||
Click="StopEmulation_Click"
|
|
||||||
Header="{locale:Locale MenuBarOptionsStopEmulation}"
|
|
||||||
InputGesture="Escape"
|
|
||||||
IsEnabled="{Binding IsGameRunning}"
|
|
||||||
ToolTip.Tip="{locale:Locale StopEmulationTooltip}" />
|
|
||||||
<MenuItem Command="{ReflectionBinding SimulateWakeUpMessage}" Header="{locale:Locale MenuBarOptionsSimulateWakeUpMessage}" />
|
|
||||||
<Separator />
|
|
||||||
<MenuItem
|
|
||||||
Name="ScanAmiiboMenuItem"
|
|
||||||
AttachedToVisualTree="ScanAmiiboMenuItem_AttachedToVisualTree"
|
|
||||||
Command="{ReflectionBinding OpenAmiiboWindow}"
|
|
||||||
Header="{locale:Locale MenuBarActionsScanAmiibo}"
|
|
||||||
IsEnabled="{Binding IsAmiiboRequested}" />
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding TakeScreenshot}"
|
|
||||||
Header="{locale:Locale MenuBarFileToolsTakeScreenshot}"
|
|
||||||
InputGesture="{Binding ScreenshotKey}"
|
|
||||||
IsEnabled="{Binding IsGameRunning}" />
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding HideUi}"
|
|
||||||
Header="{locale:Locale MenuBarFileToolsHideUi}"
|
|
||||||
InputGesture="{Binding ShowUiKey}"
|
|
||||||
IsEnabled="{Binding IsGameRunning}" />
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding OpenCheatManagerForCurrentApp}"
|
|
||||||
Header="{locale:Locale GameListContextMenuManageCheat}"
|
|
||||||
IsEnabled="{Binding IsGameRunning}" />
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarTools}">
|
|
||||||
<MenuItem Header="{locale:Locale MenuBarToolsInstallFirmware}" IsEnabled="{Binding EnableNonGameRunningControls}">
|
|
||||||
<MenuItem Command="{ReflectionBinding InstallFirmwareFromFile}" Header="{locale:Locale MenuBarFileToolsInstallFirmwareFromFile}" />
|
|
||||||
<MenuItem Command="{ReflectionBinding InstallFirmwareFromFolder}" Header="{locale:Locale MenuBarFileToolsInstallFirmwareFromDirectory}" />
|
|
||||||
</MenuItem>
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarHelp}">
|
|
||||||
<MenuItem
|
|
||||||
Name="UpdateMenuItem"
|
|
||||||
Command="{ReflectionBinding CheckForUpdates}"
|
|
||||||
Header="{locale:Locale MenuBarHelpCheckForUpdates}"
|
|
||||||
ToolTip.Tip="{locale:Locale CheckUpdatesTooltip}" />
|
|
||||||
<Separator />
|
|
||||||
<MenuItem
|
|
||||||
Command="{ReflectionBinding OpenAboutWindow}"
|
|
||||||
Header="{locale:Locale MenuBarHelpAbout}"
|
|
||||||
ToolTip.Tip="{locale:Locale OpenAboutTooltip}" />
|
|
||||||
</MenuItem>
|
|
||||||
</Menu>
|
|
||||||
</DockPanel>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<ContentControl
|
<ContentControl
|
||||||
Name="MainContent"
|
Name="MainContent"
|
||||||
@@ -277,170 +80,14 @@
|
|||||||
BorderThickness="0,0,0,0"
|
BorderThickness="0,0,0,0"
|
||||||
DockPanel.Dock="Top"
|
DockPanel.Dock="Top"
|
||||||
IsVisible="{Binding ShowContent}">
|
IsVisible="{Binding ShowContent}">
|
||||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Name="GameLibrary">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<DockPanel
|
<main:MainViewControls
|
||||||
Grid.Row="0"
|
Name="ViewControls"
|
||||||
Margin="0,0,0,5"
|
Grid.Row="0"/>
|
||||||
HorizontalAlignment="Stretch">
|
|
||||||
<Button
|
|
||||||
Width="40"
|
|
||||||
MinWidth="40"
|
|
||||||
Margin="5,2,0,2"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
Command="{ReflectionBinding SetListMode}"
|
|
||||||
IsEnabled="{Binding IsGrid}">
|
|
||||||
<ui:FontIcon
|
|
||||||
Margin="0"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
FontFamily="avares://FluentAvalonia/Fonts#Symbols"
|
|
||||||
Glyph="{helpers:GlyphValueConverter List}" />
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
Width="40"
|
|
||||||
MinWidth="40"
|
|
||||||
Margin="5,2,5,2"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
Command="{ReflectionBinding SetGridMode}"
|
|
||||||
IsEnabled="{Binding IsList}">
|
|
||||||
<ui:FontIcon
|
|
||||||
Margin="0"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
FontFamily="avares://FluentAvalonia/Fonts#Symbols"
|
|
||||||
Glyph="{helpers:GlyphValueConverter Grid}" />
|
|
||||||
</Button>
|
|
||||||
<TextBlock
|
|
||||||
Margin="10,0"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{locale:Locale IconSize}"
|
|
||||||
ToolTip.Tip="{locale:Locale IconSizeTooltip}" />
|
|
||||||
<Slider
|
|
||||||
Width="150"
|
|
||||||
Height="35"
|
|
||||||
Margin="5,-10,5,0"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
IsSnapToTickEnabled="True"
|
|
||||||
Maximum="4"
|
|
||||||
Minimum="1"
|
|
||||||
TickFrequency="1"
|
|
||||||
ToolTip.Tip="{locale:Locale IconSizeTooltip}"
|
|
||||||
Value="{Binding GridSizeScale}" />
|
|
||||||
<CheckBox
|
|
||||||
Margin="0"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
IsChecked="{Binding ShowNames, Mode=TwoWay}"
|
|
||||||
IsVisible="{Binding IsGrid}">
|
|
||||||
<TextBlock Margin="5,3,0,0" Text="{locale:Locale CommonShowNames}" />
|
|
||||||
</CheckBox>
|
|
||||||
<TextBox
|
|
||||||
Name="SearchBox"
|
|
||||||
MinWidth="200"
|
|
||||||
Margin="5,0,5,0"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
DockPanel.Dock="Right"
|
|
||||||
KeyUp="SearchBox_OnKeyUp"
|
|
||||||
Text="{Binding SearchText}"
|
|
||||||
Watermark="{locale:Locale MenuSearch}" />
|
|
||||||
<ui:DropDownButton
|
|
||||||
Width="150"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Content="{Binding SortName}"
|
|
||||||
DockPanel.Dock="Right">
|
|
||||||
<ui:DropDownButton.Flyout>
|
|
||||||
<Flyout Placement="Bottom">
|
|
||||||
<StackPanel
|
|
||||||
Margin="0"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Orientation="Vertical">
|
|
||||||
<StackPanel>
|
|
||||||
<RadioButton
|
|
||||||
Checked="Sort_Checked"
|
|
||||||
Content="{locale:Locale CommonFavorite}"
|
|
||||||
GroupName="Sort"
|
|
||||||
IsChecked="{Binding IsSortedByFavorite, Mode=OneTime}"
|
|
||||||
Tag="Favorite" />
|
|
||||||
<RadioButton
|
|
||||||
Checked="Sort_Checked"
|
|
||||||
Content="{locale:Locale GameListHeaderApplication}"
|
|
||||||
GroupName="Sort"
|
|
||||||
IsChecked="{Binding IsSortedByTitle, Mode=OneTime}"
|
|
||||||
Tag="Title" />
|
|
||||||
<RadioButton
|
|
||||||
Checked="Sort_Checked"
|
|
||||||
Content="{locale:Locale GameListHeaderDeveloper}"
|
|
||||||
GroupName="Sort"
|
|
||||||
IsChecked="{Binding IsSortedByDeveloper, Mode=OneTime}"
|
|
||||||
Tag="Developer" />
|
|
||||||
<RadioButton
|
|
||||||
Checked="Sort_Checked"
|
|
||||||
Content="{locale:Locale GameListHeaderTimePlayed}"
|
|
||||||
GroupName="Sort"
|
|
||||||
IsChecked="{Binding IsSortedByTimePlayed, Mode=OneTime}"
|
|
||||||
Tag="TotalTimePlayed" />
|
|
||||||
<RadioButton
|
|
||||||
Checked="Sort_Checked"
|
|
||||||
Content="{locale:Locale GameListHeaderLastPlayed}"
|
|
||||||
GroupName="Sort"
|
|
||||||
IsChecked="{Binding IsSortedByLastPlayed, Mode=OneTime}"
|
|
||||||
Tag="LastPlayed" />
|
|
||||||
<RadioButton
|
|
||||||
Checked="Sort_Checked"
|
|
||||||
Content="{locale:Locale GameListHeaderFileExtension}"
|
|
||||||
GroupName="Sort"
|
|
||||||
IsChecked="{Binding IsSortedByType, Mode=OneTime}"
|
|
||||||
Tag="FileType" />
|
|
||||||
<RadioButton
|
|
||||||
Checked="Sort_Checked"
|
|
||||||
Content="{locale:Locale GameListHeaderFileSize}"
|
|
||||||
GroupName="Sort"
|
|
||||||
IsChecked="{Binding IsSortedBySize, Mode=OneTime}"
|
|
||||||
Tag="FileSize" />
|
|
||||||
<RadioButton
|
|
||||||
Checked="Sort_Checked"
|
|
||||||
Content="{locale:Locale GameListHeaderPath}"
|
|
||||||
GroupName="Sort"
|
|
||||||
IsChecked="{Binding IsSortedByPath, Mode=OneTime}"
|
|
||||||
Tag="Path" />
|
|
||||||
</StackPanel>
|
|
||||||
<Border
|
|
||||||
Width="60"
|
|
||||||
Height="2"
|
|
||||||
Margin="5"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
BorderBrush="White"
|
|
||||||
BorderThickness="0,1,0,0">
|
|
||||||
<Separator Height="0" HorizontalAlignment="Stretch" />
|
|
||||||
</Border>
|
|
||||||
<RadioButton
|
|
||||||
Checked="Order_Checked"
|
|
||||||
Content="{locale:Locale OrderAscending}"
|
|
||||||
GroupName="Order"
|
|
||||||
IsChecked="{Binding IsAscending, Mode=OneTime}"
|
|
||||||
Tag="Ascending" />
|
|
||||||
<RadioButton
|
|
||||||
Checked="Order_Checked"
|
|
||||||
Content="{locale:Locale OrderDescending}"
|
|
||||||
GroupName="Order"
|
|
||||||
IsChecked="{Binding !IsAscending, Mode=OneTime}"
|
|
||||||
Tag="Descending" />
|
|
||||||
</StackPanel>
|
|
||||||
</Flyout>
|
|
||||||
</ui:DropDownButton.Flyout>
|
|
||||||
</ui:DropDownButton>
|
|
||||||
<TextBlock
|
|
||||||
Margin="10,0"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
DockPanel.Dock="Right"
|
|
||||||
Text="{locale:Locale CommonSort}" />
|
|
||||||
</DockPanel>
|
|
||||||
<controls:GameListView
|
<controls:GameListView
|
||||||
x:Name="GameList"
|
x:Name="GameList"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
@@ -512,7 +159,8 @@
|
|||||||
IsVisible="{Binding ShowLoadProgress}"
|
IsVisible="{Binding ShowLoadProgress}"
|
||||||
Text="{Binding LoadHeading}"
|
Text="{Binding LoadHeading}"
|
||||||
TextAlignment="Left"
|
TextAlignment="Left"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap"
|
||||||
|
MaxWidth="500" />
|
||||||
<Border
|
<Border
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Margin="10"
|
Margin="10"
|
||||||
@@ -529,7 +177,6 @@
|
|||||||
Margin="0"
|
Margin="0"
|
||||||
Padding="0"
|
Padding="0"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Background="{Binding ProgressBarBackgroundColor}"
|
|
||||||
ClipToBounds="True"
|
ClipToBounds="True"
|
||||||
CornerRadius="5"
|
CornerRadius="5"
|
||||||
Foreground="{Binding ProgressBarForegroundColor}"
|
Foreground="{Binding ProgressBarForegroundColor}"
|
||||||
@@ -545,226 +192,14 @@
|
|||||||
FontSize="18"
|
FontSize="18"
|
||||||
IsVisible="{Binding ShowLoadProgress}"
|
IsVisible="{Binding ShowLoadProgress}"
|
||||||
Text="{Binding CacheLoadStatus}"
|
Text="{Binding CacheLoadStatus}"
|
||||||
TextAlignment="Left" />
|
TextAlignment="Left"
|
||||||
|
MaxWidth="500" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid
|
<main:MainStatusBarView
|
||||||
Name="StatusBar"
|
Name="StatusBarView"
|
||||||
Grid.Row="2"
|
Grid.Row="2" />
|
||||||
Margin="0"
|
|
||||||
MinHeight="22"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Bottom"
|
|
||||||
Background="{DynamicResource ThemeContentBackgroundColor}"
|
|
||||||
DockPanel.Dock="Bottom"
|
|
||||||
IsVisible="{Binding ShowMenuAndStatusBar}">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<StackPanel
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="5"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
IsVisible="{Binding EnableNonGameRunningControls}">
|
|
||||||
<Grid Margin="0">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Button
|
|
||||||
Width="25"
|
|
||||||
Height="25"
|
|
||||||
MinWidth="0"
|
|
||||||
Margin="0,0,5,0"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Background="Transparent"
|
|
||||||
Command="{ReflectionBinding LoadApplications}">
|
|
||||||
<ui:SymbolIcon
|
|
||||||
Width="50"
|
|
||||||
Height="100"
|
|
||||||
Symbol="Refresh" />
|
|
||||||
</Button>
|
|
||||||
<TextBlock
|
|
||||||
Name="LoadStatus"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="0,0,5,0"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
IsVisible="{Binding EnableNonGameRunningControls}"
|
|
||||||
Text="{locale:Locale StatusBarGamesLoaded}" />
|
|
||||||
<ProgressBar
|
|
||||||
Name="LoadProgressBar"
|
|
||||||
Grid.Column="2"
|
|
||||||
Height="6"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Foreground="{DynamicResource HighlightColor}"
|
|
||||||
IsVisible="{Binding EnableNonGameRunningControls}"
|
|
||||||
Maximum="{Binding StatusBarProgressMaximum}"
|
|
||||||
Value="{Binding StatusBarProgressValue}" />
|
|
||||||
</Grid>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="0,2"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
IsVisible="{Binding IsGameRunning}"
|
|
||||||
Orientation="Horizontal">
|
|
||||||
<TextBlock
|
|
||||||
Name="VsyncStatus"
|
|
||||||
Margin="5,0,5,0"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Foreground="{Binding VsyncColor}"
|
|
||||||
IsVisible="{Binding !ShowLoadProgress}"
|
|
||||||
PointerReleased="VsyncStatus_PointerReleased"
|
|
||||||
Text="VSync"
|
|
||||||
TextAlignment="Left" />
|
|
||||||
<Border
|
|
||||||
Width="2"
|
|
||||||
Height="12"
|
|
||||||
Margin="0"
|
|
||||||
BorderBrush="Gray"
|
|
||||||
BorderThickness="1"
|
|
||||||
IsVisible="{Binding !ShowLoadProgress}" />
|
|
||||||
<TextBlock
|
|
||||||
Name="DockedStatus"
|
|
||||||
Margin="5,0,5,0"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
IsVisible="{Binding !ShowLoadProgress}"
|
|
||||||
PointerReleased="DockedStatus_PointerReleased"
|
|
||||||
Text="{Binding DockedStatusText}"
|
|
||||||
TextAlignment="Left" />
|
|
||||||
<Border
|
|
||||||
Width="2"
|
|
||||||
Height="12"
|
|
||||||
Margin="0"
|
|
||||||
BorderBrush="Gray"
|
|
||||||
BorderThickness="1"
|
|
||||||
IsVisible="{Binding !ShowLoadProgress}" />
|
|
||||||
<TextBlock
|
|
||||||
Name="AspectRatioStatus"
|
|
||||||
Margin="5,0,5,0"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
IsVisible="{Binding !ShowLoadProgress}"
|
|
||||||
PointerReleased="AspectRatioStatus_PointerReleased"
|
|
||||||
Text="{Binding AspectRatioStatusText}"
|
|
||||||
TextAlignment="Left" />
|
|
||||||
<Border
|
|
||||||
Width="2"
|
|
||||||
Height="12"
|
|
||||||
Margin="0"
|
|
||||||
BorderBrush="Gray"
|
|
||||||
BorderThickness="1"
|
|
||||||
IsVisible="{Binding !ShowLoadProgress}" />
|
|
||||||
<ui:ToggleSplitButton
|
|
||||||
Name="VolumeStatus"
|
|
||||||
Padding="5,0,5,0"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
VerticalContentAlignment="Center"
|
|
||||||
Background="{DynamicResource ThemeContentBackgroundColor}"
|
|
||||||
BorderThickness="0"
|
|
||||||
Content="{Binding VolumeStatusText}"
|
|
||||||
IsChecked="{Binding VolumeMuted}"
|
|
||||||
IsVisible="{Binding !ShowLoadProgress}">
|
|
||||||
<ui:ToggleSplitButton.Flyout>
|
|
||||||
<Flyout Placement="Bottom" ShowMode="TransientWithDismissOnPointerMoveAway">
|
|
||||||
<Grid Margin="0">
|
|
||||||
<Slider
|
|
||||||
MaxHeight="40"
|
|
||||||
Width="150"
|
|
||||||
Margin="0"
|
|
||||||
Padding="0"
|
|
||||||
IsSnapToTickEnabled="True"
|
|
||||||
LargeChange="0.05"
|
|
||||||
Maximum="1"
|
|
||||||
Minimum="0"
|
|
||||||
SmallChange="0.01"
|
|
||||||
TickFrequency="0.05"
|
|
||||||
ToolTip.Tip="{locale:Locale AudioVolumeTooltip}"
|
|
||||||
Value="{Binding Volume}" />
|
|
||||||
</Grid>
|
|
||||||
</Flyout>
|
|
||||||
</ui:ToggleSplitButton.Flyout>
|
|
||||||
</ui:ToggleSplitButton>
|
|
||||||
<Border
|
|
||||||
Width="2"
|
|
||||||
Height="12"
|
|
||||||
Margin="0"
|
|
||||||
BorderBrush="Gray"
|
|
||||||
BorderThickness="1"
|
|
||||||
IsVisible="{Binding !ShowLoadProgress}" />
|
|
||||||
<TextBlock
|
|
||||||
Margin="5,0,5,0"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
IsVisible="{Binding !ShowLoadProgress}"
|
|
||||||
Text="{Binding GameStatusText}"
|
|
||||||
TextAlignment="Left" />
|
|
||||||
<Border
|
|
||||||
Width="2"
|
|
||||||
Height="12"
|
|
||||||
Margin="0"
|
|
||||||
BorderBrush="Gray"
|
|
||||||
BorderThickness="1"
|
|
||||||
IsVisible="{Binding !ShowLoadProgress}" />
|
|
||||||
<TextBlock
|
|
||||||
Margin="5,0,5,0"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
IsVisible="{Binding !ShowLoadProgress}"
|
|
||||||
Text="{Binding FifoStatusText}"
|
|
||||||
TextAlignment="Left" />
|
|
||||||
<Border
|
|
||||||
Width="2"
|
|
||||||
Height="12"
|
|
||||||
Margin="0"
|
|
||||||
BorderBrush="Gray"
|
|
||||||
BorderThickness="1"
|
|
||||||
IsVisible="{Binding !ShowLoadProgress}" />
|
|
||||||
<TextBlock
|
|
||||||
Margin="5,0,5,0"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
IsVisible="{Binding !ShowLoadProgress}"
|
|
||||||
Text="{Binding BackendText}"
|
|
||||||
TextAlignment="Left" />
|
|
||||||
<Border
|
|
||||||
Width="2"
|
|
||||||
Height="12"
|
|
||||||
Margin="0"
|
|
||||||
BorderBrush="Gray"
|
|
||||||
BorderThickness="1"
|
|
||||||
IsVisible="{Binding !ShowLoadProgress}" />
|
|
||||||
<TextBlock
|
|
||||||
Margin="5,0,5,0"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
IsVisible="{Binding !ShowLoadProgress}"
|
|
||||||
Text="{Binding GpuNameText}"
|
|
||||||
TextAlignment="Left" />
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel
|
|
||||||
Grid.Column="3"
|
|
||||||
Margin="0,0,5,0"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
IsVisible="{Binding ShowFirmwareStatus}"
|
|
||||||
Orientation="Horizontal">
|
|
||||||
<TextBlock
|
|
||||||
Name="FirmwareStatus"
|
|
||||||
Margin="0"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{locale:Locale StatusBarSystemVersion}" />
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</window:StyleableWindow>
|
</window:StyleableWindow>
|
@@ -1,19 +1,14 @@
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
|
||||||
using Avalonia.Media;
|
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
using Ryujinx.Ava.Common;
|
using Ryujinx.Ava.Common;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.Input;
|
using Ryujinx.Ava.Input;
|
||||||
using Ryujinx.Ava.UI.Applet;
|
using Ryujinx.Ava.UI.Applet;
|
||||||
using Ryujinx.Ava.UI.Controls;
|
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
using Ryujinx.Ava.UI.Models;
|
|
||||||
using Ryujinx.Ava.UI.ViewModels;
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
using Ryujinx.Common.Configuration;
|
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Graphics.Gpu;
|
using Ryujinx.Graphics.Gpu;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
@@ -25,11 +20,9 @@ using Ryujinx.Ui.App.Common;
|
|||||||
using Ryujinx.Ui.Common;
|
using Ryujinx.Ui.Common;
|
||||||
using Ryujinx.Ui.Common.Configuration;
|
using Ryujinx.Ui.Common.Configuration;
|
||||||
using Ryujinx.Ui.Common.Helper;
|
using Ryujinx.Ui.Common.Helper;
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
|
||||||
using System;
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using InputManager = Ryujinx.Input.HLE.InputManager;
|
using InputManager = Ryujinx.Input.HLE.InputManager;
|
||||||
|
|
||||||
@@ -38,19 +31,14 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
public partial class MainWindow : StyleableWindow
|
public partial class MainWindow : StyleableWindow
|
||||||
{
|
{
|
||||||
internal static MainWindowViewModel MainWindowViewModel { get; private set; }
|
internal static MainWindowViewModel MainWindowViewModel { get; private set; }
|
||||||
private bool _canUpdate;
|
|
||||||
private bool _isClosing;
|
|
||||||
private bool _isLoading;
|
|
||||||
|
|
||||||
private Control _mainViewContent;
|
private bool _isLoading;
|
||||||
|
|
||||||
private UserChannelPersistence _userChannelPersistence;
|
private UserChannelPersistence _userChannelPersistence;
|
||||||
private static bool _deferLoad;
|
private static bool _deferLoad;
|
||||||
private static string _launchPath;
|
private static string _launchPath;
|
||||||
private static bool _startFullscreen;
|
private static bool _startFullscreen;
|
||||||
private string _currentEmulatedGamePath;
|
|
||||||
internal readonly AvaHostUiHandler UiHandler;
|
internal readonly AvaHostUiHandler UiHandler;
|
||||||
private AutoResetEvent _rendererWaitEvent;
|
|
||||||
|
|
||||||
public VirtualFileSystem VirtualFileSystem { get; private set; }
|
public VirtualFileSystem VirtualFileSystem { get; private set; }
|
||||||
public ContentManager ContentManager { get; private set; }
|
public ContentManager ContentManager { get; private set; }
|
||||||
@@ -58,30 +46,17 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
|
|
||||||
public LibHacHorizonManager LibHacHorizonManager { get; private set; }
|
public LibHacHorizonManager LibHacHorizonManager { get; private set; }
|
||||||
|
|
||||||
internal AppHost AppHost { get; private set; }
|
|
||||||
public InputManager InputManager { get; private set; }
|
public InputManager InputManager { get; private set; }
|
||||||
|
|
||||||
internal RendererHost RendererControl { get; private set; }
|
|
||||||
internal MainWindowViewModel ViewModel { get; private set; }
|
internal MainWindowViewModel ViewModel { get; private set; }
|
||||||
public SettingsWindow SettingsWindow { get; set; }
|
public SettingsWindow SettingsWindow { get; set; }
|
||||||
|
|
||||||
public bool CanUpdate
|
|
||||||
{
|
|
||||||
get => _canUpdate;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_canUpdate = value;
|
|
||||||
|
|
||||||
Dispatcher.UIThread.InvokeAsync(() => UpdateMenuItem.IsEnabled = _canUpdate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool ShowKeyErrorOnLoad { get; set; }
|
public static bool ShowKeyErrorOnLoad { get; set; }
|
||||||
public ApplicationLibrary ApplicationLibrary { get; set; }
|
public ApplicationLibrary ApplicationLibrary { get; set; }
|
||||||
|
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
ViewModel = new MainWindowViewModel(this);
|
ViewModel = new MainWindowViewModel();
|
||||||
|
|
||||||
MainWindowViewModel = ViewModel;
|
MainWindowViewModel = ViewModel;
|
||||||
|
|
||||||
@@ -92,10 +67,10 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
|
|
||||||
UiHandler = new AvaHostUiHandler(this);
|
UiHandler = new AvaHostUiHandler(this);
|
||||||
|
|
||||||
Title = $"Ryujinx {Program.Version}";
|
ViewModel.Title = $"Ryujinx {Program.Version}";
|
||||||
|
|
||||||
// NOTE: Height of MenuBar and StatusBar is not usable here, since it would still be 0 at this point.
|
// NOTE: Height of MenuBar and StatusBar is not usable here, since it would still be 0 at this point.
|
||||||
double barHeight = MenuBar.MinHeight + StatusBar.MinHeight;
|
double barHeight = MenuBar.MinHeight + StatusBarView.StatusBar.MinHeight;
|
||||||
Height = ((Height - barHeight) / Program.WindowScaleFactor) + barHeight;
|
Height = ((Height - barHeight) / Program.WindowScaleFactor) + barHeight;
|
||||||
Width /= Program.WindowScaleFactor;
|
Width /= Program.WindowScaleFactor;
|
||||||
|
|
||||||
@@ -103,14 +78,37 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
{
|
{
|
||||||
Initialize();
|
Initialize();
|
||||||
|
|
||||||
ViewModel.Initialize();
|
|
||||||
|
|
||||||
InputManager = new InputManager(new AvaloniaKeyboardDriver(this), new SDL2GamepadDriver());
|
InputManager = new InputManager(new AvaloniaKeyboardDriver(this), new SDL2GamepadDriver());
|
||||||
|
|
||||||
|
ViewModel.Initialize(
|
||||||
|
ContentManager,
|
||||||
|
ApplicationLibrary,
|
||||||
|
VirtualFileSystem,
|
||||||
|
AccountManager,
|
||||||
|
InputManager,
|
||||||
|
_userChannelPersistence,
|
||||||
|
LibHacHorizonManager,
|
||||||
|
UiHandler,
|
||||||
|
ShowLoading,
|
||||||
|
SwitchToGameControl,
|
||||||
|
SetMainContent,
|
||||||
|
this);
|
||||||
|
|
||||||
|
ViewModel.RefreshFirmwareStatus();
|
||||||
|
|
||||||
LoadGameList();
|
LoadGameList();
|
||||||
|
|
||||||
|
this.GetObservable(IsActiveProperty).Subscribe(IsActiveChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
_rendererWaitEvent = new AutoResetEvent(false);
|
ApplicationLibrary.ApplicationCountUpdated += ApplicationLibrary_ApplicationCountUpdated;
|
||||||
|
ApplicationLibrary.ApplicationAdded += ApplicationLibrary_ApplicationAdded;
|
||||||
|
ViewModel.ReloadGameList += ReloadGameList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void IsActiveChanged(bool obj)
|
||||||
|
{
|
||||||
|
ViewModel.IsActive = obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadGameList()
|
public void LoadGameList()
|
||||||
@@ -122,45 +120,51 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
|
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
|
|
||||||
ViewModel.LoadApplications();
|
LoadApplications();
|
||||||
|
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Update_StatusBar(object sender, StatusUpdatedEventArgs args)
|
|
||||||
{
|
|
||||||
if (ViewModel.ShowMenuAndStatusBar && !ViewModel.ShowLoadProgress)
|
|
||||||
{
|
|
||||||
Dispatcher.UIThread.InvokeAsync(() =>
|
|
||||||
{
|
|
||||||
if (args.VSyncEnabled)
|
|
||||||
{
|
|
||||||
ViewModel.VsyncColor = new SolidColorBrush(Color.Parse("#ff2eeac9"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ViewModel.VsyncColor = new SolidColorBrush(Color.Parse("#ffff4554"));
|
|
||||||
}
|
|
||||||
|
|
||||||
ViewModel.DockedStatusText = args.DockedMode;
|
|
||||||
ViewModel.AspectRatioStatusText = args.AspectRatio;
|
|
||||||
ViewModel.GameStatusText = args.GameStatus;
|
|
||||||
ViewModel.VolumeStatusText = args.VolumeStatus;
|
|
||||||
ViewModel.FifoStatusText = args.FifoStatus;
|
|
||||||
ViewModel.GpuNameText = args.GpuName;
|
|
||||||
ViewModel.BackendText = args.GpuBackend;
|
|
||||||
|
|
||||||
ViewModel.ShowStatusSeparator = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void HandleScalingChanged(double scale)
|
protected override void HandleScalingChanged(double scale)
|
||||||
{
|
{
|
||||||
Program.DesktopScaleFactor = scale;
|
Program.DesktopScaleFactor = scale;
|
||||||
base.HandleScalingChanged(scale);
|
base.HandleScalingChanged(scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AddApplication(ApplicationData applicationData)
|
||||||
|
{
|
||||||
|
Dispatcher.UIThread.InvokeAsync(() =>
|
||||||
|
{
|
||||||
|
ViewModel.Applications.Add(applicationData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplicationLibrary_ApplicationAdded(object sender, ApplicationAddedEventArgs e)
|
||||||
|
{
|
||||||
|
AddApplication(e.AppData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplicationLibrary_ApplicationCountUpdated(object sender, ApplicationCountUpdatedEventArgs e)
|
||||||
|
{
|
||||||
|
LocaleManager.Instance.UpdateDynamicValue(LocaleKeys.StatusBarGamesLoaded, e.NumAppsLoaded, e.NumAppsFound);
|
||||||
|
|
||||||
|
Dispatcher.UIThread.Post(() =>
|
||||||
|
{
|
||||||
|
ViewModel.StatusBarProgressValue = e.NumAppsLoaded;
|
||||||
|
ViewModel.StatusBarProgressMaximum = e.NumAppsFound;
|
||||||
|
|
||||||
|
if (e.NumAppsFound == 0)
|
||||||
|
{
|
||||||
|
StatusBarView.LoadProgressBar.IsVisible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.NumAppsLoaded == e.NumAppsFound)
|
||||||
|
{
|
||||||
|
StatusBarView.LoadProgressBar.IsVisible = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public void Application_Opened(object sender, ApplicationOpenedEventArgs args)
|
public void Application_Opened(object sender, ApplicationOpenedEventArgs args)
|
||||||
{
|
{
|
||||||
if (args.Application != null)
|
if (args.Application != null)
|
||||||
@@ -169,50 +173,12 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
|
|
||||||
string path = new FileInfo(args.Application.Path).FullName;
|
string path = new FileInfo(args.Application.Path).FullName;
|
||||||
|
|
||||||
LoadApplication(path);
|
ViewModel.LoadApplication(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PerformanceCheck()
|
|
||||||
{
|
|
||||||
if (ConfigurationState.Instance.Logger.EnableTrace.Value)
|
|
||||||
{
|
|
||||||
string mainMessage = LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckLoggingEnabledMessage];
|
|
||||||
string secondaryMessage = LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckLoggingEnabledConfirmMessage];
|
|
||||||
|
|
||||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(mainMessage, secondaryMessage,
|
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogYes], LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
|
||||||
LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
|
|
||||||
|
|
||||||
if (result != UserResult.Yes)
|
|
||||||
{
|
|
||||||
ConfigurationState.Instance.Logger.EnableTrace.Value = false;
|
|
||||||
|
|
||||||
SaveConfig();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(ConfigurationState.Instance.Graphics.ShadersDumpPath.Value))
|
|
||||||
{
|
|
||||||
string mainMessage = LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckShaderDumpEnabledMessage];
|
|
||||||
string secondaryMessage =
|
|
||||||
LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckShaderDumpEnabledConfirmMessage];
|
|
||||||
|
|
||||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(mainMessage, secondaryMessage,
|
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogYes], LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
|
||||||
LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
|
|
||||||
|
|
||||||
if (result != UserResult.Yes)
|
|
||||||
{
|
|
||||||
ConfigurationState.Instance.Graphics.ShadersDumpPath.Value = "";
|
|
||||||
|
|
||||||
SaveConfig();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void DeferLoadApplication(string launchPathArg, bool startFullscreenArg)
|
internal static void DeferLoadApplication(string launchPathArg, bool startFullscreenArg)
|
||||||
{
|
{
|
||||||
_deferLoad = true;
|
_deferLoad = true;
|
||||||
@@ -220,109 +186,6 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
_startFullscreen = startFullscreenArg;
|
_startFullscreen = startFullscreenArg;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable CS1998
|
|
||||||
public async void LoadApplication(string path, bool startFullscreen = false, string titleName = "")
|
|
||||||
#pragma warning restore CS1998
|
|
||||||
{
|
|
||||||
if (AppHost != null)
|
|
||||||
{
|
|
||||||
await ContentDialogHelper.CreateInfoDialog(
|
|
||||||
LocaleManager.Instance[LocaleKeys.DialogLoadAppGameAlreadyLoadedMessage],
|
|
||||||
LocaleManager.Instance[LocaleKeys.DialogLoadAppGameAlreadyLoadedSubMessage],
|
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
|
||||||
"",
|
|
||||||
LocaleManager.Instance[LocaleKeys.RyujinxInfo]);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if RELEASE
|
|
||||||
await PerformanceCheck();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Logger.RestartTime();
|
|
||||||
|
|
||||||
if (ViewModel.SelectedIcon == null)
|
|
||||||
{
|
|
||||||
ViewModel.SelectedIcon = ApplicationLibrary.GetApplicationIcon(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
PrepareLoadScreen();
|
|
||||||
|
|
||||||
_mainViewContent = MainContent.Content as Control;
|
|
||||||
|
|
||||||
RendererControl = new RendererHost(ConfigurationState.Instance.Logger.GraphicsDebugLevel);
|
|
||||||
if (ConfigurationState.Instance.Graphics.GraphicsBackend.Value == GraphicsBackend.OpenGl)
|
|
||||||
{
|
|
||||||
RendererControl.CreateOpenGL();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RendererControl.CreateVulkan();
|
|
||||||
}
|
|
||||||
|
|
||||||
AppHost = new AppHost(RendererControl, InputManager, path, VirtualFileSystem, ContentManager, AccountManager, _userChannelPersistence, this);
|
|
||||||
|
|
||||||
Dispatcher.UIThread.Post(async () =>
|
|
||||||
{
|
|
||||||
if (!await AppHost.LoadGuestApplication())
|
|
||||||
{
|
|
||||||
AppHost.DisposeContext();
|
|
||||||
AppHost = null;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CanUpdate = false;
|
|
||||||
ViewModel.LoadHeading = string.IsNullOrWhiteSpace(titleName) ? string.Format(LocaleManager.Instance[LocaleKeys.LoadingHeading], AppHost.Device.Application.TitleName) : titleName;
|
|
||||||
ViewModel.TitleName = string.IsNullOrWhiteSpace(titleName) ? AppHost.Device.Application.TitleName : titleName;
|
|
||||||
|
|
||||||
SwitchToGameControl(startFullscreen);
|
|
||||||
|
|
||||||
_currentEmulatedGamePath = path;
|
|
||||||
|
|
||||||
Thread gameThread = new(InitializeGame)
|
|
||||||
{
|
|
||||||
Name = "GUI.WindowThread"
|
|
||||||
};
|
|
||||||
gameThread.Start();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitializeGame()
|
|
||||||
{
|
|
||||||
RendererControl.RendererInitialized += GlRenderer_Created;
|
|
||||||
|
|
||||||
AppHost.StatusUpdatedEvent += Update_StatusBar;
|
|
||||||
AppHost.AppExit += AppHost_AppExit;
|
|
||||||
|
|
||||||
_rendererWaitEvent.WaitOne();
|
|
||||||
|
|
||||||
AppHost?.Start();
|
|
||||||
|
|
||||||
AppHost.DisposeContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void HandleRelaunch()
|
|
||||||
{
|
|
||||||
if (_userChannelPersistence.PreviousIndex != -1 && _userChannelPersistence.ShouldRestart)
|
|
||||||
{
|
|
||||||
_userChannelPersistence.ShouldRestart = false;
|
|
||||||
|
|
||||||
Dispatcher.UIThread.Post(() =>
|
|
||||||
{
|
|
||||||
LoadApplication(_currentEmulatedGamePath);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// otherwise, clear state.
|
|
||||||
_userChannelPersistence = new UserChannelPersistence();
|
|
||||||
_currentEmulatedGamePath = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SwitchToGameControl(bool startFullscreen = false)
|
public void SwitchToGameControl(bool startFullscreen = false)
|
||||||
{
|
{
|
||||||
ViewModel.ShowLoadProgress = false;
|
ViewModel.ShowLoadProgress = false;
|
||||||
@@ -331,14 +194,10 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
|
|
||||||
Dispatcher.UIThread.InvokeAsync(() =>
|
Dispatcher.UIThread.InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
MainContent.Content = RendererControl;
|
if (startFullscreen && ViewModel.WindowState != WindowState.FullScreen)
|
||||||
|
|
||||||
if (startFullscreen && WindowState != WindowState.FullScreen)
|
|
||||||
{
|
{
|
||||||
ViewModel.ToggleFullscreen();
|
ViewModel.ToggleFullscreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
RendererControl.Focus();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,71 +209,16 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
|
|
||||||
Dispatcher.UIThread.InvokeAsync(() =>
|
Dispatcher.UIThread.InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
if (startFullscreen && WindowState != WindowState.FullScreen)
|
if (startFullscreen && ViewModel.WindowState != WindowState.FullScreen)
|
||||||
{
|
{
|
||||||
ViewModel.ToggleFullscreen();
|
ViewModel.ToggleFullscreen();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GlRenderer_Created(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
ShowLoading();
|
|
||||||
|
|
||||||
_rendererWaitEvent.Set();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AppHost_AppExit(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if (_isClosing)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ViewModel.IsGameRunning = false;
|
|
||||||
|
|
||||||
Dispatcher.UIThread.InvokeAsync(() =>
|
|
||||||
{
|
|
||||||
ViewModel.ShowMenuAndStatusBar = true;
|
|
||||||
ViewModel.ShowContent = true;
|
|
||||||
ViewModel.ShowLoadProgress = false;
|
|
||||||
ViewModel.IsLoadingIndeterminate = false;
|
|
||||||
CanUpdate = true;
|
|
||||||
Cursor = Cursor.Default;
|
|
||||||
|
|
||||||
if (MainContent.Content != _mainViewContent)
|
|
||||||
{
|
|
||||||
MainContent.Content = _mainViewContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
AppHost = null;
|
|
||||||
|
|
||||||
HandleRelaunch();
|
|
||||||
});
|
|
||||||
|
|
||||||
RendererControl.RendererInitialized -= GlRenderer_Created;
|
|
||||||
RendererControl = null;
|
|
||||||
|
|
||||||
ViewModel.SelectedIcon = null;
|
|
||||||
|
|
||||||
Dispatcher.UIThread.InvokeAsync(() =>
|
|
||||||
{
|
|
||||||
Title = $"Ryujinx {Program.Version}";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Sort_Checked(object sender, RoutedEventArgs args)
|
|
||||||
{
|
|
||||||
if (sender is RadioButton button)
|
|
||||||
{
|
|
||||||
var sort = Enum.Parse<ApplicationSort>(button.Tag.ToString());
|
|
||||||
ViewModel.Sort(sort);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void HandleWindowStateChanged(WindowState state)
|
protected override void HandleWindowStateChanged(WindowState state)
|
||||||
{
|
{
|
||||||
WindowState = state;
|
ViewModel.WindowState = state;
|
||||||
|
|
||||||
if (state != WindowState.Minimized)
|
if (state != WindowState.Minimized)
|
||||||
{
|
{
|
||||||
@@ -422,15 +226,6 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Order_Checked(object sender, RoutedEventArgs args)
|
|
||||||
{
|
|
||||||
if (sender is RadioButton button)
|
|
||||||
{
|
|
||||||
var tag = button.Tag.ToString();
|
|
||||||
ViewModel.Sort(tag != "Descending");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Initialize()
|
private void Initialize()
|
||||||
{
|
{
|
||||||
_userChannelPersistence = new UserChannelPersistence();
|
_userChannelPersistence = new UserChannelPersistence();
|
||||||
@@ -457,8 +252,6 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
VirtualFileSystem.ReloadKeySet();
|
VirtualFileSystem.ReloadKeySet();
|
||||||
|
|
||||||
ApplicationHelper.Initialize(VirtualFileSystem, AccountManager, LibHacHorizonManager.RyujinxClient, this);
|
ApplicationHelper.Initialize(VirtualFileSystem, AccountManager, LibHacHorizonManager.RyujinxClient, this);
|
||||||
|
|
||||||
RefreshFirmwareStatus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void CheckLaunchState()
|
protected void CheckLaunchState()
|
||||||
@@ -475,7 +268,7 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
{
|
{
|
||||||
_deferLoad = false;
|
_deferLoad = false;
|
||||||
|
|
||||||
LoadApplication(_launchPath, _startFullscreen);
|
ViewModel.LoadApplication(_launchPath, _startFullscreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ConfigurationState.Instance.CheckUpdatesOnStart.Value && Updater.CanUpdate(false, this))
|
if (ConfigurationState.Instance.CheckUpdatesOnStart.Value && Updater.CanUpdate(false, this))
|
||||||
@@ -487,35 +280,9 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RefreshFirmwareStatus()
|
|
||||||
{
|
|
||||||
SystemVersion version = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
version = ContentManager.GetCurrentFirmwareVersion();
|
|
||||||
}
|
|
||||||
catch (Exception) { }
|
|
||||||
|
|
||||||
bool hasApplet = false;
|
|
||||||
|
|
||||||
if (version != null)
|
|
||||||
{
|
|
||||||
LocaleManager.Instance.UpdateDynamicValue(LocaleKeys.StatusBarSystemVersion,
|
|
||||||
version.VersionString);
|
|
||||||
|
|
||||||
hasApplet = version.Major > 3;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LocaleManager.Instance.UpdateDynamicValue(LocaleKeys.StatusBarSystemVersion, "0.0");
|
|
||||||
}
|
|
||||||
|
|
||||||
ViewModel.IsAppletMenuActive = hasApplet;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Load()
|
private void Load()
|
||||||
{
|
{
|
||||||
VolumeStatus.Click += VolumeStatus_CheckedChanged;
|
StatusBarView.VolumeStatus.Click += VolumeStatus_CheckedChanged;
|
||||||
|
|
||||||
GameGrid.ApplicationOpened += Application_Opened;
|
GameGrid.ApplicationOpened += Application_Opened;
|
||||||
|
|
||||||
@@ -535,6 +302,19 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
CheckLaunchState();
|
CheckLaunchState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetMainContent(Control content = null)
|
||||||
|
{
|
||||||
|
if (content == null)
|
||||||
|
{
|
||||||
|
content = GameLibrary;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MainContent.Content != content)
|
||||||
|
{
|
||||||
|
MainContent.Content = content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void UpdateGraphicsConfig()
|
public static void UpdateGraphicsConfig()
|
||||||
{
|
{
|
||||||
GraphicsConfig.ResScale = ConfigurationState.Instance.Graphics.ResScale == -1 ? ConfigurationState.Instance.Graphics.ResScaleCustom : ConfigurationState.Instance.Graphics.ResScale;
|
GraphicsConfig.ResScale = ConfigurationState.Instance.Graphics.ResScale == -1 ? ConfigurationState.Instance.Graphics.ResScaleCustom : ConfigurationState.Instance.Graphics.ResScale;
|
||||||
@@ -553,99 +333,6 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
HotKeyManager.SetHotKey(ExitHotKey, new KeyGesture(Key.Escape));
|
HotKeyManager.SetHotKey(ExitHotKey, new KeyGesture(Key.Escape));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SaveConfig()
|
|
||||||
{
|
|
||||||
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateGameMetadata(string titleId)
|
|
||||||
{
|
|
||||||
ApplicationLibrary.LoadAndSaveMetaData(titleId, appMetadata =>
|
|
||||||
{
|
|
||||||
if (DateTime.TryParse(appMetadata.LastPlayed, out DateTime lastPlayedDateTime))
|
|
||||||
{
|
|
||||||
double sessionTimePlayed = DateTime.UtcNow.Subtract(lastPlayedDateTime).TotalSeconds;
|
|
||||||
|
|
||||||
appMetadata.TimePlayed += Math.Round(sessionTimePlayed, MidpointRounding.AwayFromZero);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PrepareLoadScreen()
|
|
||||||
{
|
|
||||||
using MemoryStream stream = new MemoryStream(ViewModel.SelectedIcon);
|
|
||||||
using var gameIconBmp = SixLabors.ImageSharp.Image.Load<Bgra32>(stream);
|
|
||||||
|
|
||||||
var dominantColor = IconColorPicker.GetFilteredColor(gameIconBmp).ToPixel<Bgra32>();
|
|
||||||
|
|
||||||
const int ColorDivisor = 4;
|
|
||||||
|
|
||||||
Color progressFgColor = Color.FromRgb(dominantColor.R, dominantColor.G, dominantColor.B);
|
|
||||||
Color progressBgColor = Color.FromRgb(
|
|
||||||
(byte)(dominantColor.R / ColorDivisor),
|
|
||||||
(byte)(dominantColor.G / ColorDivisor),
|
|
||||||
(byte)(dominantColor.B / ColorDivisor));
|
|
||||||
|
|
||||||
ViewModel.ProgressBarForegroundColor = new SolidColorBrush(progressFgColor);
|
|
||||||
ViewModel.ProgressBarBackgroundColor = new SolidColorBrush(progressBgColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SearchBox_OnKeyUp(object sender, KeyEventArgs e)
|
|
||||||
{
|
|
||||||
ViewModel.SearchText = SearchBox.Text;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void StopEmulation_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (AppHost != null)
|
|
||||||
{
|
|
||||||
await AppHost.ShowExitPrompt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void PauseEmulation_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
await Task.Run(() =>
|
|
||||||
{
|
|
||||||
AppHost?.Pause();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void ResumeEmulation_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
await Task.Run(() =>
|
|
||||||
{
|
|
||||||
AppHost?.Resume();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ScanAmiiboMenuItem_AttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e)
|
|
||||||
{
|
|
||||||
if (sender is MenuItem)
|
|
||||||
{
|
|
||||||
ViewModel.IsAmiiboRequested = AppHost.Device.System.SearchingForAmiibo(out _);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void VsyncStatus_PointerReleased(object sender, PointerReleasedEventArgs e)
|
|
||||||
{
|
|
||||||
AppHost.Device.EnableDeviceVsync = !AppHost.Device.EnableDeviceVsync;
|
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.Application, $"VSync toggled to: {AppHost.Device.EnableDeviceVsync}");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DockedStatus_PointerReleased(object sender, PointerReleasedEventArgs e)
|
|
||||||
{
|
|
||||||
ConfigurationState.Instance.System.EnableDockedMode.Value = !ConfigurationState.Instance.System.EnableDockedMode.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AspectRatioStatus_PointerReleased(object sender, PointerReleasedEventArgs e)
|
|
||||||
{
|
|
||||||
AspectRatio aspectRatio = ConfigurationState.Instance.Graphics.AspectRatio.Value;
|
|
||||||
|
|
||||||
ConfigurationState.Instance.Graphics.AspectRatio.Value = (int)aspectRatio + 1 > Enum.GetNames(typeof(AspectRatio)).Length - 1 ? AspectRatio.Fixed4x3 : aspectRatio + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void VolumeStatus_CheckedChanged(object sender, SplitButtonClickEventArgs e)
|
private void VolumeStatus_CheckedChanged(object sender, SplitButtonClickEventArgs e)
|
||||||
{
|
{
|
||||||
var volumeSplitButton = sender as ToggleSplitButton;
|
var volumeSplitButton = sender as ToggleSplitButton;
|
||||||
@@ -653,20 +340,20 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
{
|
{
|
||||||
if (!volumeSplitButton.IsChecked)
|
if (!volumeSplitButton.IsChecked)
|
||||||
{
|
{
|
||||||
AppHost.Device.SetVolume(ConfigurationState.Instance.System.AudioVolume);
|
ViewModel.AppHost.Device.SetVolume(ConfigurationState.Instance.System.AudioVolume);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AppHost.Device.SetVolume(0);
|
ViewModel.AppHost.Device.SetVolume(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewModel.Volume = AppHost.Device.GetVolume();
|
ViewModel.Volume = ViewModel.AppHost.Device.GetVolume();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnClosing(CancelEventArgs e)
|
protected override void OnClosing(CancelEventArgs e)
|
||||||
{
|
{
|
||||||
if (!_isClosing && AppHost != null && ConfigurationState.Instance.ShowConfirmExit)
|
if (!ViewModel.IsClosing && ViewModel.AppHost != null && ConfigurationState.Instance.ShowConfirmExit)
|
||||||
{
|
{
|
||||||
e.Cancel = true;
|
e.Cancel = true;
|
||||||
|
|
||||||
@@ -675,14 +362,14 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_isClosing = true;
|
ViewModel.IsClosing = true;
|
||||||
|
|
||||||
if (AppHost != null)
|
if (ViewModel.AppHost != null)
|
||||||
{
|
{
|
||||||
AppHost.AppExit -= AppHost_AppExit;
|
ViewModel.AppHost.AppExit -= ViewModel.AppHost_AppExit;
|
||||||
AppHost.AppExit += (sender, e) =>
|
ViewModel.AppHost.AppExit += (sender, e) =>
|
||||||
{
|
{
|
||||||
AppHost = null;
|
ViewModel.AppHost = null;
|
||||||
|
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
{
|
{
|
||||||
@@ -691,7 +378,7 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
Close();
|
Close();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
AppHost?.Stop();
|
ViewModel.AppHost?.Stop();
|
||||||
|
|
||||||
e.Cancel = true;
|
e.Cancel = true;
|
||||||
|
|
||||||
@@ -709,13 +396,43 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
{
|
{
|
||||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||||
{
|
{
|
||||||
_isClosing = await ContentDialogHelper.CreateExitDialog();
|
ViewModel.IsClosing = await ContentDialogHelper.CreateExitDialog();
|
||||||
|
|
||||||
if (_isClosing)
|
if (ViewModel.IsClosing)
|
||||||
{
|
{
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async void LoadApplications()
|
||||||
|
{
|
||||||
|
await Dispatcher.UIThread.InvokeAsync(() =>
|
||||||
|
{
|
||||||
|
ViewModel.Applications.Clear();
|
||||||
|
|
||||||
|
StatusBarView.LoadProgressBar.IsVisible = true;
|
||||||
|
ViewModel.StatusBarProgressMaximum = 0;
|
||||||
|
ViewModel.StatusBarProgressValue = 0;
|
||||||
|
|
||||||
|
LocaleManager.Instance.UpdateDynamicValue(LocaleKeys.StatusBarGamesLoaded, 0, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
ReloadGameList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReloadGameList()
|
||||||
|
{
|
||||||
|
if (_isLoading)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isLoading = true;
|
||||||
|
|
||||||
|
ApplicationLibrary.LoadApplications(ConfigurationState.Instance.Ui.GameDirs.Value, ConfigurationState.Instance.System.Language);
|
||||||
|
|
||||||
|
_isLoading = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -6,13 +6,12 @@
|
|||||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
|
||||||
xmlns:window="clr-namespace:Ryujinx.Ava.UI.Windows"
|
xmlns:window="clr-namespace:Ryujinx.Ava.UI.Windows"
|
||||||
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
|
xmlns:settings="clr-namespace:Ryujinx.Ava.UI.Views.Settings"
|
||||||
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
||||||
Width="1100"
|
Width="1100"
|
||||||
Height="768"
|
Height="768"
|
||||||
d:DesignWidth="800"
|
|
||||||
d:DesignHeight="950"
|
|
||||||
MinWidth="800"
|
MinWidth="800"
|
||||||
MinHeight="480"
|
MinHeight="480"
|
||||||
WindowStartupLocation="CenterOwner"
|
WindowStartupLocation="CenterOwner"
|
||||||
@@ -23,9 +22,6 @@
|
|||||||
<Design.DataContext>
|
<Design.DataContext>
|
||||||
<viewModels:SettingsViewModel />
|
<viewModels:SettingsViewModel />
|
||||||
</Design.DataContext>
|
</Design.DataContext>
|
||||||
<Window.Resources>
|
|
||||||
<helpers:KeyValueConverter x:Key="Key" />
|
|
||||||
</Window.Resources>
|
|
||||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MinWidth="600">
|
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MinWidth="600">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
@@ -38,871 +34,15 @@
|
|||||||
IsVisible="False"
|
IsVisible="False"
|
||||||
KeyboardNavigation.IsTabStop="False"/>
|
KeyboardNavigation.IsTabStop="False"/>
|
||||||
<Grid Name="Pages" IsVisible="False" Grid.Row="2">
|
<Grid Name="Pages" IsVisible="False" Grid.Row="2">
|
||||||
<ScrollViewer Name="UiPage"
|
<settings:SettingsUIView Name="UiPage" />
|
||||||
Margin="0,0,2,0"
|
<settings:SettingsInputView Name="InputPage" />
|
||||||
HorizontalAlignment="Stretch"
|
<settings:SettingsHotkeysView Name="HotkeysPage" />
|
||||||
VerticalAlignment="Stretch"
|
<settings:SettingsSystemView Name="SystemPage" />
|
||||||
HorizontalScrollBarVisibility="Disabled"
|
<settings:SettingsCPUView Name="CpuPage" />
|
||||||
VerticalScrollBarVisibility="Auto">
|
<settings:SettingsGraphicsView Name="GraphicsPage" />
|
||||||
<Border Classes="settings">
|
<settings:SettingsAudioView Name="AudioPage" />
|
||||||
<StackPanel
|
<settings:SettingsNetworkView Name="NetworkPage" />
|
||||||
Margin="10,5"
|
<settings:SettingsLoggingView Name="LoggingPage" />
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Orientation="Vertical"
|
|
||||||
Spacing="10">
|
|
||||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGeneralGeneral}" />
|
|
||||||
<StackPanel Margin="10,0,0,0" Orientation="Vertical">
|
|
||||||
<CheckBox IsChecked="{Binding EnableDiscordIntegration}">
|
|
||||||
<TextBlock VerticalAlignment="Center"
|
|
||||||
ToolTip.Tip="{locale:Locale ToggleDiscordTooltip}"
|
|
||||||
Text="{locale:Locale SettingsTabGeneralEnableDiscordRichPresence}" />
|
|
||||||
</CheckBox>
|
|
||||||
<CheckBox IsChecked="{Binding CheckUpdatesOnStart}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGeneralCheckUpdatesOnLaunch}" />
|
|
||||||
</CheckBox>
|
|
||||||
<CheckBox IsChecked="{Binding ShowConfirmExit}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGeneralShowConfirmExitDialog}" />
|
|
||||||
</CheckBox>
|
|
||||||
<CheckBox IsChecked="{Binding HideCursorOnIdle}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGeneralHideCursorOnIdle}" />
|
|
||||||
</CheckBox>
|
|
||||||
</StackPanel>
|
|
||||||
<Separator Height="1" />
|
|
||||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGeneralGameDirectories}" />
|
|
||||||
<StackPanel
|
|
||||||
Margin="10,0,0,0"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Orientation="Vertical"
|
|
||||||
Spacing="10">
|
|
||||||
<ListBox
|
|
||||||
Name="GameList"
|
|
||||||
MinHeight="250"
|
|
||||||
Items="{Binding GameDirectories}" />
|
|
||||||
<Grid HorizontalAlignment="Stretch">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<TextBox
|
|
||||||
Name="PathBox"
|
|
||||||
Margin="0"
|
|
||||||
ToolTip.Tip="{locale:Locale AddGameDirBoxTooltip}"
|
|
||||||
VerticalAlignment="Stretch" />
|
|
||||||
<Button
|
|
||||||
Name="AddButton"
|
|
||||||
Grid.Column="1"
|
|
||||||
MinWidth="90"
|
|
||||||
Margin="10,0,0,0"
|
|
||||||
ToolTip.Tip="{locale:Locale AddGameDirTooltip}"
|
|
||||||
Click="AddButton_OnClick">
|
|
||||||
<TextBlock HorizontalAlignment="Center"
|
|
||||||
Text="{locale:Locale SettingsTabGeneralAdd}" />
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
Name="RemoveButton"
|
|
||||||
Grid.Column="2"
|
|
||||||
MinWidth="90"
|
|
||||||
Margin="10,0,0,0"
|
|
||||||
ToolTip.Tip="{locale:Locale RemoveGameDirTooltip}"
|
|
||||||
Click="RemoveButton_OnClick">
|
|
||||||
<TextBlock HorizontalAlignment="Center"
|
|
||||||
Text="{locale:Locale SettingsTabGeneralRemove}" />
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
</StackPanel>
|
|
||||||
<Separator Height="1" />
|
|
||||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGeneralTheme}" />
|
|
||||||
<Grid Margin="10,0,0,0">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition />
|
|
||||||
<RowDefinition />
|
|
||||||
<RowDefinition />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<CheckBox IsChecked="{Binding EnableCustomTheme}"
|
|
||||||
ToolTip.Tip="{locale:Locale CustomThemeCheckTooltip}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGeneralThemeEnableCustomTheme}" />
|
|
||||||
</CheckBox>
|
|
||||||
<TextBlock VerticalAlignment="Center"
|
|
||||||
Margin="0,10,0,0"
|
|
||||||
Grid.Row="1"
|
|
||||||
Text="{locale:Locale SettingsTabGeneralThemeCustomTheme}"
|
|
||||||
ToolTip.Tip="{locale:Locale CustomThemePathTooltip}" />
|
|
||||||
<TextBox Margin="0,10,0,0"
|
|
||||||
Grid.Row="1"
|
|
||||||
Grid.Column="1"
|
|
||||||
Text="{Binding CustomThemePath}" />
|
|
||||||
<Button Grid.Row="1"
|
|
||||||
Grid.Column="2"
|
|
||||||
Margin="10,10,0,0"
|
|
||||||
Command="{ReflectionBinding BrowseTheme}"
|
|
||||||
ToolTip.Tip="{locale:Locale CustomThemeBrowseTooltip}"
|
|
||||||
Content="{locale:Locale ButtonBrowse}" />
|
|
||||||
<TextBlock VerticalAlignment="Center"
|
|
||||||
Margin="0,10,0,0"
|
|
||||||
Grid.Row="2"
|
|
||||||
Text="{locale:Locale SettingsTabGeneralThemeBaseStyle}" />
|
|
||||||
<ComboBox VerticalAlignment="Center"
|
|
||||||
Margin="0,10,0,0"
|
|
||||||
Grid.Column="1"
|
|
||||||
Grid.Row="2"
|
|
||||||
MinWidth="100"
|
|
||||||
SelectedIndex="{Binding BaseStyleIndex}">
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGeneralThemeBaseStyleLight}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGeneralThemeBaseStyleDark}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
</ComboBox>
|
|
||||||
</Grid>
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
</ScrollViewer>
|
|
||||||
<ScrollViewer Name="InputPage"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
Padding="0,0,2,0"
|
|
||||||
HorizontalScrollBarVisibility="Disabled"
|
|
||||||
VerticalScrollBarVisibility="Auto">
|
|
||||||
<Border Classes="settings">
|
|
||||||
<StackPanel Margin="4" Orientation="Vertical">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<CheckBox Margin="5,0"
|
|
||||||
ToolTip.Tip="{locale:Locale DockModeToggleTooltip}"
|
|
||||||
IsChecked="{Binding EnableDockedMode}">
|
|
||||||
<TextBlock VerticalAlignment="Center"
|
|
||||||
Text="{locale:Locale SettingsTabInputEnableDockedMode}" />
|
|
||||||
</CheckBox>
|
|
||||||
<CheckBox Margin="5,0"
|
|
||||||
ToolTip.Tip="{locale:Locale DirectKeyboardTooltip}"
|
|
||||||
IsChecked="{Binding EnableKeyboard}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabInputDirectKeyboardAccess}" />
|
|
||||||
</CheckBox>
|
|
||||||
<CheckBox Margin="5,0"
|
|
||||||
ToolTip.Tip="{locale:Locale DirectMouseTooltip}"
|
|
||||||
IsChecked="{Binding EnableMouse}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabInputDirectMouseAccess}" />
|
|
||||||
</CheckBox>
|
|
||||||
</StackPanel>
|
|
||||||
<window:ControllerSettingsWindow Name="ControllerSettings" Margin="0,0,0,0" MinHeight="600" />
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
</ScrollViewer>
|
|
||||||
<ScrollViewer Name="HotkeysPage"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
HorizontalScrollBarVisibility="Disabled"
|
|
||||||
VerticalScrollBarVisibility="Auto">
|
|
||||||
<Border Classes="settings">
|
|
||||||
<StackPanel Margin="10,5" Orientation="Vertical" Spacing="10">
|
|
||||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabHotkeysHotkeys}" />
|
|
||||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
|
||||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysToggleVsyncHotkey}" Width="230" />
|
|
||||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
|
||||||
<TextBlock
|
|
||||||
Text="{Binding KeyboardHotkeys.ToggleVsync, Mode=TwoWay, Converter={StaticResource Key}}"
|
|
||||||
TextAlignment="Center" />
|
|
||||||
</ToggleButton>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
|
||||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysScreenshotHotkey}" Width="230" />
|
|
||||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
|
||||||
<TextBlock
|
|
||||||
Text="{Binding KeyboardHotkeys.Screenshot, Mode=TwoWay, Converter={StaticResource Key}}"
|
|
||||||
TextAlignment="Center" />
|
|
||||||
</ToggleButton>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
|
||||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysShowUiHotkey}" Width="230" />
|
|
||||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
|
||||||
<TextBlock
|
|
||||||
Text="{Binding KeyboardHotkeys.ShowUi, Mode=TwoWay, Converter={StaticResource Key}}"
|
|
||||||
TextAlignment="Center" />
|
|
||||||
</ToggleButton>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
|
||||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysPauseHotkey}" Width="230" />
|
|
||||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
|
||||||
<TextBlock
|
|
||||||
Text="{Binding KeyboardHotkeys.Pause, Mode=TwoWay, Converter={StaticResource Key}}"
|
|
||||||
TextAlignment="Center" />
|
|
||||||
</ToggleButton>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
|
||||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysToggleMuteHotkey}" Width="230" />
|
|
||||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
|
||||||
<TextBlock
|
|
||||||
Text="{Binding KeyboardHotkeys.ToggleMute, Mode=TwoWay, Converter={StaticResource Key}}"
|
|
||||||
TextAlignment="Center" />
|
|
||||||
</ToggleButton>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
|
||||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysResScaleUpHotkey}" Width="230" />
|
|
||||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
|
||||||
<TextBlock
|
|
||||||
Text="{Binding KeyboardHotkeys.ResScaleUp, Mode=TwoWay, Converter={StaticResource Key}}"
|
|
||||||
TextAlignment="Center" />
|
|
||||||
</ToggleButton>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
|
||||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysResScaleDownHotkey}" Width="230" />
|
|
||||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
|
||||||
<TextBlock
|
|
||||||
Text="{Binding KeyboardHotkeys.ResScaleDown, Mode=TwoWay, Converter={StaticResource Key}}"
|
|
||||||
TextAlignment="Center" />
|
|
||||||
</ToggleButton>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
|
||||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysVolumeUpHotkey}" Width="230" />
|
|
||||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
|
||||||
<TextBlock
|
|
||||||
Text="{Binding KeyboardHotkeys.VolumeUp, Mode=TwoWay, Converter={StaticResource Key}}"
|
|
||||||
TextAlignment="Center" />
|
|
||||||
</ToggleButton>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
|
||||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysVolumeDownHotkey}" Width="230" />
|
|
||||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
|
||||||
<TextBlock
|
|
||||||
Text="{Binding KeyboardHotkeys.VolumeDown, Mode=TwoWay, Converter={StaticResource Key}}"
|
|
||||||
TextAlignment="Center" />
|
|
||||||
</ToggleButton>
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
</ScrollViewer>
|
|
||||||
<ScrollViewer Name="SystemPage"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
HorizontalScrollBarVisibility="Disabled"
|
|
||||||
VerticalScrollBarVisibility="Auto">
|
|
||||||
<Border Classes="settings">
|
|
||||||
<StackPanel
|
|
||||||
Margin="10,5"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Orientation="Vertical"
|
|
||||||
Spacing="10">
|
|
||||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabSystemCore}" />
|
|
||||||
<StackPanel Margin="10,0,0,0" Orientation="Vertical">
|
|
||||||
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
|
|
||||||
<TextBlock VerticalAlignment="Center"
|
|
||||||
Text="{locale:Locale SettingsTabSystemSystemRegion}"
|
|
||||||
Width="250" />
|
|
||||||
<ComboBox SelectedIndex="{Binding Region}"
|
|
||||||
ToolTip.Tip="{locale:Locale RegionTooltip}"
|
|
||||||
HorizontalContentAlignment="Left"
|
|
||||||
Width="350">
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionJapan}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionUSA}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionEurope}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionAustralia}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionChina}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionKorea}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionTaiwan}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
</ComboBox>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
|
|
||||||
<TextBlock VerticalAlignment="Center"
|
|
||||||
Text="{locale:Locale SettingsTabSystemSystemLanguage}"
|
|
||||||
ToolTip.Tip="{locale:Locale LanguageTooltip}"
|
|
||||||
Width="250" />
|
|
||||||
<ComboBox SelectedIndex="{Binding Language}"
|
|
||||||
ToolTip.Tip="{locale:Locale LanguageTooltip}"
|
|
||||||
HorizontalContentAlignment="Left"
|
|
||||||
Width="350">
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageJapanese}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock
|
|
||||||
Text="{locale:Locale SettingsTabSystemSystemLanguageAmericanEnglish}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageFrench}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageGerman}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageItalian}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageSpanish}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageChinese}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageKorean}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageDutch}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguagePortuguese}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageRussian}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageTaiwanese}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock
|
|
||||||
Text="{locale:Locale SettingsTabSystemSystemLanguageBritishEnglish}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock
|
|
||||||
Text="{locale:Locale SettingsTabSystemSystemLanguageCanadianFrench}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock
|
|
||||||
Text="{locale:Locale SettingsTabSystemSystemLanguageLatinAmericanSpanish}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock
|
|
||||||
Text="{locale:Locale SettingsTabSystemSystemLanguageSimplifiedChinese}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock
|
|
||||||
Text="{locale:Locale SettingsTabSystemSystemLanguageTraditionalChinese}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock
|
|
||||||
Text="{locale:Locale SettingsTabSystemSystemLanguageBrazilianPortuguese}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
</ComboBox>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
|
|
||||||
<TextBlock VerticalAlignment="Center"
|
|
||||||
Text="{locale:Locale SettingsTabSystemSystemTimeZone}"
|
|
||||||
ToolTip.Tip="{locale:Locale TimezoneTooltip}"
|
|
||||||
Width="250" />
|
|
||||||
<AutoCompleteBox
|
|
||||||
Name="TimeZoneBox"
|
|
||||||
Width="350"
|
|
||||||
MaxDropDownHeight="500"
|
|
||||||
FilterMode="Contains"
|
|
||||||
Items="{Binding TimeZones}"
|
|
||||||
SelectionChanged="TimeZoneBox_OnSelectionChanged"
|
|
||||||
Text="{Binding Path=TimeZone, Mode=OneWay}"
|
|
||||||
TextChanged="TimeZoneBox_OnTextChanged"
|
|
||||||
ValueMemberBinding="{ReflectionBinding TzMultiBinding}"
|
|
||||||
ToolTip.Tip="{locale:Locale TimezoneTooltip}" />
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
|
|
||||||
<TextBlock VerticalAlignment="Center"
|
|
||||||
Text="{locale:Locale SettingsTabSystemSystemTime}"
|
|
||||||
ToolTip.Tip="{locale:Locale TimeTooltip}"
|
|
||||||
Width="250"/>
|
|
||||||
<DatePicker VerticalAlignment="Center" SelectedDate="{Binding DateOffset}"
|
|
||||||
ToolTip.Tip="{locale:Locale TimeTooltip}"
|
|
||||||
Width="350" />
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Margin="250,0,0,10" Orientation="Horizontal">
|
|
||||||
<TimePicker
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
ClockIdentifier="24HourClock"
|
|
||||||
SelectedTime="{Binding TimeOffset}"
|
|
||||||
Width="350"
|
|
||||||
ToolTip.Tip="{locale:Locale TimeTooltip}" />
|
|
||||||
</StackPanel>
|
|
||||||
<CheckBox IsChecked="{Binding EnableVsync}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemEnableVsync}"
|
|
||||||
ToolTip.Tip="{locale:Locale VSyncToggleTooltip}" />
|
|
||||||
</CheckBox>
|
|
||||||
<CheckBox IsChecked="{Binding EnableFsIntegrityChecks}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemEnableFsIntegrityChecks}"
|
|
||||||
ToolTip.Tip="{locale:Locale FsIntegrityToggleTooltip}" />
|
|
||||||
</CheckBox>
|
|
||||||
</StackPanel>
|
|
||||||
<Separator Height="1" />
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabSystemHacks}" />
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemHacksNote}" />
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel
|
|
||||||
Margin="10,0,0,0"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Orientation="Vertical">
|
|
||||||
<CheckBox IsChecked="{Binding ExpandDramSize}"
|
|
||||||
ToolTip.Tip="{locale:Locale DRamTooltip}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemExpandDramSize}" />
|
|
||||||
</CheckBox>
|
|
||||||
<CheckBox IsChecked="{Binding IgnoreMissingServices}"
|
|
||||||
ToolTip.Tip="{locale:Locale IgnoreMissingServicesTooltip}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemIgnoreMissingServices}" />
|
|
||||||
</CheckBox>
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
</ScrollViewer>
|
|
||||||
<ScrollViewer
|
|
||||||
Name="CpuPage"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
HorizontalScrollBarVisibility="Disabled"
|
|
||||||
VerticalScrollBarVisibility="Auto">
|
|
||||||
<Border Classes="settings">
|
|
||||||
<StackPanel
|
|
||||||
Margin="10,5"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Orientation="Vertical"
|
|
||||||
Spacing="10">
|
|
||||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabCpuCache}" />
|
|
||||||
<StackPanel
|
|
||||||
Margin="10,0,0,0"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Orientation="Vertical">
|
|
||||||
<CheckBox IsChecked="{Binding EnablePptc}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemEnablePptc}"
|
|
||||||
ToolTip.Tip="{locale:Locale PptcToggleTooltip}" />
|
|
||||||
</CheckBox>
|
|
||||||
</StackPanel>
|
|
||||||
<Separator Height="1" />
|
|
||||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabCpuMemory}" />
|
|
||||||
<StackPanel
|
|
||||||
Margin="10,0,0,0"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Orientation="Vertical">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBlock VerticalAlignment="Center"
|
|
||||||
Text="{locale:Locale SettingsTabSystemMemoryManagerMode}"
|
|
||||||
ToolTip.Tip="{locale:Locale MemoryManagerTooltip}"
|
|
||||||
Width="250" />
|
|
||||||
<ComboBox SelectedIndex="{Binding MemoryMode}"
|
|
||||||
ToolTip.Tip="{locale:Locale MemoryManagerTooltip}"
|
|
||||||
HorizontalContentAlignment="Left"
|
|
||||||
Width="350">
|
|
||||||
<ComboBoxItem
|
|
||||||
ToolTip.Tip="{locale:Locale MemoryManagerSoftwareTooltip}">
|
|
||||||
<TextBlock
|
|
||||||
Text="{locale:Locale SettingsTabSystemMemoryManagerModeSoftware}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem
|
|
||||||
ToolTip.Tip="{locale:Locale MemoryManagerHostTooltip}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemMemoryManagerModeHost}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem
|
|
||||||
ToolTip.Tip="{locale:Locale MemoryManagerUnsafeTooltip}">
|
|
||||||
<TextBlock
|
|
||||||
Text="{locale:Locale SettingsTabSystemMemoryManagerModeHostUnchecked}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
</ComboBox>
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
</ScrollViewer>
|
|
||||||
<ScrollViewer
|
|
||||||
Name="GraphicsPage"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
HorizontalScrollBarVisibility="Disabled"
|
|
||||||
VerticalScrollBarVisibility="Auto">
|
|
||||||
<Border Classes="settings">
|
|
||||||
<StackPanel
|
|
||||||
Margin="10,5"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Orientation="Vertical"
|
|
||||||
Spacing="10">
|
|
||||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGraphicsAPI}" />
|
|
||||||
<StackPanel Margin="10,0,0,0" Orientation="Vertical" Spacing="10">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBlock VerticalAlignment="Center"
|
|
||||||
ToolTip.Tip="{locale:Locale SettingsTabGraphicsBackendTooltip}"
|
|
||||||
Text="{locale:Locale SettingsTabGraphicsBackend}"
|
|
||||||
Width="250" />
|
|
||||||
<ComboBox Width="350"
|
|
||||||
HorizontalContentAlignment="Left"
|
|
||||||
ToolTip.Tip="{locale:Locale SettingsTabGraphicsBackendTooltip}"
|
|
||||||
SelectedIndex="{Binding GraphicsBackendIndex}">
|
|
||||||
<ComboBoxItem IsVisible="{Binding IsVulkanAvailable}">
|
|
||||||
<TextBlock Text="Vulkan" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem IsEnabled="{Binding IsOpenGLAvailable}">
|
|
||||||
<TextBlock Text="OpenGL" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
</ComboBox>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Orientation="Horizontal" IsVisible="{Binding IsVulkanSelected}">
|
|
||||||
<TextBlock VerticalAlignment="Center"
|
|
||||||
ToolTip.Tip="{locale:Locale SettingsTabGraphicsPreferredGpuTooltip}"
|
|
||||||
Text="{locale:Locale SettingsTabGraphicsPreferredGpu}"
|
|
||||||
Width="250" />
|
|
||||||
<ComboBox Width="350"
|
|
||||||
HorizontalContentAlignment="Left"
|
|
||||||
ToolTip.Tip="{locale:Locale SettingsTabGraphicsPreferredGpuTooltip}"
|
|
||||||
SelectedIndex="{Binding PreferredGpuIndex}"
|
|
||||||
Items="{Binding AvailableGpus}"/>
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
<Separator Height="1" />
|
|
||||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGraphicsFeatures}" />
|
|
||||||
<StackPanel Margin="10,0,0,0" Orientation="Vertical" Spacing="10">
|
|
||||||
<StackPanel Orientation="Vertical">
|
|
||||||
<CheckBox IsChecked="{Binding EnableShaderCache}"
|
|
||||||
ToolTip.Tip="{locale:Locale ShaderCacheToggleTooltip}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsEnableShaderCache}" />
|
|
||||||
</CheckBox>
|
|
||||||
<CheckBox IsChecked="{Binding EnableTextureRecompression}"
|
|
||||||
ToolTip.Tip="{locale:Locale SettingsEnableTextureRecompressionTooltip}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsEnableTextureRecompression}" />
|
|
||||||
</CheckBox>
|
|
||||||
<CheckBox IsChecked="{Binding EnableMacroHLE}"
|
|
||||||
ToolTip.Tip="{locale:Locale SettingsEnableMacroHLETooltip}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsEnableMacroHLE}" />
|
|
||||||
</CheckBox>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBlock VerticalAlignment="Center"
|
|
||||||
ToolTip.Tip="{locale:Locale ResolutionScaleTooltip}"
|
|
||||||
Text="{locale:Locale SettingsTabGraphicsResolutionScale}"
|
|
||||||
Width="250" />
|
|
||||||
<ComboBox SelectedIndex="{Binding ResolutionScale}"
|
|
||||||
Width="350"
|
|
||||||
HorizontalContentAlignment="Left"
|
|
||||||
ToolTip.Tip="{locale:Locale ResolutionScaleTooltip}">
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScaleCustom}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScaleNative}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScale2x}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScale3x}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScale4x}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
</ComboBox>
|
|
||||||
<ui:NumberBox
|
|
||||||
Margin="10,0,0,0"
|
|
||||||
ToolTip.Tip="{locale:Locale ResolutionScaleEntryTooltip}"
|
|
||||||
MinWidth="150"
|
|
||||||
SmallChange="0.1"
|
|
||||||
LargeChange="1"
|
|
||||||
SimpleNumberFormat="F2"
|
|
||||||
SpinButtonPlacementMode="Inline"
|
|
||||||
IsVisible="{Binding IsCustomResolutionScaleActive}"
|
|
||||||
Maximum="100"
|
|
||||||
Minimum="0.1"
|
|
||||||
Value="{Binding CustomResolutionScale}" />
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBlock VerticalAlignment="Center"
|
|
||||||
ToolTip.Tip="{locale:Locale AnisotropyTooltip}"
|
|
||||||
Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering}"
|
|
||||||
Width="250" />
|
|
||||||
<ComboBox SelectedIndex="{Binding MaxAnisotropy}"
|
|
||||||
Width="350"
|
|
||||||
HorizontalContentAlignment="Left"
|
|
||||||
ToolTip.Tip="{locale:Locale AnisotropyTooltip}">
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock
|
|
||||||
Text="{locale:Locale SettingsTabGraphicsAnisotropicFilteringAuto}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering2x}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering4x}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering8x}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock
|
|
||||||
Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering16x}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
</ComboBox>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBlock VerticalAlignment="Center"
|
|
||||||
ToolTip.Tip="{locale:Locale AspectRatioTooltip}"
|
|
||||||
Text="{locale:Locale SettingsTabGraphicsAspectRatio}"
|
|
||||||
Width="250" />
|
|
||||||
<ComboBox SelectedIndex="{Binding AspectRatio}"
|
|
||||||
Width="350"
|
|
||||||
HorizontalContentAlignment="Left"
|
|
||||||
ToolTip.Tip="{locale:Locale AspectRatioTooltip}">
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio4x3}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio16x9}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio16x10}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio21x9}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio32x9}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatioStretch}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
</ComboBox>
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel
|
|
||||||
Margin="10,0,0,0"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Orientation="Vertical"
|
|
||||||
Spacing="10">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBlock VerticalAlignment="Center"
|
|
||||||
ToolTip.Tip="{locale:Locale GraphicsBackendThreadingTooltip}"
|
|
||||||
Text="{locale:Locale SettingsTabGraphicsBackendMultithreading}"
|
|
||||||
Width="250" />
|
|
||||||
<ComboBox Width="350"
|
|
||||||
HorizontalContentAlignment="Left"
|
|
||||||
ToolTip.Tip="{locale:Locale GalThreadingTooltip}"
|
|
||||||
SelectedIndex="{Binding GraphicsBackendMultithreadingIndex}">
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale CommonAuto}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale CommonOff}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale CommonOn}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
</ComboBox>
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
<Separator Height="1" />
|
|
||||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGraphicsDeveloperOptions}" />
|
|
||||||
<StackPanel
|
|
||||||
Margin="10,0,0,0"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Orientation="Vertical"
|
|
||||||
Spacing="10">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBlock VerticalAlignment="Center"
|
|
||||||
ToolTip.Tip="{locale:Locale ShaderDumpPathTooltip}"
|
|
||||||
Text="{locale:Locale SettingsTabGraphicsShaderDumpPath}"
|
|
||||||
Width="250" />
|
|
||||||
<TextBox Text="{Binding ShaderDumpPath}"
|
|
||||||
Width="350"
|
|
||||||
ToolTip.Tip="{locale:Locale ShaderDumpPathTooltip}" />
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
</ScrollViewer>
|
|
||||||
<ScrollViewer
|
|
||||||
Name="AudioPage"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
HorizontalScrollBarVisibility="Disabled"
|
|
||||||
VerticalScrollBarVisibility="Auto">
|
|
||||||
<Border Classes="settings">
|
|
||||||
<StackPanel
|
|
||||||
Margin="10,5"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Orientation="Vertical"
|
|
||||||
Spacing="10">
|
|
||||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabAudio}" />
|
|
||||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
|
||||||
<TextBlock VerticalAlignment="Center"
|
|
||||||
Text="{locale:Locale SettingsTabSystemAudioBackend}"
|
|
||||||
ToolTip.Tip="{locale:Locale AudioBackendTooltip}"
|
|
||||||
Width="250" />
|
|
||||||
<ComboBox SelectedIndex="{Binding AudioBackend}"
|
|
||||||
Width="350"
|
|
||||||
HorizontalContentAlignment="Left">
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendDummy}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem IsEnabled="{Binding IsOpenAlEnabled}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendOpenAL}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem IsEnabled="{Binding IsSoundIoEnabled}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendSoundIO}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem IsEnabled="{Binding IsSDL2Enabled}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendSDL2}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
</ComboBox>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
|
||||||
<TextBlock VerticalAlignment="Center"
|
|
||||||
Text="{locale:Locale SettingsTabSystemAudioVolume}"
|
|
||||||
ToolTip.Tip="{locale:Locale AudioVolumeTooltip}"
|
|
||||||
Width="250" />
|
|
||||||
<ui:NumberBox Value="{Binding Volume}"
|
|
||||||
ToolTip.Tip="{locale:Locale AudioVolumeTooltip}"
|
|
||||||
Width="350"
|
|
||||||
SmallChange="1"
|
|
||||||
LargeChange="10"
|
|
||||||
SimpleNumberFormat="F0"
|
|
||||||
SpinButtonPlacementMode="Inline"
|
|
||||||
Minimum="0"
|
|
||||||
Maximum="100" />
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
|
||||||
<Slider Value="{Binding Volume}"
|
|
||||||
Margin="250,0,0,0"
|
|
||||||
ToolTip.Tip="{locale:Locale AudioVolumeTooltip}"
|
|
||||||
Minimum="0"
|
|
||||||
Maximum="100"
|
|
||||||
SmallChange="5"
|
|
||||||
TickFrequency="5"
|
|
||||||
IsSnapToTickEnabled="True"
|
|
||||||
LargeChange="10"
|
|
||||||
Width="350" />
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
</ScrollViewer>
|
|
||||||
<ScrollViewer
|
|
||||||
Name="NetworkPage"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
HorizontalScrollBarVisibility="Disabled"
|
|
||||||
VerticalScrollBarVisibility="Auto">
|
|
||||||
<Border Classes="settings">
|
|
||||||
<StackPanel
|
|
||||||
Margin="10,5"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Orientation="Vertical"
|
|
||||||
Spacing="10">
|
|
||||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabNetworkConnection}" />
|
|
||||||
<CheckBox Margin="10,0,0,0" IsChecked="{Binding EnableInternetAccess}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabSystemEnableInternetAccess}"
|
|
||||||
ToolTip.Tip="{locale:Locale EnableInternetAccessTooltip}" />
|
|
||||||
</CheckBox>
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
</ScrollViewer>
|
|
||||||
<ScrollViewer
|
|
||||||
Name="LoggingPage"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
HorizontalScrollBarVisibility="Disabled"
|
|
||||||
VerticalScrollBarVisibility="Auto">
|
|
||||||
<Border Classes="settings">
|
|
||||||
<StackPanel
|
|
||||||
Margin="10,5"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Orientation="Vertical"
|
|
||||||
Spacing="10">
|
|
||||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabLoggingLogging}" />
|
|
||||||
<StackPanel Margin="10,0,0,0" Orientation="Vertical">
|
|
||||||
<CheckBox IsChecked="{Binding EnableFileLog}"
|
|
||||||
ToolTip.Tip="{locale:Locale FileLogTooltip}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableLoggingToFile}" />
|
|
||||||
</CheckBox>
|
|
||||||
<CheckBox IsChecked="{Binding EnableStub}"
|
|
||||||
ToolTip.Tip="{locale:Locale StubLogTooltip}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableStubLogs}" />
|
|
||||||
</CheckBox>
|
|
||||||
<CheckBox IsChecked="{Binding EnableInfo}"
|
|
||||||
ToolTip.Tip="{locale:Locale InfoLogTooltip}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableInfoLogs}" />
|
|
||||||
</CheckBox>
|
|
||||||
<CheckBox IsChecked="{Binding EnableWarn}"
|
|
||||||
ToolTip.Tip="{locale:Locale WarnLogTooltip}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableWarningLogs}" />
|
|
||||||
</CheckBox>
|
|
||||||
<CheckBox IsChecked="{Binding EnableError}"
|
|
||||||
ToolTip.Tip="{locale:Locale ErrorLogTooltip}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableErrorLogs}" />
|
|
||||||
</CheckBox>
|
|
||||||
<CheckBox IsChecked="{Binding EnableTrace}"
|
|
||||||
ToolTip.Tip="{locale:Locale TraceLogTooltip}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableTraceLogs}" />
|
|
||||||
</CheckBox>
|
|
||||||
<CheckBox IsChecked="{Binding EnableGuest}"
|
|
||||||
ToolTip.Tip="{locale:Locale GuestLogTooltip}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableGuestLogs}" />
|
|
||||||
</CheckBox>
|
|
||||||
</StackPanel>
|
|
||||||
<Separator Height="1" />
|
|
||||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabLoggingDeveloperOptions}" />
|
|
||||||
<StackPanel
|
|
||||||
Margin="10,0,0,0"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Orientation="Vertical"
|
|
||||||
Spacing="10">
|
|
||||||
<StackPanel Orientation="Vertical">
|
|
||||||
<CheckBox IsChecked="{Binding EnableDebug}"
|
|
||||||
ToolTip.Tip="{locale:Locale DebugLogTooltip}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableDebugLogs}" />
|
|
||||||
</CheckBox>
|
|
||||||
<CheckBox IsChecked="{Binding EnableFsAccessLog}"
|
|
||||||
ToolTip.Tip="{locale:Locale FileAccessLogTooltip}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableFsAccessLogs}" />
|
|
||||||
</CheckBox>
|
|
||||||
<StackPanel Margin="0,10,0,0" Orientation="Horizontal" VerticalAlignment="Stretch">
|
|
||||||
<TextBlock VerticalAlignment="Center"
|
|
||||||
ToolTip.Tip="{locale:Locale FSAccessLogModeTooltip}"
|
|
||||||
Text="{locale:Locale SettingsTabLoggingFsGlobalAccessLogMode}"
|
|
||||||
Width="285" />
|
|
||||||
<ui:NumberBox
|
|
||||||
Maximum="3"
|
|
||||||
Minimum="0"
|
|
||||||
Width="150"
|
|
||||||
SpinButtonPlacementMode="Inline"
|
|
||||||
SmallChange="1"
|
|
||||||
LargeChange="1"
|
|
||||||
Value="{Binding FsGlobalAccessLogMode}" />
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Margin="0,10,0,0" Orientation="Horizontal">
|
|
||||||
<TextBlock VerticalAlignment="Center"
|
|
||||||
Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevel}"
|
|
||||||
ToolTip.Tip="{locale:Locale OpenGlLogLevel}"
|
|
||||||
Width="285" />
|
|
||||||
<ComboBox SelectedIndex="{Binding OpenglDebugLevel}"
|
|
||||||
Width="150"
|
|
||||||
HorizontalContentAlignment="Left"
|
|
||||||
ToolTip.Tip="{locale:Locale OpenGlLogLevel}">
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelNone}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelError}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock
|
|
||||||
Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelPerformance}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelAll}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
</ComboBox>
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
</ScrollViewer>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<ui:NavigationView Grid.Row="1"
|
<ui:NavigationView Grid.Row="1"
|
||||||
IsSettingsVisible="False"
|
IsSettingsVisible="False"
|
||||||
@@ -962,7 +102,7 @@
|
|||||||
Spacing="10"
|
Spacing="10"
|
||||||
Orientation="Horizontal"
|
Orientation="Horizontal"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
ReverseOrder="{ReflectionBinding IsMacOS}">
|
ReverseOrder="{Binding IsMacOS}">
|
||||||
<Button
|
<Button
|
||||||
HotKey="Enter"
|
HotKey="Enter"
|
||||||
Classes="accent"
|
Classes="accent"
|
||||||
|
@@ -1,49 +1,29 @@
|
|||||||
using Avalonia.Controls;
|
|
||||||
using Avalonia.Controls.Primitives;
|
|
||||||
using Avalonia.Data;
|
|
||||||
using Avalonia.Data.Converters;
|
|
||||||
using Avalonia.Input;
|
|
||||||
using Avalonia.Interactivity;
|
|
||||||
using FluentAvalonia.Core;
|
using FluentAvalonia.Core;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.UI.Controls;
|
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
|
||||||
using Ryujinx.Ava.UI.ViewModels;
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using Ryujinx.Input;
|
|
||||||
using Ryujinx.Input.Assigner;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.ComponentModel;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using TimeZone = Ryujinx.Ava.UI.Models.TimeZone;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Windows
|
namespace Ryujinx.Ava.UI.Windows
|
||||||
{
|
{
|
||||||
public partial class SettingsWindow : StyleableWindow
|
public partial class SettingsWindow : StyleableWindow
|
||||||
{
|
{
|
||||||
private ButtonKeyAssigner _currentAssigner;
|
|
||||||
|
|
||||||
internal SettingsViewModel ViewModel { get; set; }
|
internal SettingsViewModel ViewModel { get; set; }
|
||||||
|
|
||||||
public SettingsWindow(VirtualFileSystem virtualFileSystem, ContentManager contentManager)
|
public SettingsWindow(VirtualFileSystem virtualFileSystem, ContentManager contentManager)
|
||||||
{
|
{
|
||||||
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance[LocaleKeys.Settings]}";
|
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance[LocaleKeys.Settings]}";
|
||||||
|
|
||||||
ViewModel = new SettingsViewModel(virtualFileSystem, contentManager, this);
|
ViewModel = new SettingsViewModel(virtualFileSystem, contentManager);
|
||||||
DataContext = ViewModel;
|
DataContext = ViewModel;
|
||||||
|
|
||||||
|
ViewModel.CloseWindow += Close;
|
||||||
|
ViewModel.SaveSettingsEvent += SaveSettings;
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Load();
|
Load();
|
||||||
|
|
||||||
FuncMultiValueConverter<string, string> converter = new(parts => string.Format("{0} {1} {2}", parts.ToArray()).Trim());
|
|
||||||
MultiBinding tzMultiBinding = new() { Converter = converter };
|
|
||||||
tzMultiBinding.Bindings.Add(new Binding("UtcDifference"));
|
|
||||||
tzMultiBinding.Bindings.Add(new Binding("Location"));
|
|
||||||
tzMultiBinding.Bindings.Add(new Binding("Abbreviation"));
|
|
||||||
|
|
||||||
TimeZoneBox.ValueMemberBinding = tzMultiBinding;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SettingsWindow()
|
public SettingsWindow()
|
||||||
@@ -55,6 +35,16 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
Load();
|
Load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SaveSettings()
|
||||||
|
{
|
||||||
|
InputPage.ControllerSettings?.SaveCurrentProfile();
|
||||||
|
|
||||||
|
if (Owner is MainWindow window && ViewModel.DirectoryChanged)
|
||||||
|
{
|
||||||
|
window.ViewModel.LoadApplications();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void Load()
|
private void Load()
|
||||||
{
|
{
|
||||||
Pages.Children.Clear();
|
Pages.Children.Clear();
|
||||||
@@ -62,152 +52,52 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
NavPanel.SelectedItem = NavPanel.MenuItems.ElementAt(0);
|
NavPanel.SelectedItem = NavPanel.MenuItems.ElementAt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Button_Checked(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (sender is ToggleButton button)
|
|
||||||
{
|
|
||||||
if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_currentAssigner == null && (bool)button.IsChecked)
|
|
||||||
{
|
|
||||||
_currentAssigner = new ButtonKeyAssigner(button);
|
|
||||||
|
|
||||||
FocusManager.Instance.Focus(this, NavigationMethod.Pointer);
|
|
||||||
|
|
||||||
PointerPressed += MouseClick;
|
|
||||||
|
|
||||||
IKeyboard keyboard = (IKeyboard)ViewModel.AvaloniaKeyboardDriver.GetGamepad(ViewModel.AvaloniaKeyboardDriver.GamepadsIds[0]);
|
|
||||||
IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard);
|
|
||||||
|
|
||||||
_currentAssigner.GetInputAndAssign(assigner);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (_currentAssigner != null)
|
|
||||||
{
|
|
||||||
ToggleButton oldButton = _currentAssigner.ToggledButton;
|
|
||||||
|
|
||||||
_currentAssigner.Cancel();
|
|
||||||
_currentAssigner = null;
|
|
||||||
|
|
||||||
button.IsChecked = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Button_Unchecked(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
_currentAssigner?.Cancel();
|
|
||||||
_currentAssigner = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MouseClick(object sender, PointerPressedEventArgs e)
|
|
||||||
{
|
|
||||||
bool shouldUnbind = false;
|
|
||||||
|
|
||||||
if (e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed)
|
|
||||||
{
|
|
||||||
shouldUnbind = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
_currentAssigner?.Cancel(shouldUnbind);
|
|
||||||
|
|
||||||
PointerPressed -= MouseClick;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void NavPanelOnSelectionChanged(object sender, NavigationViewSelectionChangedEventArgs e)
|
private void NavPanelOnSelectionChanged(object sender, NavigationViewSelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.SelectedItem is NavigationViewItem navitem)
|
if (e.SelectedItem is NavigationViewItem navItem && navItem.Tag is not null)
|
||||||
{
|
{
|
||||||
NavPanel.Content = navitem.Tag.ToString() switch
|
switch (navItem.Tag.ToString())
|
||||||
{
|
{
|
||||||
"UiPage" => UiPage,
|
case "UiPage":
|
||||||
"InputPage" => InputPage,
|
UiPage.ViewModel = ViewModel;
|
||||||
"HotkeysPage" => HotkeysPage,
|
NavPanel.Content = UiPage;
|
||||||
"SystemPage" => SystemPage,
|
break;
|
||||||
"CpuPage" => CpuPage,
|
case "InputPage":
|
||||||
"GraphicsPage" => GraphicsPage,
|
NavPanel.Content = InputPage;
|
||||||
"AudioPage" => AudioPage,
|
break;
|
||||||
"NetworkPage" => NetworkPage,
|
case "HotkeysPage":
|
||||||
"LoggingPage" => LoggingPage,
|
NavPanel.Content = HotkeysPage;
|
||||||
_ => throw new NotImplementedException()
|
break;
|
||||||
};
|
case "SystemPage":
|
||||||
}
|
SystemPage.ViewModel = ViewModel;
|
||||||
}
|
NavPanel.Content = SystemPage;
|
||||||
|
break;
|
||||||
private async void AddButton_OnClick(object sender, RoutedEventArgs e)
|
case "CpuPage":
|
||||||
{
|
NavPanel.Content = CpuPage;
|
||||||
string path = PathBox.Text;
|
break;
|
||||||
|
case "GraphicsPage":
|
||||||
if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path) && !ViewModel.GameDirectories.Contains(path))
|
NavPanel.Content = GraphicsPage;
|
||||||
{
|
break;
|
||||||
ViewModel.GameDirectories.Add(path);
|
case "AudioPage":
|
||||||
ViewModel.DirectoryChanged = true;
|
NavPanel.Content = AudioPage;
|
||||||
}
|
break;
|
||||||
else
|
case "NetworkPage":
|
||||||
{
|
NavPanel.Content = NetworkPage;
|
||||||
path = await new OpenFolderDialog().ShowAsync(this);
|
break;
|
||||||
|
case "LoggingPage":
|
||||||
if (!string.IsNullOrWhiteSpace(path))
|
NavPanel.Content = LoggingPage;
|
||||||
{
|
break;
|
||||||
ViewModel.GameDirectories.Add(path);
|
default:
|
||||||
ViewModel.DirectoryChanged = true;
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveButton_OnClick(object sender, RoutedEventArgs e)
|
protected override void OnClosing(CancelEventArgs e)
|
||||||
{
|
{
|
||||||
int oldIndex = GameList.SelectedIndex;
|
HotkeysPage.Dispose();
|
||||||
|
InputPage.Dispose();
|
||||||
foreach (string path in new List<string>(GameList.SelectedItems.Cast<string>()))
|
base.OnClosing(e);
|
||||||
{
|
|
||||||
ViewModel.GameDirectories.Remove(path);
|
|
||||||
ViewModel.DirectoryChanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GameList.ItemCount > 0)
|
|
||||||
{
|
|
||||||
GameList.SelectedIndex = oldIndex < GameList.ItemCount ? oldIndex : 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TimeZoneBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
||||||
{
|
|
||||||
if (e.AddedItems != null && e.AddedItems.Count > 0)
|
|
||||||
{
|
|
||||||
if (e.AddedItems[0] is TimeZone timeZone)
|
|
||||||
{
|
|
||||||
e.Handled = true;
|
|
||||||
|
|
||||||
ViewModel.ValidateAndSetTimeZone(timeZone.Location);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TimeZoneBox_OnTextChanged(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if (sender is AutoCompleteBox box)
|
|
||||||
{
|
|
||||||
if (box.SelectedItem != null && box.SelectedItem is TimeZone timeZone)
|
|
||||||
{
|
|
||||||
ViewModel.ValidateAndSetTimeZone(timeZone.Location);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnClosed(EventArgs e)
|
|
||||||
{
|
|
||||||
ControllerSettings.Dispose();
|
|
||||||
|
|
||||||
_currentAssigner?.Cancel();
|
|
||||||
_currentAssigner = null;
|
|
||||||
|
|
||||||
base.OnClosed(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -7,9 +7,9 @@ namespace Ryujinx.Common.Logging
|
|||||||
AudioRenderer,
|
AudioRenderer,
|
||||||
Configuration,
|
Configuration,
|
||||||
Cpu,
|
Cpu,
|
||||||
Font,
|
|
||||||
Emulation,
|
Emulation,
|
||||||
FFmpeg,
|
FFmpeg,
|
||||||
|
Font,
|
||||||
Gpu,
|
Gpu,
|
||||||
Hid,
|
Hid,
|
||||||
Host1x,
|
Host1x,
|
||||||
@@ -66,6 +66,7 @@ namespace Ryujinx.Common.Logging
|
|||||||
ServiceVi,
|
ServiceVi,
|
||||||
SurfaceFlinger,
|
SurfaceFlinger,
|
||||||
TamperMachine,
|
TamperMachine,
|
||||||
|
Ui,
|
||||||
Vic
|
Vic
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -29,7 +29,7 @@ namespace Ryujinx.Common.Logging
|
|||||||
files[i].Delete();
|
files[i].Delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
string version = ReleaseInformations.GetVersion();
|
string version = ReleaseInformation.GetVersion();
|
||||||
|
|
||||||
// Get path for the current time
|
// Get path for the current time
|
||||||
path = Path.Combine(logDir.FullName, $"Ryujinx_{version}_{DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")}.log");
|
path = Path.Combine(logDir.FullName, $"Ryujinx_{version}_{DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")}.log");
|
||||||
|
@@ -5,7 +5,7 @@ using System.Reflection;
|
|||||||
namespace Ryujinx.Common
|
namespace Ryujinx.Common
|
||||||
{
|
{
|
||||||
// DO NOT EDIT, filled by CI
|
// DO NOT EDIT, filled by CI
|
||||||
public static class ReleaseInformations
|
public static class ReleaseInformation
|
||||||
{
|
{
|
||||||
private const string FlatHubChannelOwner = "flathub";
|
private const string FlatHubChannelOwner = "flathub";
|
||||||
|
|
@@ -123,6 +123,8 @@ namespace Ryujinx.HLE.HOS
|
|||||||
|
|
||||||
internal LibHacHorizonManager LibHacHorizonManager { get; private set; }
|
internal LibHacHorizonManager LibHacHorizonManager { get; private set; }
|
||||||
|
|
||||||
|
internal ServiceTable ServiceTable { get; private set; }
|
||||||
|
|
||||||
public bool IsPaused { get; private set; }
|
public bool IsPaused { get; private set; }
|
||||||
|
|
||||||
public Horizon(Switch device)
|
public Horizon(Switch device)
|
||||||
@@ -326,6 +328,7 @@ namespace Ryujinx.HLE.HOS
|
|||||||
|
|
||||||
private void StartNewServices()
|
private void StartNewServices()
|
||||||
{
|
{
|
||||||
|
ServiceTable = new ServiceTable();
|
||||||
var services = ServiceTable.GetServices(new HorizonOptions(Device.Configuration.IgnoreMissingServices));
|
var services = ServiceTable.GetServices(new HorizonOptions(Device.Configuration.IgnoreMissingServices));
|
||||||
|
|
||||||
foreach (var service in services)
|
foreach (var service in services)
|
||||||
|
@@ -182,6 +182,8 @@ namespace Ryujinx.HLE.HOS
|
|||||||
byte[] arguments = null,
|
byte[] arguments = null,
|
||||||
params IExecutable[] executables)
|
params IExecutable[] executables)
|
||||||
{
|
{
|
||||||
|
context.Device.System.ServiceTable.WaitServicesReady();
|
||||||
|
|
||||||
LibHac.Result rc = metaData.GetNpdm(out var npdm);
|
LibHac.Result rc = metaData.GetNpdm(out var npdm);
|
||||||
|
|
||||||
if (rc.IsFailure())
|
if (rc.IsFailure())
|
||||||
|
@@ -1,19 +0,0 @@
|
|||||||
using Ryujinx.HLE.HOS.Services.Lm.LogService;
|
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Lm
|
|
||||||
{
|
|
||||||
[Service("lm")]
|
|
||||||
class ILogService : IpcService
|
|
||||||
{
|
|
||||||
public ILogService(ServiceCtx context) { }
|
|
||||||
|
|
||||||
[CommandHipc(0)]
|
|
||||||
// Initialize(u64, pid) -> object<nn::lm::ILogger>
|
|
||||||
public ResultCode Initialize(ServiceCtx context)
|
|
||||||
{
|
|
||||||
MakeObject(context, new ILogger());
|
|
||||||
|
|
||||||
return ResultCode.Success;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,109 +0,0 @@
|
|||||||
using Ryujinx.Common.Logging;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Lm.LogService
|
|
||||||
{
|
|
||||||
class ILogger : IpcService
|
|
||||||
{
|
|
||||||
public ILogger() { }
|
|
||||||
|
|
||||||
[CommandHipc(0)]
|
|
||||||
// Log(buffer<unknown, 0x21>)
|
|
||||||
public ResultCode Log(ServiceCtx context)
|
|
||||||
{
|
|
||||||
Logger.Guest?.Print(LogClass.ServiceLm, LogImpl(context));
|
|
||||||
|
|
||||||
return ResultCode.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string LogImpl(ServiceCtx context)
|
|
||||||
{
|
|
||||||
(ulong bufPos, ulong bufSize) = context.Request.GetBufferType0x21();
|
|
||||||
|
|
||||||
byte[] logBuffer = new byte[bufSize];
|
|
||||||
|
|
||||||
context.Memory.Read(bufPos, logBuffer);
|
|
||||||
|
|
||||||
using MemoryStream ms = new MemoryStream(logBuffer);
|
|
||||||
|
|
||||||
BinaryReader reader = new BinaryReader(ms);
|
|
||||||
|
|
||||||
long pid = reader.ReadInt64();
|
|
||||||
long threadContext = reader.ReadInt64();
|
|
||||||
short flags = reader.ReadInt16();
|
|
||||||
byte level = reader.ReadByte();
|
|
||||||
byte verbosity = reader.ReadByte();
|
|
||||||
int payloadLength = reader.ReadInt32();
|
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
|
|
||||||
sb.AppendLine($"Guest Log:\n Log level: {(LmLogLevel)level}");
|
|
||||||
|
|
||||||
while (ms.Position < ms.Length)
|
|
||||||
{
|
|
||||||
int type = ReadEncodedInt(reader);
|
|
||||||
int size = ReadEncodedInt(reader);
|
|
||||||
|
|
||||||
LmLogField field = (LmLogField)type;
|
|
||||||
|
|
||||||
string fieldStr = string.Empty;
|
|
||||||
|
|
||||||
if (field == LmLogField.Start)
|
|
||||||
{
|
|
||||||
reader.ReadBytes(size);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (field == LmLogField.Stop)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (field == LmLogField.Line)
|
|
||||||
{
|
|
||||||
fieldStr = $"{field}: {reader.ReadInt32()}";
|
|
||||||
}
|
|
||||||
else if (field == LmLogField.DropCount)
|
|
||||||
{
|
|
||||||
fieldStr = $"{field}: {reader.ReadInt64()}";
|
|
||||||
}
|
|
||||||
else if (field == LmLogField.Time)
|
|
||||||
{
|
|
||||||
fieldStr = $"{field}: {reader.ReadInt64()}s";
|
|
||||||
}
|
|
||||||
else if (field < LmLogField.Count)
|
|
||||||
{
|
|
||||||
fieldStr = $"{field}: '{Encoding.UTF8.GetString(reader.ReadBytes(size)).TrimEnd()}'";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fieldStr = $"Field{field}: '{Encoding.UTF8.GetString(reader.ReadBytes(size)).TrimEnd()}'";
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.AppendLine($" {fieldStr}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int ReadEncodedInt(BinaryReader reader)
|
|
||||||
{
|
|
||||||
int result = 0;
|
|
||||||
int position = 0;
|
|
||||||
|
|
||||||
byte encoded;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
encoded = reader.ReadByte();
|
|
||||||
|
|
||||||
result += (encoded & 0x7F) << (7 * position);
|
|
||||||
|
|
||||||
position++;
|
|
||||||
|
|
||||||
} while ((encoded & 0x80) != 0);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,18 +0,0 @@
|
|||||||
namespace Ryujinx.HLE.HOS.Services.Lm.LogService
|
|
||||||
{
|
|
||||||
enum LmLogField
|
|
||||||
{
|
|
||||||
Start = 0,
|
|
||||||
Stop = 1,
|
|
||||||
Message = 2,
|
|
||||||
Line = 3,
|
|
||||||
Filename = 4,
|
|
||||||
Function = 5,
|
|
||||||
Module = 6,
|
|
||||||
Thread = 7,
|
|
||||||
DropCount = 8,
|
|
||||||
Time = 9,
|
|
||||||
ProgramName = 10,
|
|
||||||
Count
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
namespace Ryujinx.HLE.HOS.Services.Lm.LogService
|
|
||||||
{
|
|
||||||
enum LmLogLevel
|
|
||||||
{
|
|
||||||
Trace,
|
|
||||||
Info,
|
|
||||||
Warning,
|
|
||||||
Error,
|
|
||||||
Critical
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,182 +0,0 @@
|
|||||||
using MsgPack;
|
|
||||||
using MsgPack.Serialization;
|
|
||||||
using Ryujinx.Common;
|
|
||||||
using Ryujinx.Common.Logging;
|
|
||||||
using Ryujinx.Common.Utilities;
|
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
|
||||||
using Ryujinx.HLE.Utilities;
|
|
||||||
using System;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Prepo
|
|
||||||
{
|
|
||||||
[Service("prepo:a", PrepoServicePermissionLevel.Admin)] // 1.0.0-5.1.0
|
|
||||||
[Service("prepo:a2", PrepoServicePermissionLevel.Admin)] // 6.0.0+
|
|
||||||
[Service("prepo:m", PrepoServicePermissionLevel.Manager)]
|
|
||||||
[Service("prepo:u", PrepoServicePermissionLevel.User)]
|
|
||||||
[Service("prepo:s", PrepoServicePermissionLevel.System)]
|
|
||||||
class IPrepoService : IpcService
|
|
||||||
{
|
|
||||||
private PrepoServicePermissionLevel _permission;
|
|
||||||
private ulong _systemSessionId;
|
|
||||||
|
|
||||||
public IPrepoService(ServiceCtx context, PrepoServicePermissionLevel permission)
|
|
||||||
{
|
|
||||||
_permission = permission;
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandHipc(10100)] // 1.0.0-5.1.0
|
|
||||||
[CommandHipc(10102)] // 6.0.0-9.2.0
|
|
||||||
[CommandHipc(10104)] // 10.0.0+
|
|
||||||
// SaveReport(u64, pid, buffer<u8, 9>, buffer<bytes, 5>)
|
|
||||||
public ResultCode SaveReport(ServiceCtx context)
|
|
||||||
{
|
|
||||||
if ((_permission & PrepoServicePermissionLevel.User) == 0)
|
|
||||||
{
|
|
||||||
return ResultCode.PermissionDenied;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We don't care about the differences since we don't use the play report.
|
|
||||||
return ProcessReport(context, withUserID: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandHipc(10101)] // 1.0.0-5.1.0
|
|
||||||
[CommandHipc(10103)] // 6.0.0-9.2.0
|
|
||||||
[CommandHipc(10105)] // 10.0.0+
|
|
||||||
// SaveReportWithUser(nn::account::Uid, u64, pid, buffer<u8, 9>, buffer<bytes, 5>)
|
|
||||||
public ResultCode SaveReportWithUser(ServiceCtx context)
|
|
||||||
{
|
|
||||||
if ((_permission & PrepoServicePermissionLevel.User) == 0)
|
|
||||||
{
|
|
||||||
return ResultCode.PermissionDenied;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We don't care about the differences since we don't use the play report.
|
|
||||||
return ProcessReport(context, withUserID: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandHipc(10200)]
|
|
||||||
// RequestImmediateTransmission()
|
|
||||||
public ResultCode RequestImmediateTransmission(ServiceCtx context)
|
|
||||||
{
|
|
||||||
// It signals an event of nn::prepo::detail::service::core::TransmissionStatusManager that requests the transmission of the report.
|
|
||||||
// Since we don't use reports it's fine to do nothing.
|
|
||||||
|
|
||||||
return ResultCode.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandHipc(10300)]
|
|
||||||
// GetTransmissionStatus() -> u32
|
|
||||||
public ResultCode GetTransmissionStatus(ServiceCtx context)
|
|
||||||
{
|
|
||||||
// It returns the transmission result of nn::prepo::detail::service::core::TransmissionStatusManager.
|
|
||||||
// Since we don't use reports it's fine to return ResultCode.Success.
|
|
||||||
context.ResponseData.Write((int)ResultCode.Success);
|
|
||||||
|
|
||||||
return ResultCode.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandHipc(10400)] // 9.0.0+
|
|
||||||
// GetSystemSessionId() -> u64
|
|
||||||
public ResultCode GetSystemSessionId(ServiceCtx context)
|
|
||||||
{
|
|
||||||
if ((_permission & PrepoServicePermissionLevel.User) == 0)
|
|
||||||
{
|
|
||||||
return ResultCode.PermissionDenied;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_systemSessionId == 0)
|
|
||||||
{
|
|
||||||
byte[] randomBuffer = new byte[8];
|
|
||||||
|
|
||||||
Random.Shared.NextBytes(randomBuffer);
|
|
||||||
|
|
||||||
_systemSessionId = BitConverter.ToUInt64(randomBuffer, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.ResponseData.Write(_systemSessionId);
|
|
||||||
|
|
||||||
return ResultCode.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandHipc(20100)]
|
|
||||||
// SaveSystemReport(u64, pid, buffer<u8, 9>, buffer<bytes, 5>)
|
|
||||||
public ResultCode SaveSystemReport(ServiceCtx context)
|
|
||||||
{
|
|
||||||
if ((_permission & PrepoServicePermissionLevel.System) != 0)
|
|
||||||
{
|
|
||||||
return ResultCode.PermissionDenied;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We don't care about the differences since we don't use the play report.
|
|
||||||
return ProcessReport(context, withUserID: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandHipc(20101)]
|
|
||||||
// SaveSystemReportWithUser(nn::account::Uid, u64, pid, buffer<u8, 9>, buffer<bytes, 5>)
|
|
||||||
public ResultCode SaveSystemReportWithUser(ServiceCtx context)
|
|
||||||
{
|
|
||||||
if ((_permission & PrepoServicePermissionLevel.System) != 0)
|
|
||||||
{
|
|
||||||
return ResultCode.PermissionDenied;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We don't care about the differences since we don't use the play report.
|
|
||||||
return ProcessReport(context, withUserID: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ResultCode ProcessReport(ServiceCtx context, bool withUserID)
|
|
||||||
{
|
|
||||||
UserId userId = withUserID ? context.RequestData.ReadStruct<UserId>() : new UserId();
|
|
||||||
string gameRoom = StringUtils.ReadUtf8String(context);
|
|
||||||
|
|
||||||
if (withUserID)
|
|
||||||
{
|
|
||||||
if (userId.IsNull)
|
|
||||||
{
|
|
||||||
return ResultCode.InvalidArgument;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gameRoom == string.Empty)
|
|
||||||
{
|
|
||||||
return ResultCode.InvalidState;
|
|
||||||
}
|
|
||||||
|
|
||||||
ulong inputPosition = context.Request.SendBuff[0].Position;
|
|
||||||
ulong inputSize = context.Request.SendBuff[0].Size;
|
|
||||||
|
|
||||||
if (inputSize == 0)
|
|
||||||
{
|
|
||||||
return ResultCode.InvalidBufferSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] inputBuffer = new byte[inputSize];
|
|
||||||
|
|
||||||
context.Memory.Read(inputPosition, inputBuffer);
|
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.ServicePrepo, ReadReportBuffer(inputBuffer, gameRoom, userId));
|
|
||||||
|
|
||||||
return ResultCode.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string ReadReportBuffer(byte[] buffer, string room, UserId userId)
|
|
||||||
{
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
MessagePackObject deserializedReport = MessagePackSerializer.UnpackMessagePackObject(buffer);
|
|
||||||
|
|
||||||
builder.AppendLine();
|
|
||||||
builder.AppendLine("PlayReport log:");
|
|
||||||
|
|
||||||
if (!userId.IsNull)
|
|
||||||
{
|
|
||||||
builder.AppendLine($" UserId: {userId}");
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.AppendLine($" Room: {room}");
|
|
||||||
builder.AppendLine($" Report: {MessagePackObjectFormatter.Format(deserializedReport)}");
|
|
||||||
|
|
||||||
return builder.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,15 +0,0 @@
|
|||||||
namespace Ryujinx.HLE.HOS.Services.Prepo
|
|
||||||
{
|
|
||||||
enum ResultCode
|
|
||||||
{
|
|
||||||
ModuleId = 129,
|
|
||||||
ErrorCodeShift = 9,
|
|
||||||
|
|
||||||
Success = 0,
|
|
||||||
|
|
||||||
InvalidArgument = (1 << ErrorCodeShift) | ModuleId,
|
|
||||||
InvalidState = (5 << ErrorCodeShift) | ModuleId,
|
|
||||||
InvalidBufferSize = (9 << ErrorCodeShift) | ModuleId,
|
|
||||||
PermissionDenied = (90 << ErrorCodeShift) | ModuleId
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@@ -180,7 +180,7 @@ namespace Ryujinx.HLE.HOS.Services.Sm
|
|||||||
return ResultCode.InvalidName;
|
return ResultCode.InvalidName;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.ServiceSm, $"Register \"{name}\".");
|
Logger.Debug?.Print(LogClass.ServiceSm, $"Register \"{name}\".");
|
||||||
|
|
||||||
KPort port = new KPort(context.Device.System.KernelContext, maxSessions, isLight, null);
|
KPort port = new KPort(context.Device.System.KernelContext, maxSessions, isLight, null);
|
||||||
|
|
||||||
|
9
Ryujinx.Headless.SDL2/HideCursor.cs
Normal file
9
Ryujinx.Headless.SDL2/HideCursor.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Ryujinx.Headless.SDL2
|
||||||
|
{
|
||||||
|
public enum HideCursor
|
||||||
|
{
|
||||||
|
Never,
|
||||||
|
OnIdle,
|
||||||
|
Always
|
||||||
|
}
|
||||||
|
}
|
@@ -5,7 +5,6 @@ using Ryujinx.Common.Logging;
|
|||||||
using Ryujinx.Graphics.OpenGL;
|
using Ryujinx.Graphics.OpenGL;
|
||||||
using Ryujinx.Input.HLE;
|
using Ryujinx.Input.HLE;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
using static SDL2.SDL;
|
using static SDL2.SDL;
|
||||||
|
|
||||||
namespace Ryujinx.Headless.SDL2.OpenGL
|
namespace Ryujinx.Headless.SDL2.OpenGL
|
||||||
@@ -103,7 +102,13 @@ namespace Ryujinx.Headless.SDL2.OpenGL
|
|||||||
private GraphicsDebugLevel _glLogLevel;
|
private GraphicsDebugLevel _glLogLevel;
|
||||||
private SDL2OpenGLContext _openGLContext;
|
private SDL2OpenGLContext _openGLContext;
|
||||||
|
|
||||||
public OpenGLWindow(InputManager inputManager, GraphicsDebugLevel glLogLevel, AspectRatio aspectRatio, bool enableMouse) : base(inputManager, glLogLevel, aspectRatio, enableMouse)
|
public OpenGLWindow(
|
||||||
|
InputManager inputManager,
|
||||||
|
GraphicsDebugLevel glLogLevel,
|
||||||
|
AspectRatio aspectRatio,
|
||||||
|
bool enableMouse,
|
||||||
|
HideCursor hideCursor)
|
||||||
|
: base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursor)
|
||||||
{
|
{
|
||||||
_glLogLevel = glLogLevel;
|
_glLogLevel = glLogLevel;
|
||||||
}
|
}
|
||||||
|
@@ -6,6 +6,14 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
{
|
{
|
||||||
public class Options
|
public class Options
|
||||||
{
|
{
|
||||||
|
// General
|
||||||
|
|
||||||
|
[Option("root-data-dir", Required = false, HelpText = "Set the custom folder path for Ryujinx data.")]
|
||||||
|
public string BaseDataDir { get; set; }
|
||||||
|
|
||||||
|
[Option("profile", Required = false, HelpText = "Set the user profile to launch the game with.")]
|
||||||
|
public string UserProfile { get; set; }
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
|
|
||||||
[Option("input-profile-1", Required = false, HelpText = "Set the input profile in use for Player 1.")]
|
[Option("input-profile-1", Required = false, HelpText = "Set the input profile in use for Player 1.")]
|
||||||
@@ -23,7 +31,7 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
[Option("input-profile-5", Required = false, HelpText = "Set the input profile in use for Player 5.")]
|
[Option("input-profile-5", Required = false, HelpText = "Set the input profile in use for Player 5.")]
|
||||||
public string InputProfile5Name { get; set; }
|
public string InputProfile5Name { get; set; }
|
||||||
|
|
||||||
[Option("input-profile-6", Required = false, HelpText = "Set the input profile in use for Player 5.")]
|
[Option("input-profile-6", Required = false, HelpText = "Set the input profile in use for Player 6.")]
|
||||||
public string InputProfile6Name { get; set; }
|
public string InputProfile6Name { get; set; }
|
||||||
|
|
||||||
[Option("input-profile-7", Required = false, HelpText = "Set the input profile in use for Player 7.")]
|
[Option("input-profile-7", Required = false, HelpText = "Set the input profile in use for Player 7.")]
|
||||||
@@ -63,42 +71,45 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
public string InputIdHandheld { get; set; }
|
public string InputIdHandheld { get; set; }
|
||||||
|
|
||||||
[Option("enable-keyboard", Required = false, Default = false, HelpText = "Enable or disable keyboard support (Independent from controllers binding).")]
|
[Option("enable-keyboard", Required = false, Default = false, HelpText = "Enable or disable keyboard support (Independent from controllers binding).")]
|
||||||
public bool? EnableKeyboard { get; set; }
|
public bool EnableKeyboard { get; set; }
|
||||||
|
|
||||||
[Option("enable-mouse", Required = false, Default = false, HelpText = "Enable or disable mouse support.")]
|
[Option("enable-mouse", Required = false, Default = false, HelpText = "Enable or disable mouse support.")]
|
||||||
public bool? EnableMouse { get; set; }
|
public bool EnableMouse { get; set; }
|
||||||
|
|
||||||
|
[Option("hide-cursor", Required = false, Default = HideCursor.OnIdle, HelpText = "Change when the cursor gets hidden.")]
|
||||||
|
public HideCursor HideCursor { get; set; }
|
||||||
|
|
||||||
[Option("list-input-profiles", Required = false, HelpText = "List inputs profiles.")]
|
[Option("list-input-profiles", Required = false, HelpText = "List inputs profiles.")]
|
||||||
public bool? ListInputProfiles { get; set; }
|
public bool ListInputProfiles { get; set; }
|
||||||
|
|
||||||
[Option("list-inputs-ids", Required = false, HelpText = "List inputs ids.")]
|
[Option("list-inputs-ids", Required = false, HelpText = "List inputs ids.")]
|
||||||
public bool ListInputIds { get; set; }
|
public bool ListInputIds { get; set; }
|
||||||
|
|
||||||
// System
|
// System
|
||||||
|
|
||||||
[Option("enable-ptc", Required = false, Default = true, HelpText = "Enables profiled translation cache persistency.")]
|
[Option("disable-ptc", Required = false, HelpText = "Disables profiled persistent translation cache.")]
|
||||||
public bool? EnablePtc { get; set; }
|
public bool DisablePtc { get; set; }
|
||||||
|
|
||||||
[Option("enable-internet-connection", Required = false, Default = false, HelpText = "Enables guest Internet connection.")]
|
[Option("enable-internet-connection", Required = false, Default = false, HelpText = "Enables guest Internet connection.")]
|
||||||
public bool? EnableInternetAccess { get; set; }
|
public bool EnableInternetAccess { get; set; }
|
||||||
|
|
||||||
[Option("enable-fs-integrity-checks", Required = false, Default = true, HelpText = "Enables integrity checks on Game content files.")]
|
[Option("disable-fs-integrity-checks", Required = false, HelpText = "Disables integrity checks on Game content files.")]
|
||||||
public bool? EnableFsIntegrityChecks { get; set; }
|
public bool DisableFsIntegrityChecks { get; set; }
|
||||||
|
|
||||||
[Option("fs-global-access-log-mode", Required = false, Default = 0, HelpText = "Enables FS access log output to the console.")]
|
[Option("fs-global-access-log-mode", Required = false, Default = 0, HelpText = "Enables FS access log output to the console.")]
|
||||||
public int FsGlobalAccessLogMode { get; set; }
|
public int FsGlobalAccessLogMode { get; set; }
|
||||||
|
|
||||||
[Option("enable-vsync", Required = false, Default = true, HelpText = "Enables Vertical Sync.")]
|
[Option("disable-vsync", Required = false, HelpText = "Disables Vertical Sync.")]
|
||||||
public bool? EnableVsync { get; set; }
|
public bool DisableVsync { get; set; }
|
||||||
|
|
||||||
[Option("enable-shader-cache", Required = false, Default = true, HelpText = "Enables Shader cache.")]
|
[Option("disable-shader-cache", Required = false, HelpText = "Disables Shader cache.")]
|
||||||
public bool? EnableShaderCache { get; set; }
|
public bool DisableShaderCache { get; set; }
|
||||||
|
|
||||||
[Option("enable-texture-recompression", Required = false, Default = false, HelpText = "Enables Texture recompression.")]
|
[Option("enable-texture-recompression", Required = false, Default = false, HelpText = "Enables Texture recompression.")]
|
||||||
public bool? EnableTextureRecompression { get; set; }
|
public bool EnableTextureRecompression { get; set; }
|
||||||
|
|
||||||
[Option("enable-docked-mode", Required = false, Default = true, HelpText = "Enables Docked Mode.")]
|
[Option("disable-docked-mode", Required = false, HelpText = "Disables Docked Mode.")]
|
||||||
public bool? EnableDockedMode { get; set; }
|
public bool DisableDockedMode { get; set; }
|
||||||
|
|
||||||
[Option("system-language", Required = false, Default = SystemLanguage.AmericanEnglish, HelpText = "Change System Language.")]
|
[Option("system-language", Required = false, Default = SystemLanguage.AmericanEnglish, HelpText = "Change System Language.")]
|
||||||
public SystemLanguage SystemLanguage { get; set; }
|
public SystemLanguage SystemLanguage { get; set; }
|
||||||
@@ -120,32 +131,32 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
|
|
||||||
[Option("enable-file-logging", Required = false, Default = false, HelpText = "Enables logging to a file on disk.")]
|
[Option("disable-file-logging", Required = false, Default = false, HelpText = "Disables logging to a file on disk.")]
|
||||||
public bool? EnableFileLog { get; set; }
|
public bool DisableFileLog { get; set; }
|
||||||
|
|
||||||
[Option("enable-debug-logs", Required = false, Default = false, HelpText = "Enables printing debug log messages.")]
|
[Option("enable-debug-logs", Required = false, Default = false, HelpText = "Enables printing debug log messages.")]
|
||||||
public bool? LoggingEnableDebug { get; set; }
|
public bool LoggingEnableDebug { get; set; }
|
||||||
|
|
||||||
[Option("enable-stub-logs", Required = false, Default = true, HelpText = "Enables printing stub log messages.")]
|
[Option("disable-stub-logs", Required = false, HelpText = "Disables printing stub log messages.")]
|
||||||
public bool? LoggingEnableStub { get; set; }
|
public bool LoggingDisableStub { get; set; }
|
||||||
|
|
||||||
[Option("enable-info-logs", Required = false, Default = true, HelpText = "Enables printing info log messages.")]
|
[Option("disable-info-logs", Required = false, HelpText = "Disables printing info log messages.")]
|
||||||
public bool? LoggingEnableInfo { get; set; }
|
public bool LoggingDisableInfo { get; set; }
|
||||||
|
|
||||||
[Option("enable-warning-logs", Required = false, Default = true, HelpText = "Enables printing warning log messages.")]
|
[Option("disable-warning-logs", Required = false, HelpText = "Disables printing warning log messages.")]
|
||||||
public bool? LoggingEnableWarning { get; set; }
|
public bool LoggingDisableWarning { get; set; }
|
||||||
|
|
||||||
[Option("enable-error-logs", Required = false, Default = true, HelpText = "Enables printing error log messages.")]
|
[Option("disable-error-logs", Required = false, HelpText = "Disables printing error log messages.")]
|
||||||
public bool? LoggingEnableError { get; set; }
|
public bool LoggingEnableError { get; set; }
|
||||||
|
|
||||||
[Option("enable-trace-logs", Required = false, Default = false, HelpText = "Enables printing trace log messages.")]
|
[Option("enable-trace-logs", Required = false, Default = false, HelpText = "Enables printing trace log messages.")]
|
||||||
public bool? LoggingEnableTrace { get; set; }
|
public bool LoggingEnableTrace { get; set; }
|
||||||
|
|
||||||
[Option("enable-guest-logs", Required = false, Default = true, HelpText = "Enables printing guest log messages.")]
|
[Option("disable-guest-logs", Required = false, HelpText = "Disables printing guest log messages.")]
|
||||||
public bool? LoggingEnableGuest { get; set; }
|
public bool LoggingDisableGuest { get; set; }
|
||||||
|
|
||||||
[Option("enable-fs-access-logs", Required = false, Default = false, HelpText = "Enables printing FS access log messages.")]
|
[Option("enable-fs-access-logs", Required = false, Default = false, HelpText = "Enables printing FS access log messages.")]
|
||||||
public bool? LoggingEnableFsAccessLog { get; set; }
|
public bool LoggingEnableFsAccessLog { get; set; }
|
||||||
|
|
||||||
[Option("graphics-debug-level", Required = false, Default = GraphicsDebugLevel.None, HelpText = "Change Graphics API debug log level.")]
|
[Option("graphics-debug-level", Required = false, Default = GraphicsDebugLevel.None, HelpText = "Change Graphics API debug log level.")]
|
||||||
public GraphicsDebugLevel LoggingGraphicsDebugLevel { get; set; }
|
public GraphicsDebugLevel LoggingGraphicsDebugLevel { get; set; }
|
||||||
@@ -164,6 +175,9 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
[Option("backend-threading", Required = false, Default = BackendThreading.Auto, HelpText = "Whether or not backend threading is enabled. The \"Auto\" setting will determine whether threading should be enabled at runtime.")]
|
[Option("backend-threading", Required = false, Default = BackendThreading.Auto, HelpText = "Whether or not backend threading is enabled. The \"Auto\" setting will determine whether threading should be enabled at runtime.")]
|
||||||
public BackendThreading BackendThreading { get; set; }
|
public BackendThreading BackendThreading { get; set; }
|
||||||
|
|
||||||
|
[Option("disable-macro-hle", Required= false, HelpText = "Disables high-level emulation of Macro code. Leaving this enabled improves performance but may cause graphical glitches in some games.")]
|
||||||
|
public bool DisableMacroHLE { get; set; }
|
||||||
|
|
||||||
[Option("graphics-shaders-dump-path", Required = false, HelpText = "Dumps shaders in this local directory. (Developer only)")]
|
[Option("graphics-shaders-dump-path", Required = false, HelpText = "Dumps shaders in this local directory. (Developer only)")]
|
||||||
public string GraphicsShadersDumpPath { get; set; }
|
public string GraphicsShadersDumpPath { get; set; }
|
||||||
|
|
||||||
@@ -176,10 +190,10 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
// Hacks
|
// Hacks
|
||||||
|
|
||||||
[Option("expand-ram", Required = false, Default = false, HelpText = "Expands the RAM amount on the emulated system from 4GiB to 6GiB.")]
|
[Option("expand-ram", Required = false, Default = false, HelpText = "Expands the RAM amount on the emulated system from 4GiB to 6GiB.")]
|
||||||
public bool? ExpandRam { get; set; }
|
public bool ExpandRam { get; set; }
|
||||||
|
|
||||||
[Option("ignore-missing-services", Required = false, Default = false, HelpText = "Enable ignoring missing services.")]
|
[Option("ignore-missing-services", Required = false, Default = false, HelpText = "Enable ignoring missing services.")]
|
||||||
public bool? IgnoreMissingServices { get; set; }
|
public bool IgnoreMissingServices { get; set; }
|
||||||
|
|
||||||
// Values
|
// Values
|
||||||
|
|
||||||
|
@@ -33,7 +33,6 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId;
|
using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId;
|
||||||
using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
|
using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
|
||||||
using Key = Ryujinx.Common.Configuration.Hid.Key;
|
using Key = Ryujinx.Common.Configuration.Hid.Key;
|
||||||
@@ -59,24 +58,10 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
|
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
Version = ReleaseInformations.GetVersion();
|
Version = ReleaseInformation.GetVersion();
|
||||||
|
|
||||||
Console.Title = $"Ryujinx Console {Version} (Headless SDL2)";
|
Console.Title = $"Ryujinx Console {Version} (Headless SDL2)";
|
||||||
|
|
||||||
AppDataManager.Initialize(null);
|
|
||||||
|
|
||||||
_virtualFileSystem = VirtualFileSystem.CreateInstance();
|
|
||||||
_libHacHorizonManager = new LibHacHorizonManager();
|
|
||||||
|
|
||||||
_libHacHorizonManager.InitializeFsServer(_virtualFileSystem);
|
|
||||||
_libHacHorizonManager.InitializeArpServer();
|
|
||||||
_libHacHorizonManager.InitializeBcatServer();
|
|
||||||
_libHacHorizonManager.InitializeSystemClients();
|
|
||||||
|
|
||||||
_contentManager = new ContentManager(_virtualFileSystem);
|
|
||||||
_accountManager = new AccountManager(_libHacHorizonManager.RyujinxClient);
|
|
||||||
_userChannelPersistence = new UserChannelPersistence();
|
|
||||||
|
|
||||||
if (OperatingSystem.IsMacOS() || OperatingSystem.IsLinux())
|
if (OperatingSystem.IsMacOS() || OperatingSystem.IsLinux())
|
||||||
{
|
{
|
||||||
AutoResetEvent invoked = new AutoResetEvent(false);
|
AutoResetEvent invoked = new AutoResetEvent(false);
|
||||||
@@ -97,15 +82,9 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_inputManager = new InputManager(new SDL2KeyboardDriver(), new SDL2GamepadDriver());
|
|
||||||
|
|
||||||
GraphicsConfig.EnableShaderCache = true;
|
|
||||||
|
|
||||||
Parser.Default.ParseArguments<Options>(args)
|
Parser.Default.ParseArguments<Options>(args)
|
||||||
.WithParsed(options => Load(options))
|
.WithParsed(Load)
|
||||||
.WithNotParsed(errors => errors.Output());
|
.WithNotParsed(errors => errors.Output());
|
||||||
|
|
||||||
_inputManager.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InputConfig HandlePlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index)
|
private static InputConfig HandlePlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index)
|
||||||
@@ -343,6 +322,24 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
|
|
||||||
static void Load(Options option)
|
static void Load(Options option)
|
||||||
{
|
{
|
||||||
|
AppDataManager.Initialize(option.BaseDataDir);
|
||||||
|
|
||||||
|
_virtualFileSystem = VirtualFileSystem.CreateInstance();
|
||||||
|
_libHacHorizonManager = new LibHacHorizonManager();
|
||||||
|
|
||||||
|
_libHacHorizonManager.InitializeFsServer(_virtualFileSystem);
|
||||||
|
_libHacHorizonManager.InitializeArpServer();
|
||||||
|
_libHacHorizonManager.InitializeBcatServer();
|
||||||
|
_libHacHorizonManager.InitializeSystemClients();
|
||||||
|
|
||||||
|
_contentManager = new ContentManager(_virtualFileSystem);
|
||||||
|
_accountManager = new AccountManager(_libHacHorizonManager.RyujinxClient, option.UserProfile);
|
||||||
|
_userChannelPersistence = new UserChannelPersistence();
|
||||||
|
|
||||||
|
_inputManager = new InputManager(new SDL2KeyboardDriver(), new SDL2GamepadDriver());
|
||||||
|
|
||||||
|
GraphicsConfig.EnableShaderCache = true;
|
||||||
|
|
||||||
IGamepad gamepad;
|
IGamepad gamepad;
|
||||||
|
|
||||||
if (option.ListInputIds)
|
if (option.ListInputIds)
|
||||||
@@ -378,8 +375,8 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
}
|
}
|
||||||
|
|
||||||
_inputConfiguration = new List<InputConfig>();
|
_inputConfiguration = new List<InputConfig>();
|
||||||
_enableKeyboard = (bool)option.EnableKeyboard;
|
_enableKeyboard = option.EnableKeyboard;
|
||||||
_enableMouse = (bool)option.EnableMouse;
|
_enableMouse = option.EnableMouse;
|
||||||
|
|
||||||
void LoadPlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index)
|
void LoadPlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index)
|
||||||
{
|
{
|
||||||
@@ -407,30 +404,31 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup logging level
|
// Setup logging level
|
||||||
Logger.SetEnable(LogLevel.Debug, (bool)option.LoggingEnableDebug);
|
Logger.SetEnable(LogLevel.Debug, option.LoggingEnableDebug);
|
||||||
Logger.SetEnable(LogLevel.Stub, (bool)option.LoggingEnableStub);
|
Logger.SetEnable(LogLevel.Stub, !option.LoggingDisableStub);
|
||||||
Logger.SetEnable(LogLevel.Info, (bool)option.LoggingEnableInfo);
|
Logger.SetEnable(LogLevel.Info, !option.LoggingDisableInfo);
|
||||||
Logger.SetEnable(LogLevel.Warning, (bool)option.LoggingEnableWarning);
|
Logger.SetEnable(LogLevel.Warning, !option.LoggingDisableWarning);
|
||||||
Logger.SetEnable(LogLevel.Error, (bool)option.LoggingEnableError);
|
Logger.SetEnable(LogLevel.Error, option.LoggingEnableError);
|
||||||
Logger.SetEnable(LogLevel.Trace, (bool)option.LoggingEnableTrace);
|
Logger.SetEnable(LogLevel.Trace, option.LoggingEnableTrace);
|
||||||
Logger.SetEnable(LogLevel.Guest, (bool)option.LoggingEnableGuest);
|
Logger.SetEnable(LogLevel.Guest, !option.LoggingDisableGuest);
|
||||||
Logger.SetEnable(LogLevel.AccessLog, (bool)option.LoggingEnableFsAccessLog);
|
Logger.SetEnable(LogLevel.AccessLog, option.LoggingEnableFsAccessLog);
|
||||||
|
|
||||||
if ((bool)option.EnableFileLog)
|
if (!option.DisableFileLog)
|
||||||
{
|
{
|
||||||
Logger.AddTarget(new AsyncLogTargetWrapper(
|
Logger.AddTarget(new AsyncLogTargetWrapper(
|
||||||
new FileLogTarget(ReleaseInformations.GetBaseApplicationDirectory(), "file"),
|
new FileLogTarget(ReleaseInformation.GetBaseApplicationDirectory(), "file"),
|
||||||
1000,
|
1000,
|
||||||
AsyncLogTargetOverflowAction.Block
|
AsyncLogTargetOverflowAction.Block
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup graphics configuration
|
// Setup graphics configuration
|
||||||
GraphicsConfig.EnableShaderCache = (bool)option.EnableShaderCache;
|
GraphicsConfig.EnableShaderCache = !option.DisableShaderCache;
|
||||||
GraphicsConfig.EnableTextureRecompression = (bool)option.EnableTextureRecompression;
|
GraphicsConfig.EnableTextureRecompression = option.EnableTextureRecompression;
|
||||||
GraphicsConfig.ResScale = option.ResScale;
|
GraphicsConfig.ResScale = option.ResScale;
|
||||||
GraphicsConfig.MaxAnisotropy = option.MaxAnisotropy;
|
GraphicsConfig.MaxAnisotropy = option.MaxAnisotropy;
|
||||||
GraphicsConfig.ShadersDumpPath = option.GraphicsShadersDumpPath;
|
GraphicsConfig.ShadersDumpPath = option.GraphicsShadersDumpPath;
|
||||||
|
GraphicsConfig.EnableMacroHLE = !option.DisableMacroHLE;
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@@ -443,6 +441,8 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
|
|
||||||
_userChannelPersistence.ShouldRestart = false;
|
_userChannelPersistence.ShouldRestart = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_inputManager.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetupProgressHandler()
|
private static void SetupProgressHandler()
|
||||||
@@ -479,8 +479,8 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
private static WindowBase CreateWindow(Options options)
|
private static WindowBase CreateWindow(Options options)
|
||||||
{
|
{
|
||||||
return options.GraphicsBackend == GraphicsBackend.Vulkan
|
return options.GraphicsBackend == GraphicsBackend.Vulkan
|
||||||
? new VulkanWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, (bool)options.EnableMouse)
|
? new VulkanWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, options.EnableMouse, options.HideCursor)
|
||||||
: new OpenGLWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, (bool)options.EnableMouse);
|
: new OpenGLWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, options.EnableMouse, options.HideCursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IRenderer CreateRenderer(Options options, WindowBase window)
|
private static IRenderer CreateRenderer(Options options, WindowBase window)
|
||||||
@@ -533,20 +533,20 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
_userChannelPersistence,
|
_userChannelPersistence,
|
||||||
renderer,
|
renderer,
|
||||||
new SDL2HardwareDeviceDriver(),
|
new SDL2HardwareDeviceDriver(),
|
||||||
(bool)options.ExpandRam ? MemoryConfiguration.MemoryConfiguration6GiB : MemoryConfiguration.MemoryConfiguration4GiB,
|
options.ExpandRam ? MemoryConfiguration.MemoryConfiguration6GiB : MemoryConfiguration.MemoryConfiguration4GiB,
|
||||||
window,
|
window,
|
||||||
options.SystemLanguage,
|
options.SystemLanguage,
|
||||||
options.SystemRegion,
|
options.SystemRegion,
|
||||||
(bool)options.EnableVsync,
|
!options.DisableVsync,
|
||||||
(bool)options.EnableDockedMode,
|
!options.DisableDockedMode,
|
||||||
(bool)options.EnablePtc,
|
!options.DisablePtc,
|
||||||
(bool)options.EnableInternetAccess,
|
options.EnableInternetAccess,
|
||||||
(bool)options.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None,
|
!options.DisableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None,
|
||||||
options.FsGlobalAccessLogMode,
|
options.FsGlobalAccessLogMode,
|
||||||
options.SystemTimeOffset,
|
options.SystemTimeOffset,
|
||||||
options.SystemTimeZone,
|
options.SystemTimeZone,
|
||||||
options.MemoryManagerMode,
|
options.MemoryManagerMode,
|
||||||
(bool)options.IgnoreMissingServices,
|
options.IgnoreMissingServices,
|
||||||
options.AspectRatio,
|
options.AspectRatio,
|
||||||
options.AudioVolume);
|
options.AudioVolume);
|
||||||
|
|
||||||
@@ -649,7 +649,7 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Application, "Please specify a valid XCI/NCA/NSP/PFS0/NRO file.");
|
Logger.Warning?.Print(LogClass.Application, $"Couldn't load '{options.InputPath}'. Please specify a valid XCI/NCA/NSP/PFS0/NRO file.");
|
||||||
|
|
||||||
_emulationContext.Dispose();
|
_emulationContext.Dispose();
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
@@ -31,16 +31,26 @@
|
|||||||
<PackageReference Include="CommandLineParser" />
|
<PackageReference Include="CommandLineParser" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="..\distribution\legal\THIRDPARTY.md">
|
<Content Include="..\distribution\legal\THIRDPARTY.md">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
<TargetPath>THIRDPARTY.md</TargetPath>
|
<TargetPath>THIRDPARTY.md</TargetPath>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Include="..\LICENSE.txt">
|
<Content Include="..\LICENSE.txt">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
<TargetPath>LICENSE.txt</TargetPath>
|
<TargetPath>LICENSE.txt</TargetPath>
|
||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(RuntimeIdentifier)' == 'linux-x64'">
|
||||||
|
<Content Include="..\distribution\linux\Ryujinx.sh">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="Ryujinx.bmp" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- Due to .net core 3.1 embedded resource loading -->
|
<!-- Due to .net core 3.1 embedded resource loading -->
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
BIN
Ryujinx.Headless.SDL2/Ryujinx.bmp
Normal file
BIN
Ryujinx.Headless.SDL2/Ryujinx.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.1 KiB |
@@ -10,7 +10,12 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
{
|
{
|
||||||
class SDL2MouseDriver : IGamepadDriver
|
class SDL2MouseDriver : IGamepadDriver
|
||||||
{
|
{
|
||||||
|
private const int CursorHideIdleTime = 8; // seconds
|
||||||
|
|
||||||
private bool _isDisposed;
|
private bool _isDisposed;
|
||||||
|
private HideCursor _hideCursor;
|
||||||
|
private bool _isHidden;
|
||||||
|
private long _lastCursorMoveTime;
|
||||||
|
|
||||||
public bool[] PressedButtons { get; }
|
public bool[] PressedButtons { get; }
|
||||||
|
|
||||||
@@ -18,9 +23,16 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
public Vector2 Scroll { get; private set; }
|
public Vector2 Scroll { get; private set; }
|
||||||
public Size _clientSize;
|
public Size _clientSize;
|
||||||
|
|
||||||
public SDL2MouseDriver()
|
public SDL2MouseDriver(HideCursor hideCursor)
|
||||||
{
|
{
|
||||||
PressedButtons = new bool[(int)MouseButton.Count];
|
PressedButtons = new bool[(int)MouseButton.Count];
|
||||||
|
_hideCursor = hideCursor;
|
||||||
|
|
||||||
|
if (_hideCursor == HideCursor.Always)
|
||||||
|
{
|
||||||
|
SDL_ShowCursor(SDL_DISABLE);
|
||||||
|
_isHidden = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -31,26 +43,75 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
return (MouseButton)(rawButton - 1);
|
return (MouseButton)(rawButton - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(SDL_Event evnt)
|
public void UpdatePosition()
|
||||||
{
|
{
|
||||||
if (evnt.type == SDL_EventType.SDL_MOUSEBUTTONDOWN || evnt.type == SDL_EventType.SDL_MOUSEBUTTONUP)
|
SDL_GetMouseState(out int posX, out int posY);
|
||||||
|
Vector2 position = new(posX, posY);
|
||||||
|
|
||||||
|
if (CurrentPosition != position)
|
||||||
{
|
{
|
||||||
uint rawButton = evnt.button.button;
|
CurrentPosition = position;
|
||||||
|
_lastCursorMoveTime = Stopwatch.GetTimestamp();
|
||||||
|
}
|
||||||
|
|
||||||
if (rawButton > 0 && rawButton <= (int)MouseButton.Count)
|
CheckIdle();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckIdle()
|
||||||
|
{
|
||||||
|
if (_hideCursor != HideCursor.OnIdle)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
long cursorMoveDelta = Stopwatch.GetTimestamp() - _lastCursorMoveTime;
|
||||||
|
|
||||||
|
if (cursorMoveDelta >= CursorHideIdleTime * Stopwatch.Frequency)
|
||||||
|
{
|
||||||
|
if (!_isHidden)
|
||||||
{
|
{
|
||||||
PressedButtons[(int)DriverButtonToMouseButton(rawButton)] = evnt.type == SDL_EventType.SDL_MOUSEBUTTONDOWN;
|
SDL_ShowCursor(SDL_DISABLE);
|
||||||
|
_isHidden = true;
|
||||||
CurrentPosition = new Vector2(evnt.button.x, evnt.button.y);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (evnt.type == SDL_EventType.SDL_MOUSEMOTION)
|
else
|
||||||
{
|
{
|
||||||
CurrentPosition = new Vector2(evnt.motion.x, evnt.motion.y);
|
if (_isHidden)
|
||||||
|
{
|
||||||
|
SDL_ShowCursor(SDL_ENABLE);
|
||||||
|
_isHidden = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (evnt.type == SDL_EventType.SDL_MOUSEWHEEL)
|
}
|
||||||
|
|
||||||
|
public void Update(SDL_Event evnt)
|
||||||
|
{
|
||||||
|
switch (evnt.type)
|
||||||
{
|
{
|
||||||
Scroll = new Vector2(evnt.wheel.x, evnt.wheel.y);
|
case SDL_EventType.SDL_MOUSEBUTTONDOWN:
|
||||||
|
case SDL_EventType.SDL_MOUSEBUTTONUP:
|
||||||
|
uint rawButton = evnt.button.button;
|
||||||
|
|
||||||
|
if (rawButton > 0 && rawButton <= (int)MouseButton.Count)
|
||||||
|
{
|
||||||
|
PressedButtons[(int)DriverButtonToMouseButton(rawButton)] = evnt.type == SDL_EventType.SDL_MOUSEBUTTONDOWN;
|
||||||
|
|
||||||
|
CurrentPosition = new Vector2(evnt.button.x, evnt.button.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
// NOTE: On Linux using Wayland mouse motion events won't be received at all.
|
||||||
|
case SDL_EventType.SDL_MOUSEMOTION:
|
||||||
|
CurrentPosition = new Vector2(evnt.motion.x, evnt.motion.y);
|
||||||
|
_lastCursorMoveTime = Stopwatch.GetTimestamp();
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDL_EventType.SDL_MOUSEWHEEL:
|
||||||
|
Scroll = new Vector2(evnt.wheel.x, evnt.wheel.y);
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -12,7 +12,13 @@ namespace Ryujinx.Headless.SDL2.Vulkan
|
|||||||
{
|
{
|
||||||
private GraphicsDebugLevel _glLogLevel;
|
private GraphicsDebugLevel _glLogLevel;
|
||||||
|
|
||||||
public VulkanWindow(InputManager inputManager, GraphicsDebugLevel glLogLevel, AspectRatio aspectRatio, bool enableMouse) : base(inputManager, glLogLevel, aspectRatio, enableMouse)
|
public VulkanWindow(
|
||||||
|
InputManager inputManager,
|
||||||
|
GraphicsDebugLevel glLogLevel,
|
||||||
|
AspectRatio aspectRatio,
|
||||||
|
bool enableMouse,
|
||||||
|
HideCursor hideCursor)
|
||||||
|
: base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursor)
|
||||||
{
|
{
|
||||||
_glLogLevel = glLogLevel;
|
_glLogLevel = glLogLevel;
|
||||||
}
|
}
|
||||||
|
@@ -14,13 +14,16 @@ using System;
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using static SDL2.SDL;
|
using static SDL2.SDL;
|
||||||
using Switch = Ryujinx.HLE.Switch;
|
using Switch = Ryujinx.HLE.Switch;
|
||||||
|
|
||||||
namespace Ryujinx.Headless.SDL2
|
namespace Ryujinx.Headless.SDL2
|
||||||
{
|
{
|
||||||
abstract class WindowBase : IHostUiHandler, IDisposable
|
abstract partial class WindowBase : IHostUiHandler, IDisposable
|
||||||
{
|
{
|
||||||
protected const int DefaultWidth = 1280;
|
protected const int DefaultWidth = 1280;
|
||||||
protected const int DefaultHeight = 720;
|
protected const int DefaultHeight = 720;
|
||||||
@@ -29,6 +32,10 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
|
|
||||||
private static ConcurrentQueue<Action> MainThreadActions = new ConcurrentQueue<Action>();
|
private static ConcurrentQueue<Action> MainThreadActions = new ConcurrentQueue<Action>();
|
||||||
|
|
||||||
|
[LibraryImport("SDL2")]
|
||||||
|
// TODO: Remove this as soon as SDL2-CS was updated to expose this method publicly
|
||||||
|
private static partial IntPtr SDL_LoadBMP_RW(IntPtr src, int freesrc);
|
||||||
|
|
||||||
public static void QueueMainThreadAction(Action action)
|
public static void QueueMainThreadAction(Action action)
|
||||||
{
|
{
|
||||||
MainThreadActions.Enqueue(action);
|
MainThreadActions.Enqueue(action);
|
||||||
@@ -66,9 +73,14 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
private AspectRatio _aspectRatio;
|
private AspectRatio _aspectRatio;
|
||||||
private bool _enableMouse;
|
private bool _enableMouse;
|
||||||
|
|
||||||
public WindowBase(InputManager inputManager, GraphicsDebugLevel glLogLevel, AspectRatio aspectRatio, bool enableMouse)
|
public WindowBase(
|
||||||
|
InputManager inputManager,
|
||||||
|
GraphicsDebugLevel glLogLevel,
|
||||||
|
AspectRatio aspectRatio,
|
||||||
|
bool enableMouse,
|
||||||
|
HideCursor hideCursor)
|
||||||
{
|
{
|
||||||
MouseDriver = new SDL2MouseDriver();
|
MouseDriver = new SDL2MouseDriver(hideCursor);
|
||||||
_inputManager = inputManager;
|
_inputManager = inputManager;
|
||||||
_inputManager.SetMouseDriver(MouseDriver);
|
_inputManager.SetMouseDriver(MouseDriver);
|
||||||
NpadManager = _inputManager.CreateNpadManager();
|
NpadManager = _inputManager.CreateNpadManager();
|
||||||
@@ -103,6 +115,34 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
TouchScreenManager.Initialize(device);
|
TouchScreenManager.Initialize(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetWindowIcon()
|
||||||
|
{
|
||||||
|
Stream iconStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Ryujinx.Headless.SDL2.Ryujinx.bmp");
|
||||||
|
byte[] iconBytes = new byte[iconStream!.Length];
|
||||||
|
|
||||||
|
if (iconStream.Read(iconBytes, 0, iconBytes.Length) != iconBytes.Length)
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, "Failed to read icon to byte array.");
|
||||||
|
iconStream.Close();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
iconStream.Close();
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (byte* iconPtr = iconBytes)
|
||||||
|
{
|
||||||
|
IntPtr rwOpsStruct = SDL_RWFromConstMem((IntPtr)iconPtr, iconBytes.Length);
|
||||||
|
IntPtr iconHandle = SDL_LoadBMP_RW(rwOpsStruct, 1);
|
||||||
|
|
||||||
|
SDL_SetWindowIcon(WindowHandle, iconHandle);
|
||||||
|
SDL_FreeSurface(iconHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void InitializeWindow()
|
private void InitializeWindow()
|
||||||
{
|
{
|
||||||
string titleNameSection = string.IsNullOrWhiteSpace(Device.Application.TitleName) ? string.Empty
|
string titleNameSection = string.IsNullOrWhiteSpace(Device.Application.TitleName) ? string.Empty
|
||||||
@@ -127,6 +167,8 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
throw new Exception(errorMessage);
|
throw new Exception(errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetWindowIcon();
|
||||||
|
|
||||||
_windowId = SDL_GetWindowID(WindowHandle);
|
_windowId = SDL_GetWindowID(WindowHandle);
|
||||||
SDL2Driver.Instance.RegisterWindow(_windowId, HandleWindowEvent);
|
SDL2Driver.Instance.RegisterWindow(_windowId, HandleWindowEvent);
|
||||||
|
|
||||||
@@ -146,9 +188,11 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
Renderer?.Window.SetSize(Width, Height);
|
Renderer?.Window.SetSize(Width, Height);
|
||||||
MouseDriver.SetClientSize(Width, Height);
|
MouseDriver.SetClientSize(Width, Height);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_WindowEventID.SDL_WINDOWEVENT_CLOSE:
|
case SDL_WindowEventID.SDL_WINDOWEVENT_CLOSE:
|
||||||
Exit();
|
Exit();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -331,6 +375,9 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
|
|
||||||
Device.Hid.DebugPad.Update();
|
Device.Hid.DebugPad.Update();
|
||||||
|
|
||||||
|
// TODO: Replace this with MouseDriver.CheckIdle() when mouse motion events are received on every supported platform.
|
||||||
|
MouseDriver.UpdatePosition();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -123,44 +123,51 @@ namespace Ryujinx.Horizon.Generators.Hipc
|
|||||||
{
|
{
|
||||||
string[] args = new string[method.ParameterList.Parameters.Count];
|
string[] args = new string[method.ParameterList.Parameters.Count];
|
||||||
|
|
||||||
int index = 0;
|
if (args.Length == 0)
|
||||||
|
|
||||||
foreach (var parameter in method.ParameterList.Parameters)
|
|
||||||
{
|
{
|
||||||
string canonicalTypeName = GetCanonicalTypeNameWithGenericArguments(compilation, parameter.Type);
|
generator.AppendLine($"{{ {commandId}, new CommandHandler({method.Identifier.Text}, Array.Empty<CommandArg>()) }},");
|
||||||
CommandArgType argType = GetCommandArgType(compilation, parameter);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
string arg;
|
foreach (var parameter in method.ParameterList.Parameters)
|
||||||
|
|
||||||
if (argType == CommandArgType.Buffer)
|
|
||||||
{
|
{
|
||||||
string bufferFlags = GetFirstAttributeAgument(compilation, parameter, TypeBufferAttribute, 0);
|
string canonicalTypeName = GetCanonicalTypeNameWithGenericArguments(compilation, parameter.Type);
|
||||||
string bufferFixedSize = GetFirstAttributeAgument(compilation, parameter, TypeBufferAttribute, 1);
|
CommandArgType argType = GetCommandArgType(compilation, parameter);
|
||||||
|
|
||||||
if (bufferFixedSize != null)
|
string arg;
|
||||||
|
|
||||||
|
if (argType == CommandArgType.Buffer)
|
||||||
{
|
{
|
||||||
arg = $"new CommandArg({bufferFlags}, {bufferFixedSize})";
|
string bufferFlags = GetFirstAttributeAgument(compilation, parameter, TypeBufferAttribute, 0);
|
||||||
|
string bufferFixedSize = GetFirstAttributeAgument(compilation, parameter, TypeBufferAttribute, 1);
|
||||||
|
|
||||||
|
if (bufferFixedSize != null)
|
||||||
|
{
|
||||||
|
arg = $"new CommandArg({bufferFlags}, {bufferFixedSize})";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
arg = $"new CommandArg({bufferFlags})";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (argType == CommandArgType.InArgument || argType == CommandArgType.OutArgument)
|
||||||
|
{
|
||||||
|
string alignment = GetTypeAlignmentExpression(compilation, parameter.Type);
|
||||||
|
|
||||||
|
arg = $"new CommandArg(CommandArgType.{argType}, Unsafe.SizeOf<{canonicalTypeName}>(), {alignment})";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
arg = $"new CommandArg({bufferFlags})";
|
arg = $"new CommandArg(CommandArgType.{argType})";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (argType == CommandArgType.InArgument || argType == CommandArgType.OutArgument)
|
|
||||||
{
|
|
||||||
string alignment = GetTypeAlignmentExpression(compilation, parameter.Type);
|
|
||||||
|
|
||||||
arg = $"new CommandArg(CommandArgType.{argType}, Unsafe.SizeOf<{canonicalTypeName}>(), {alignment})";
|
args[index++] = arg;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
arg = $"new CommandArg(CommandArgType.{argType})";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
args[index++] = arg;
|
generator.AppendLine($"{{ {commandId}, new CommandHandler({method.Identifier.Text}, {string.Join(", ", args)}) }},");
|
||||||
}
|
}
|
||||||
|
|
||||||
generator.AppendLine($"{{ {commandId}, new CommandHandler({method.Identifier.Text}, {string.Join(", ", args)}) }},");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -12,12 +12,12 @@ namespace Ryujinx.Horizon
|
|||||||
private struct Range : IComparable<Range>
|
private struct Range : IComparable<Range>
|
||||||
{
|
{
|
||||||
public ulong Offset { get; }
|
public ulong Offset { get; }
|
||||||
public ulong Size { get; }
|
public ulong Size { get; }
|
||||||
|
|
||||||
public Range(ulong offset, ulong size)
|
public Range(ulong offset, ulong size)
|
||||||
{
|
{
|
||||||
Offset = offset;
|
Offset = offset;
|
||||||
Size = size;
|
Size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CompareTo(Range other)
|
public int CompareTo(Range other)
|
||||||
@@ -31,7 +31,7 @@ namespace Ryujinx.Horizon
|
|||||||
|
|
||||||
public HeapAllocator()
|
public HeapAllocator()
|
||||||
{
|
{
|
||||||
_freeRanges = new List<Range>();
|
_freeRanges = new List<Range>();
|
||||||
_currentHeapSize = 0;
|
_currentHeapSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,8 +70,8 @@ namespace Ryujinx.Horizon
|
|||||||
var range = _freeRanges[i];
|
var range = _freeRanges[i];
|
||||||
|
|
||||||
ulong alignedOffset = BitUtils.AlignUp(range.Offset, alignment);
|
ulong alignedOffset = BitUtils.AlignUp(range.Offset, alignment);
|
||||||
ulong sizeDelta = alignedOffset - range.Offset;
|
ulong sizeDelta = alignedOffset - range.Offset;
|
||||||
ulong usableSize = range.Size - sizeDelta;
|
ulong usableSize = range.Size - sizeDelta;
|
||||||
|
|
||||||
if (sizeDelta < range.Size && usableSize >= size)
|
if (sizeDelta < range.Size && usableSize >= size)
|
||||||
{
|
{
|
||||||
@@ -82,7 +82,7 @@ namespace Ryujinx.Horizon
|
|||||||
InsertFreeRange(range.Offset, sizeDelta);
|
InsertFreeRange(range.Offset, sizeDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong endOffset = range.Offset + range.Size;
|
ulong endOffset = range.Offset + range.Size;
|
||||||
ulong remainingSize = endOffset - (alignedOffset + size);
|
ulong remainingSize = endOffset - (alignedOffset + size);
|
||||||
if (remainingSize != 0)
|
if (remainingSize != 0)
|
||||||
{
|
{
|
||||||
|
@@ -2,11 +2,13 @@ namespace Ryujinx.Horizon
|
|||||||
{
|
{
|
||||||
public struct HorizonOptions
|
public struct HorizonOptions
|
||||||
{
|
{
|
||||||
public bool IgnoreMissingServices { get; }
|
public bool IgnoreMissingServices { get; }
|
||||||
|
public bool ThrowOnInvalidCommandIds { get; }
|
||||||
|
|
||||||
public HorizonOptions(bool ignoreMissingServices)
|
public HorizonOptions(bool ignoreMissingServices)
|
||||||
{
|
{
|
||||||
IgnoreMissingServices = ignoreMissingServices;
|
IgnoreMissingServices = ignoreMissingServices;
|
||||||
|
ThrowOnInvalidCommandIds = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -21,24 +21,24 @@ namespace Ryujinx.Horizon
|
|||||||
[ThreadStatic]
|
[ThreadStatic]
|
||||||
private static int _threadHandle;
|
private static int _threadHandle;
|
||||||
|
|
||||||
public static HorizonOptions Options => _options;
|
public static HorizonOptions Options => _options;
|
||||||
public static ISyscallApi Syscall => _syscall;
|
public static ISyscallApi Syscall => _syscall;
|
||||||
public static IVirtualMemoryManager AddressSpace => _addressSpace;
|
public static IVirtualMemoryManager AddressSpace => _addressSpace;
|
||||||
public static IThreadContext ThreadContext => _threadContext;
|
public static IThreadContext ThreadContext => _threadContext;
|
||||||
public static int CurrentThreadHandle => _threadHandle;
|
public static int CurrentThreadHandle => _threadHandle;
|
||||||
|
|
||||||
public static void Register(
|
public static void Register(
|
||||||
HorizonOptions options,
|
HorizonOptions options,
|
||||||
ISyscallApi syscallApi,
|
ISyscallApi syscallApi,
|
||||||
IVirtualMemoryManager addressSpace,
|
IVirtualMemoryManager addressSpace,
|
||||||
IThreadContext threadContext,
|
IThreadContext threadContext,
|
||||||
int threadHandle)
|
int threadHandle)
|
||||||
{
|
{
|
||||||
_options = options;
|
_options = options;
|
||||||
_syscall = syscallApi;
|
_syscall = syscallApi;
|
||||||
_addressSpace = addressSpace;
|
_addressSpace = addressSpace;
|
||||||
_threadContext = threadContext;
|
_threadContext = threadContext;
|
||||||
_threadHandle = threadHandle;
|
_threadHandle = threadHandle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,6 @@
|
|||||||
{
|
{
|
||||||
interface IService
|
interface IService
|
||||||
{
|
{
|
||||||
abstract static void Main();
|
abstract static void Main(ServiceTable serviceTable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,23 +9,23 @@ using System.Runtime.CompilerServices;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Ryujinx.Horizon.LogManager
|
namespace Ryujinx.Horizon.LogManager.Ipc
|
||||||
{
|
{
|
||||||
partial class LmLogger : IServiceObject
|
partial class LmLogger : ILmLogger
|
||||||
{
|
{
|
||||||
private readonly LmLog _log;
|
private readonly LogService _log;
|
||||||
private readonly ulong _clientProcessId;
|
private readonly ulong _pid;
|
||||||
|
|
||||||
public LmLogger(LmLog log, ulong clientProcessId)
|
public LmLogger(LogService log, ulong pid)
|
||||||
{
|
{
|
||||||
_log = log;
|
_log = log;
|
||||||
_clientProcessId = clientProcessId;
|
_pid = pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
[CmifCommand(0)]
|
[CmifCommand(0)]
|
||||||
public Result Log([Buffer(HipcBufferFlags.In | HipcBufferFlags.AutoSelect)] Span<byte> message)
|
public Result Log([Buffer(HipcBufferFlags.In | HipcBufferFlags.AutoSelect)] Span<byte> message)
|
||||||
{
|
{
|
||||||
if (!SetProcessId(message, _clientProcessId))
|
if (!SetProcessId(message, _pid))
|
||||||
{
|
{
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
@@ -35,7 +35,7 @@ namespace Ryujinx.Horizon.LogManager
|
|||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
[CmifCommand(1)]
|
[CmifCommand(1)] // 3.0.0+
|
||||||
public Result SetDestination(LogDestination destination)
|
public Result SetDestination(LogDestination destination)
|
||||||
{
|
{
|
||||||
_log.LogDestination = destination;
|
_log.LogDestination = destination;
|
||||||
@@ -48,7 +48,6 @@ namespace Ryujinx.Horizon.LogManager
|
|||||||
ref LogPacketHeader header = ref MemoryMarshal.Cast<byte, LogPacketHeader>(message)[0];
|
ref LogPacketHeader header = ref MemoryMarshal.Cast<byte, LogPacketHeader>(message)[0];
|
||||||
|
|
||||||
uint expectedMessageSize = (uint)Unsafe.SizeOf<LogPacketHeader>() + header.PayloadSize;
|
uint expectedMessageSize = (uint)Unsafe.SizeOf<LogPacketHeader>() + header.PayloadSize;
|
||||||
|
|
||||||
if (expectedMessageSize != (uint)message.Length)
|
if (expectedMessageSize != (uint)message.Length)
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.ServiceLm, $"Invalid message size (expected 0x{expectedMessageSize:X} but got 0x{message.Length:X}).");
|
Logger.Warning?.Print(LogClass.ServiceLm, $"Invalid message size (expected 0x{expectedMessageSize:X} but got 0x{message.Length:X}).");
|
||||||
@@ -63,13 +62,11 @@ namespace Ryujinx.Horizon.LogManager
|
|||||||
|
|
||||||
private static string LogImpl(ReadOnlySpan<byte> message)
|
private static string LogImpl(ReadOnlySpan<byte> message)
|
||||||
{
|
{
|
||||||
SpanReader reader = new SpanReader(message);
|
SpanReader reader = new(message);
|
||||||
|
LogPacketHeader header = reader.Read<LogPacketHeader>();
|
||||||
|
StringBuilder builder = new();
|
||||||
|
|
||||||
LogPacketHeader header = reader.Read<LogPacketHeader>();
|
builder.AppendLine($"Guest Log:\n Log level: {header.Severity}");
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
|
|
||||||
sb.AppendLine($"Guest Log:\n Log level: {header.Severity}");
|
|
||||||
|
|
||||||
while (reader.Length > 0)
|
while (reader.Length > 0)
|
||||||
{
|
{
|
||||||
@@ -78,7 +75,7 @@ namespace Ryujinx.Horizon.LogManager
|
|||||||
|
|
||||||
LogDataChunkKey field = (LogDataChunkKey)type;
|
LogDataChunkKey field = (LogDataChunkKey)type;
|
||||||
|
|
||||||
string fieldStr = string.Empty;
|
string fieldStr;
|
||||||
|
|
||||||
if (field == LogDataChunkKey.Start)
|
if (field == LogDataChunkKey.Start)
|
||||||
{
|
{
|
||||||
@@ -111,16 +108,16 @@ namespace Ryujinx.Horizon.LogManager
|
|||||||
fieldStr = $"Field{field}: '{Encoding.UTF8.GetString(reader.GetSpan(size)).TrimEnd()}'";
|
fieldStr = $"Field{field}: '{Encoding.UTF8.GetString(reader.GetSpan(size)).TrimEnd()}'";
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.AppendLine($" {fieldStr}");
|
builder.AppendLine($" {fieldStr}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb.ToString();
|
return builder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int ReadUleb128(ref SpanReader reader)
|
private static int ReadUleb128(ref SpanReader reader)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
byte encoded;
|
byte encoded;
|
||||||
|
|
@@ -2,16 +2,17 @@
|
|||||||
using Ryujinx.Horizon.Sdk.Lm;
|
using Ryujinx.Horizon.Sdk.Lm;
|
||||||
using Ryujinx.Horizon.Sdk.Sf;
|
using Ryujinx.Horizon.Sdk.Sf;
|
||||||
|
|
||||||
namespace Ryujinx.Horizon.LogManager
|
namespace Ryujinx.Horizon.LogManager.Ipc
|
||||||
{
|
{
|
||||||
partial class LmLog : IServiceObject
|
partial class LogService : ILogService
|
||||||
{
|
{
|
||||||
public LogDestination LogDestination { get; set; } = LogDestination.TargetManager;
|
public LogDestination LogDestination { get; set; } = LogDestination.TargetManager;
|
||||||
|
|
||||||
[CmifCommand(0)]
|
[CmifCommand(0)]
|
||||||
public Result OpenLogger(out LmLogger logger, [ClientProcessId] ulong clientProcessId)
|
public Result OpenLogger(out LmLogger logger, [ClientProcessId] ulong pid)
|
||||||
{
|
{
|
||||||
logger = new LmLogger(this, clientProcessId);
|
// NOTE: Internal name is Logger, but we rename it LmLogger to avoid name clash with Ryujinx.Common.Logging logger.
|
||||||
|
logger = new LmLogger(this, pid);
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
@@ -1,6 +1,6 @@
|
|||||||
using Ryujinx.Horizon.Sdk.Sf.Hipc;
|
using Ryujinx.Horizon.LogManager.Ipc;
|
||||||
|
using Ryujinx.Horizon.Sdk.Sf.Hipc;
|
||||||
using Ryujinx.Horizon.Sdk.Sm;
|
using Ryujinx.Horizon.Sdk.Sm;
|
||||||
using Ryujinx.Horizon.Sm;
|
|
||||||
|
|
||||||
namespace Ryujinx.Horizon.LogManager
|
namespace Ryujinx.Horizon.LogManager
|
||||||
{
|
{
|
||||||
@@ -9,36 +9,25 @@ namespace Ryujinx.Horizon.LogManager
|
|||||||
private const int LogMaxSessionsCount = 42;
|
private const int LogMaxSessionsCount = 42;
|
||||||
|
|
||||||
private const int PointerBufferSize = 0x400;
|
private const int PointerBufferSize = 0x400;
|
||||||
private const int MaxDomains = 31;
|
private const int MaxDomains = 31;
|
||||||
private const int MaxDomainObjects = 61;
|
private const int MaxDomainObjects = 61;
|
||||||
|
private const int MaxPortsCount = 1;
|
||||||
|
|
||||||
private const int MaxPortsCount = 1;
|
private static readonly ManagerOptions _logManagerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false);
|
||||||
|
|
||||||
private static readonly ManagerOptions _logManagerOptions = new ManagerOptions(
|
private SmApi _sm;
|
||||||
PointerBufferSize,
|
|
||||||
MaxDomains,
|
|
||||||
MaxDomainObjects,
|
|
||||||
false);
|
|
||||||
|
|
||||||
private static readonly ServiceName _logServiceName = ServiceName.Encode("lm");
|
|
||||||
|
|
||||||
private SmApi _sm;
|
|
||||||
private ServerManager _serverManager;
|
private ServerManager _serverManager;
|
||||||
|
|
||||||
private LmLog _logServiceObject;
|
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
HeapAllocator allocator = new HeapAllocator();
|
HeapAllocator allocator = new();
|
||||||
|
|
||||||
_sm = new SmApi();
|
_sm = new SmApi();
|
||||||
_sm.Initialize().AbortOnFailure();
|
_sm.Initialize().AbortOnFailure();
|
||||||
|
|
||||||
_serverManager = new ServerManager(allocator, _sm, MaxPortsCount, _logManagerOptions, LogMaxSessionsCount);
|
_serverManager = new ServerManager(allocator, _sm, MaxPortsCount, _logManagerOptions, LogMaxSessionsCount);
|
||||||
|
|
||||||
_logServiceObject = new LmLog();
|
_serverManager.RegisterObjectForServer(new LogService(), ServiceName.Encode("lm"), LogMaxSessionsCount);
|
||||||
|
|
||||||
_serverManager.RegisterObjectForServer(_logServiceObject, _logServiceName, LogMaxSessionsCount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ServiceRequests()
|
public void ServiceRequests()
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user