Compare commits
31 Commits
Author | SHA1 | Date | |
---|---|---|---|
121296834a | |||
bbb24d8c7e | |||
4da44e09cb | |||
ae13f0ab4d | |||
a2a35f1be6 | |||
aedfadaaf7 | |||
5c0fb0cec3 | |||
17a1cab5d2 | |||
73aed239c3 | |||
9ac66336a2 | |||
4965681e06 | |||
3868a00206 | |||
933e5144a9 | |||
73a42c85c4 | |||
39ba11054b | |||
c250e3392c | |||
e56b069081 | |||
204c031fef | |||
d9053bbe37 | |||
c25e8427aa | |||
21a081b185 | |||
b540ea80d1 | |||
d692a9b83e | |||
9677ddaa5d | |||
ce92e8cd04 | |||
456fc04007 | |||
458452279c | |||
817b89767a | |||
3fb583c98c | |||
d2686e0a5b | |||
4905101df1 |
@ -89,6 +89,7 @@ csharp_style_conditional_delegate_call = true:suggestion
|
|||||||
# Modifier preferences
|
# Modifier preferences
|
||||||
csharp_prefer_static_local_function = true:suggestion
|
csharp_prefer_static_local_function = true:suggestion
|
||||||
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
|
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
|
||||||
|
csharp_style_prefer_readonly_struct = true
|
||||||
|
|
||||||
# Code-block preferences
|
# Code-block preferences
|
||||||
csharp_prefer_braces = true:silent
|
csharp_prefer_braces = true:silent
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace ARMeilleure.CodeGen.RegisterAllocators
|
namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||||
{
|
{
|
||||||
struct AllocationResult
|
readonly struct AllocationResult
|
||||||
{
|
{
|
||||||
public int IntUsedRegisters { get; }
|
public int IntUsedRegisters { get; }
|
||||||
public int VecUsedRegisters { get; }
|
public int VecUsedRegisters { get; }
|
||||||
|
@ -11,7 +11,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
{
|
{
|
||||||
private class ParallelCopy
|
private class ParallelCopy
|
||||||
{
|
{
|
||||||
private struct Copy
|
private readonly struct Copy
|
||||||
{
|
{
|
||||||
public Register Dest { get; }
|
public Register Dest { get; }
|
||||||
public Register Source { get; }
|
public Register Source { get; }
|
||||||
|
@ -11,7 +11,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
{
|
{
|
||||||
class HybridAllocator : IRegisterAllocator
|
class HybridAllocator : IRegisterAllocator
|
||||||
{
|
{
|
||||||
private struct BlockInfo
|
private readonly struct BlockInfo
|
||||||
{
|
{
|
||||||
public bool HasCall { get; }
|
public bool HasCall { get; }
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ using System;
|
|||||||
|
|
||||||
namespace ARMeilleure.CodeGen.RegisterAllocators
|
namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||||
{
|
{
|
||||||
struct RegisterMasks
|
readonly struct RegisterMasks
|
||||||
{
|
{
|
||||||
public int IntAvailableRegisters { get; }
|
public int IntAvailableRegisters { get; }
|
||||||
public int VecAvailableRegisters { get; }
|
public int VecAvailableRegisters { get; }
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace ARMeilleure.CodeGen.X86
|
namespace ARMeilleure.CodeGen.X86
|
||||||
{
|
{
|
||||||
struct IntrinsicInfo
|
readonly struct IntrinsicInfo
|
||||||
{
|
{
|
||||||
public X86Instruction Inst { get; }
|
public X86Instruction Inst { get; }
|
||||||
public IntrinsicType Type { get; }
|
public IntrinsicType Type { get; }
|
||||||
|
@ -2,7 +2,7 @@ using ARMeilleure.Instructions;
|
|||||||
|
|
||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
struct InstDescriptor
|
readonly struct InstDescriptor
|
||||||
{
|
{
|
||||||
public static InstDescriptor Undefined => new InstDescriptor(InstName.Und, InstEmit.Und);
|
public static InstDescriptor Undefined => new InstDescriptor(InstName.Und, InstEmit.Und);
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ namespace ARMeilleure.Decoders
|
|||||||
|
|
||||||
private const int FastLookupSize = 0x1000;
|
private const int FastLookupSize = 0x1000;
|
||||||
|
|
||||||
private struct InstInfo
|
private readonly struct InstInfo
|
||||||
{
|
{
|
||||||
public int Mask { get; }
|
public int Mask { get; }
|
||||||
public int Value { get; }
|
public int Value { get; }
|
||||||
|
@ -6,7 +6,7 @@ namespace ARMeilleure.Diagnostics
|
|||||||
{
|
{
|
||||||
static class Symbols
|
static class Symbols
|
||||||
{
|
{
|
||||||
private struct RangedSymbol
|
private readonly struct RangedSymbol
|
||||||
{
|
{
|
||||||
public readonly ulong Start;
|
public readonly ulong Start;
|
||||||
public readonly ulong End;
|
public readonly ulong End;
|
||||||
|
@ -3,7 +3,7 @@ using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
|||||||
|
|
||||||
namespace ARMeilleure.IntermediateRepresentation
|
namespace ARMeilleure.IntermediateRepresentation
|
||||||
{
|
{
|
||||||
struct PhiOperation
|
readonly struct PhiOperation
|
||||||
{
|
{
|
||||||
private readonly Operation _operation;
|
private readonly Operation _operation;
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ using System;
|
|||||||
|
|
||||||
namespace ARMeilleure.IntermediateRepresentation
|
namespace ARMeilleure.IntermediateRepresentation
|
||||||
{
|
{
|
||||||
struct Register : IEquatable<Register>
|
readonly struct Register : IEquatable<Register>
|
||||||
{
|
{
|
||||||
public int Index { get; }
|
public int Index { get; }
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ using System.Diagnostics.CodeAnalysis;
|
|||||||
|
|
||||||
namespace ARMeilleure.Translation.Cache
|
namespace ARMeilleure.Translation.Cache
|
||||||
{
|
{
|
||||||
struct CacheEntry : IComparable<CacheEntry>
|
readonly struct CacheEntry : IComparable<CacheEntry>
|
||||||
{
|
{
|
||||||
public int Offset { get; }
|
public int Offset { get; }
|
||||||
public int Size { get; }
|
public int Size { get; }
|
||||||
|
@ -6,7 +6,7 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
{
|
{
|
||||||
class CacheMemoryAllocator
|
class CacheMemoryAllocator
|
||||||
{
|
{
|
||||||
private struct MemoryBlock : IComparable<MemoryBlock>
|
private readonly struct MemoryBlock : IComparable<MemoryBlock>
|
||||||
{
|
{
|
||||||
public int Offset { get; }
|
public int Offset { get; }
|
||||||
public int Size { get; }
|
public int Size { get; }
|
||||||
|
@ -2,7 +2,7 @@ using ARMeilleure.IntermediateRepresentation;
|
|||||||
|
|
||||||
namespace ARMeilleure.Translation
|
namespace ARMeilleure.Translation
|
||||||
{
|
{
|
||||||
struct CompilerContext
|
readonly struct CompilerContext
|
||||||
{
|
{
|
||||||
public ControlFlowGraph Cfg { get; }
|
public ControlFlowGraph Cfg { get; }
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ namespace ARMeilleure.Translation
|
|||||||
private const int RegsCount = 32;
|
private const int RegsCount = 32;
|
||||||
private const int RegsMask = RegsCount - 1;
|
private const int RegsMask = RegsCount - 1;
|
||||||
|
|
||||||
private struct RegisterMask : IEquatable<RegisterMask>
|
private readonly struct RegisterMask : IEquatable<RegisterMask>
|
||||||
{
|
{
|
||||||
public long IntMask => Mask.GetElement(0);
|
public long IntMask => Mask.GetElement(0);
|
||||||
public long VecMask => Mask.GetElement(1);
|
public long VecMask => Mask.GetElement(1);
|
||||||
|
@ -293,7 +293,7 @@ namespace ARMeilleure.Translation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct Range
|
private readonly struct Range
|
||||||
{
|
{
|
||||||
public ulong Start { get; }
|
public ulong Start { get; }
|
||||||
public ulong End { get; }
|
public ulong End { get; }
|
||||||
|
@ -21,6 +21,10 @@
|
|||||||
<img src="https://github.com/Ryujinx/Ryujinx/actions/workflows/release.yml/badge.svg"
|
<img src="https://github.com/Ryujinx/Ryujinx/actions/workflows/release.yml/badge.svg"
|
||||||
alt="">
|
alt="">
|
||||||
</a>
|
</a>
|
||||||
|
<a href="https://crwd.in/ryujinx">
|
||||||
|
<img src="https://badges.crowdin.net/ryujinx/localized.svg"
|
||||||
|
alt="">
|
||||||
|
</a>
|
||||||
<a href="https://discord.com/invite/VkQYXAZ">
|
<a href="https://discord.com/invite/VkQYXAZ">
|
||||||
<img src="https://img.shields.io/discord/410208534861447168?color=5865F2&label=Ryujinx&logo=discord&logoColor=white"
|
<img src="https://img.shields.io/discord/410208534861447168?color=5865F2&label=Ryujinx&logo=discord&logoColor=white"
|
||||||
alt="Discord">
|
alt="Discord">
|
||||||
@ -48,6 +52,8 @@ See our [Setup & Configuration Guide](https://github.com/Ryujinx/Ryujinx/wiki/Ry
|
|||||||
For our Local Wireless and LAN builds, see our [Multiplayer: Local Play/Local Wireless Guide
|
For our Local Wireless and LAN builds, see our [Multiplayer: Local Play/Local Wireless Guide
|
||||||
](https://github.com/Ryujinx/Ryujinx/wiki/Multiplayer-(LDN-Local-Wireless)-Guide).
|
](https://github.com/Ryujinx/Ryujinx/wiki/Multiplayer-(LDN-Local-Wireless)-Guide).
|
||||||
|
|
||||||
|
Avalonia UI comes with translations for various languages. See [Crowdin](https://crwd.in/ryujinx) for more information.
|
||||||
|
|
||||||
## Latest build
|
## Latest build
|
||||||
|
|
||||||
These builds are compiled automatically for each commit on the master branch. While we strive to ensure optimal stability and performance prior to pushing an update, our automated builds **may be unstable or completely broken.**
|
These builds are compiled automatically for each commit on the master branch. While we strive to ensure optimal stability and performance prior to pushing an update, our automated builds **may be unstable or completely broken.**
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using Ryujinx.Audio.Common;
|
using Ryujinx.Audio.Common;
|
||||||
using Ryujinx.Audio.Integration;
|
using Ryujinx.Audio.Integration;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using Ryujinx.SDL2.Common;
|
using Ryujinx.SDL2.Common;
|
||||||
using System;
|
using System;
|
||||||
@ -112,6 +113,9 @@ namespace Ryujinx.Audio.Backends.SDL2
|
|||||||
|
|
||||||
if (device == 0)
|
if (device == 0)
|
||||||
{
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application,
|
||||||
|
$"SDL2 open audio device initialization failed with error \"{SDL_GetError()}\"");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,6 +123,7 @@ namespace Ryujinx.Audio.Backends.SDL2
|
|||||||
|
|
||||||
if (!isValid)
|
if (!isValid)
|
||||||
{
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, "SDL2 open audio device is not valid");
|
||||||
SDL_CloseAudioDevice(device);
|
SDL_CloseAudioDevice(device);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -4,7 +4,7 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
namespace SoundIOSharp
|
namespace SoundIOSharp
|
||||||
{
|
{
|
||||||
public struct SoundIOChannelLayout
|
public readonly struct SoundIOChannelLayout
|
||||||
{
|
{
|
||||||
public static int BuiltInCount
|
public static int BuiltInCount
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace SoundIOSharp
|
namespace SoundIOSharp
|
||||||
{
|
{
|
||||||
public struct SoundIOSampleRateRange
|
public readonly struct SoundIOSampleRateRange
|
||||||
{
|
{
|
||||||
internal SoundIOSampleRateRange(int min, int max)
|
internal SoundIOSampleRateRange(int min, int max)
|
||||||
{
|
{
|
||||||
|
@ -116,6 +116,11 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool HasRemainingCommands(int sessionId)
|
||||||
|
{
|
||||||
|
return _sessionCommandList[sessionId] != null;
|
||||||
|
}
|
||||||
|
|
||||||
public void Signal()
|
public void Signal()
|
||||||
{
|
{
|
||||||
_mailbox.SendMessage(MailboxMessage.RenderStart);
|
_mailbox.SendMessage(MailboxMessage.RenderStart);
|
||||||
|
@ -670,6 +670,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
{
|
{
|
||||||
_terminationEvent.Reset();
|
_terminationEvent.Reset();
|
||||||
|
|
||||||
|
if (!_manager.Processor.HasRemainingCommands(_sessionId))
|
||||||
|
{
|
||||||
GenerateCommandList(out CommandList commands);
|
GenerateCommandList(out CommandList commands);
|
||||||
|
|
||||||
_manager.Processor.Send(_sessionId,
|
_manager.Processor.Send(_sessionId,
|
||||||
@ -680,6 +682,11 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
_systemEvent.Signal();
|
_systemEvent.Signal();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
_isDspRunningBehind = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
_terminationEvent.Set();
|
_terminationEvent.Set();
|
||||||
}
|
}
|
||||||
|
@ -168,6 +168,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "Direkter Tastaturzugriff",
|
"SettingsTabInputDirectKeyboardAccess": "Direkter Tastaturzugriff",
|
||||||
"SettingsButtonSave": "Speichern",
|
"SettingsButtonSave": "Speichern",
|
||||||
"SettingsButtonClose": "Schließen",
|
"SettingsButtonClose": "Schließen",
|
||||||
|
"SettingsButtonOk": "OK",
|
||||||
|
"SettingsButtonCancel": "Abbrechen",
|
||||||
"SettingsButtonApply": "Übernehmen",
|
"SettingsButtonApply": "Übernehmen",
|
||||||
"ControllerSettingsPlayer": "Spieler",
|
"ControllerSettingsPlayer": "Spieler",
|
||||||
"ControllerSettingsPlayer1": "Spieler 1",
|
"ControllerSettingsPlayer1": "Spieler 1",
|
||||||
|
@ -168,6 +168,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "Άμεση Πρόσβαση στο Πληκτρολόγιο",
|
"SettingsTabInputDirectKeyboardAccess": "Άμεση Πρόσβαση στο Πληκτρολόγιο",
|
||||||
"SettingsButtonSave": "Αποθήκευση",
|
"SettingsButtonSave": "Αποθήκευση",
|
||||||
"SettingsButtonClose": "Κλείσιμο",
|
"SettingsButtonClose": "Κλείσιμο",
|
||||||
|
"SettingsButtonOk": "OK",
|
||||||
|
"SettingsButtonCancel": "Ακύρωση",
|
||||||
"SettingsButtonApply": "Εφαρμογή",
|
"SettingsButtonApply": "Εφαρμογή",
|
||||||
"ControllerSettingsPlayer": "Παίχτης",
|
"ControllerSettingsPlayer": "Παίχτης",
|
||||||
"ControllerSettingsPlayer1": "Παίχτης 1",
|
"ControllerSettingsPlayer1": "Παίχτης 1",
|
||||||
|
@ -168,6 +168,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "Direct Keyboard Access",
|
"SettingsTabInputDirectKeyboardAccess": "Direct Keyboard Access",
|
||||||
"SettingsButtonSave": "Save",
|
"SettingsButtonSave": "Save",
|
||||||
"SettingsButtonClose": "Close",
|
"SettingsButtonClose": "Close",
|
||||||
|
"SettingsButtonOk": "OK",
|
||||||
|
"SettingsButtonCancel": "Cancel",
|
||||||
"SettingsButtonApply": "Apply",
|
"SettingsButtonApply": "Apply",
|
||||||
"ControllerSettingsPlayer": "Player",
|
"ControllerSettingsPlayer": "Player",
|
||||||
"ControllerSettingsPlayer1": "Player 1",
|
"ControllerSettingsPlayer1": "Player 1",
|
||||||
@ -594,7 +596,18 @@
|
|||||||
"RyujinxUpdaterMessage": "Do you want to update Ryujinx to the latest version?",
|
"RyujinxUpdaterMessage": "Do you want to update Ryujinx to the latest version?",
|
||||||
"SettingsTabHotkeysVolumeUpHotkey": "Increase Volume:",
|
"SettingsTabHotkeysVolumeUpHotkey": "Increase Volume:",
|
||||||
"SettingsTabHotkeysVolumeDownHotkey": "Decrease Volume:",
|
"SettingsTabHotkeysVolumeDownHotkey": "Decrease Volume:",
|
||||||
"VolumeShort": "Vol",
|
|
||||||
"SettingsEnableMacroHLE": "Enable Macro HLE",
|
"SettingsEnableMacroHLE": "Enable Macro HLE",
|
||||||
"SettingsEnableMacroHLETooltip": "High-level emulation of GPU Macro code.\n\nImproves performance, but may cause graphical glitches in some games.\n\nLeave ON if unsure."
|
"SettingsEnableMacroHLETooltip": "High-level emulation of GPU Macro code.\n\nImproves performance, but may cause graphical glitches in some games.\n\nLeave ON if unsure.",
|
||||||
|
"VolumeShort": "Vol",
|
||||||
|
"UserProfilesManageSaves": "Manage Saves",
|
||||||
|
"DeleteUserSave": "Do you want to delete user save for this game?",
|
||||||
|
"IrreversibleActionNote": "This action is not reversible.",
|
||||||
|
"SaveManagerHeading": "Manage Saves for {0}",
|
||||||
|
"SaveManagerTitle": "Save Manager",
|
||||||
|
"Name": "Name",
|
||||||
|
"Size": "Size",
|
||||||
|
"Search": "Search",
|
||||||
|
"UserProfilesRecoverLostAccounts": "Recover Lost Accounts",
|
||||||
|
"Recover": "Recover",
|
||||||
|
"UserProfilesRecoverHeading" : "Saves were found for the following accounts"
|
||||||
}
|
}
|
||||||
|
@ -168,6 +168,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "Acceso directo al teclado",
|
"SettingsTabInputDirectKeyboardAccess": "Acceso directo al teclado",
|
||||||
"SettingsButtonSave": "Guardar",
|
"SettingsButtonSave": "Guardar",
|
||||||
"SettingsButtonClose": "Cerrar",
|
"SettingsButtonClose": "Cerrar",
|
||||||
|
"SettingsButtonOk": "OK",
|
||||||
|
"SettingsButtonCancel": "Cancelar",
|
||||||
"SettingsButtonApply": "Aplicar",
|
"SettingsButtonApply": "Aplicar",
|
||||||
"ControllerSettingsPlayer": "Jugador",
|
"ControllerSettingsPlayer": "Jugador",
|
||||||
"ControllerSettingsPlayer1": "Jugador 1",
|
"ControllerSettingsPlayer1": "Jugador 1",
|
||||||
|
@ -161,6 +161,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "Accès direct au clavier",
|
"SettingsTabInputDirectKeyboardAccess": "Accès direct au clavier",
|
||||||
"SettingsButtonSave": "Enregistrer",
|
"SettingsButtonSave": "Enregistrer",
|
||||||
"SettingsButtonClose": "Fermer",
|
"SettingsButtonClose": "Fermer",
|
||||||
|
"SettingsButtonOk": "OK",
|
||||||
|
"SettingsButtonCancel": "Annuler",
|
||||||
"SettingsButtonApply": "Appliquer",
|
"SettingsButtonApply": "Appliquer",
|
||||||
"ControllerSettingsPlayer": "Joueur",
|
"ControllerSettingsPlayer": "Joueur",
|
||||||
"ControllerSettingsPlayer1": "Joueur 1",
|
"ControllerSettingsPlayer1": "Joueur 1",
|
||||||
|
@ -168,6 +168,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "Accesso diretto alla tastiera",
|
"SettingsTabInputDirectKeyboardAccess": "Accesso diretto alla tastiera",
|
||||||
"SettingsButtonSave": "Salva",
|
"SettingsButtonSave": "Salva",
|
||||||
"SettingsButtonClose": "Chiudi",
|
"SettingsButtonClose": "Chiudi",
|
||||||
|
"SettingsButtonOk": "OK",
|
||||||
|
"SettingsButtonCancel": "Cancella",
|
||||||
"SettingsButtonApply": "Applica",
|
"SettingsButtonApply": "Applica",
|
||||||
"ControllerSettingsPlayer": "Giocatore",
|
"ControllerSettingsPlayer": "Giocatore",
|
||||||
"ControllerSettingsPlayer1": "Giocatore 1",
|
"ControllerSettingsPlayer1": "Giocatore 1",
|
||||||
|
@ -168,6 +168,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "キーボード直接アクセス",
|
"SettingsTabInputDirectKeyboardAccess": "キーボード直接アクセス",
|
||||||
"SettingsButtonSave": "セーブ",
|
"SettingsButtonSave": "セーブ",
|
||||||
"SettingsButtonClose": "閉じる",
|
"SettingsButtonClose": "閉じる",
|
||||||
|
"SettingsButtonOk": "オーケー",
|
||||||
|
"SettingsButtonCancel": "キャンセル",
|
||||||
"SettingsButtonApply": "適用",
|
"SettingsButtonApply": "適用",
|
||||||
"ControllerSettingsPlayer": "プレイヤー",
|
"ControllerSettingsPlayer": "プレイヤー",
|
||||||
"ControllerSettingsPlayer1": "プレイヤー 1",
|
"ControllerSettingsPlayer1": "プレイヤー 1",
|
||||||
|
@ -167,6 +167,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "직접 키보드 액세스",
|
"SettingsTabInputDirectKeyboardAccess": "직접 키보드 액세스",
|
||||||
"SettingsButtonSave": "구하다",
|
"SettingsButtonSave": "구하다",
|
||||||
"SettingsButtonClose": "출구",
|
"SettingsButtonClose": "출구",
|
||||||
|
"SettingsButtonOk": "좋아",
|
||||||
|
"SettingsButtonCancel": "취소",
|
||||||
"SettingsButtonApply": "적용하다",
|
"SettingsButtonApply": "적용하다",
|
||||||
"ControllerSettingsPlayer": "플레이어",
|
"ControllerSettingsPlayer": "플레이어",
|
||||||
"ControllerSettingsPlayer1": "플레이어 1",
|
"ControllerSettingsPlayer1": "플레이어 1",
|
||||||
|
@ -168,6 +168,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "Bezpośredni Dostęp do Klawiatury",
|
"SettingsTabInputDirectKeyboardAccess": "Bezpośredni Dostęp do Klawiatury",
|
||||||
"SettingsButtonSave": "Zapisz",
|
"SettingsButtonSave": "Zapisz",
|
||||||
"SettingsButtonClose": "Zamknij",
|
"SettingsButtonClose": "Zamknij",
|
||||||
|
"SettingsButtonOk": "OK",
|
||||||
|
"SettingsButtonCancel": "Anuluj",
|
||||||
"SettingsButtonApply": "Zastosuj",
|
"SettingsButtonApply": "Zastosuj",
|
||||||
"ControllerSettingsPlayer": "Gracz",
|
"ControllerSettingsPlayer": "Gracz",
|
||||||
"ControllerSettingsPlayer1": "Gracz 1",
|
"ControllerSettingsPlayer1": "Gracz 1",
|
||||||
|
@ -168,6 +168,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "Acesso direto ao teclado",
|
"SettingsTabInputDirectKeyboardAccess": "Acesso direto ao teclado",
|
||||||
"SettingsButtonSave": "Salvar",
|
"SettingsButtonSave": "Salvar",
|
||||||
"SettingsButtonClose": "Fechar",
|
"SettingsButtonClose": "Fechar",
|
||||||
|
"SettingsButtonOk": "OK",
|
||||||
|
"SettingsButtonCancel": "Cancelar",
|
||||||
"SettingsButtonApply": "Aplicar",
|
"SettingsButtonApply": "Aplicar",
|
||||||
"ControllerSettingsPlayer": "Jogador",
|
"ControllerSettingsPlayer": "Jogador",
|
||||||
"ControllerSettingsPlayer1": "Jogador 1",
|
"ControllerSettingsPlayer1": "Jogador 1",
|
||||||
|
@ -167,6 +167,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "Прямой доступ с клавиатуры",
|
"SettingsTabInputDirectKeyboardAccess": "Прямой доступ с клавиатуры",
|
||||||
"SettingsButtonSave": "Сохранить",
|
"SettingsButtonSave": "Сохранить",
|
||||||
"SettingsButtonClose": "Закрыть",
|
"SettingsButtonClose": "Закрыть",
|
||||||
|
"SettingsButtonOk": "OK",
|
||||||
|
"SettingsButtonCancel": "Отмена",
|
||||||
"SettingsButtonApply": "Применить",
|
"SettingsButtonApply": "Применить",
|
||||||
"ControllerSettingsPlayer": "Игрок",
|
"ControllerSettingsPlayer": "Игрок",
|
||||||
"ControllerSettingsPlayer1": "Игрок 1",
|
"ControllerSettingsPlayer1": "Игрок 1",
|
||||||
|
@ -168,6 +168,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "Doğrudan Klavye Erişimi",
|
"SettingsTabInputDirectKeyboardAccess": "Doğrudan Klavye Erişimi",
|
||||||
"SettingsButtonSave": "Kaydet",
|
"SettingsButtonSave": "Kaydet",
|
||||||
"SettingsButtonClose": "Kapat",
|
"SettingsButtonClose": "Kapat",
|
||||||
|
"SettingsButtonOk": "Tamam",
|
||||||
|
"SettingsButtonCancel": "İptal",
|
||||||
"SettingsButtonApply": "Uygula",
|
"SettingsButtonApply": "Uygula",
|
||||||
"ControllerSettingsPlayer": "Oyuncu",
|
"ControllerSettingsPlayer": "Oyuncu",
|
||||||
"ControllerSettingsPlayer1": "Oyuncu 1",
|
"ControllerSettingsPlayer1": "Oyuncu 1",
|
||||||
|
@ -168,6 +168,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "直通键盘控制",
|
"SettingsTabInputDirectKeyboardAccess": "直通键盘控制",
|
||||||
"SettingsButtonSave": "保存",
|
"SettingsButtonSave": "保存",
|
||||||
"SettingsButtonClose": "关闭",
|
"SettingsButtonClose": "关闭",
|
||||||
|
"SettingsButtonOk": "批准",
|
||||||
|
"SettingsButtonCancel": "取消",
|
||||||
"SettingsButtonApply": "应用",
|
"SettingsButtonApply": "应用",
|
||||||
"ControllerSettingsPlayer": "玩家",
|
"ControllerSettingsPlayer": "玩家",
|
||||||
"ControllerSettingsPlayer1": "玩家 1",
|
"ControllerSettingsPlayer1": "玩家 1",
|
||||||
|
@ -168,6 +168,8 @@
|
|||||||
"SettingsTabInputDirectKeyboardAccess": "直通鍵盤控制",
|
"SettingsTabInputDirectKeyboardAccess": "直通鍵盤控制",
|
||||||
"SettingsButtonSave": "儲存",
|
"SettingsButtonSave": "儲存",
|
||||||
"SettingsButtonClose": "關閉",
|
"SettingsButtonClose": "關閉",
|
||||||
|
"SettingsButtonOk": "嘛好",
|
||||||
|
"SettingsButtonCancel": "取消",
|
||||||
"SettingsButtonApply": "套用",
|
"SettingsButtonApply": "套用",
|
||||||
"ControllerSettingsPlayer": "玩家",
|
"ControllerSettingsPlayer": "玩家",
|
||||||
"ControllerSettingsPlayer1": "玩家 1",
|
"ControllerSettingsPlayer1": "玩家 1",
|
||||||
|
@ -41,6 +41,9 @@
|
|||||||
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush" Color="{DynamicResource DataGridSelectionColor}" />
|
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush" Color="{DynamicResource DataGridSelectionColor}" />
|
||||||
<SolidColorBrush x:Key="ThemeAccentColorBrush" Color="{DynamicResource SystemAccentColor}" />
|
<SolidColorBrush x:Key="ThemeAccentColorBrush" Color="{DynamicResource SystemAccentColor}" />
|
||||||
<SolidColorBrush x:Key="ThemeAccentBrush4" Color="{DynamicResource ThemeAccentColor4}" />
|
<SolidColorBrush x:Key="ThemeAccentBrush4" Color="{DynamicResource ThemeAccentColor4}" />
|
||||||
|
<Color x:Key="ControlFillColorSecondary">#008AA8</Color>
|
||||||
|
<SolidColorBrush x:Key="ControlFillColorSecondaryBrush" Color="{StaticResource ControlFillColorSecondary}" />
|
||||||
|
<StaticResource x:Key="ButtonBackgroundPointerOver" ResourceKey="ControlFillColorSecondaryBrush" />
|
||||||
<Color x:Key="SystemAccentColor">#FF00C3E3</Color>
|
<Color x:Key="SystemAccentColor">#FF00C3E3</Color>
|
||||||
<Color x:Key="SystemAccentColorDark1">#FF99b000</Color>
|
<Color x:Key="SystemAccentColorDark1">#FF99b000</Color>
|
||||||
<Color x:Key="SystemAccentColorDark2">#FF006d7d</Color>
|
<Color x:Key="SystemAccentColorDark2">#FF006d7d</Color>
|
||||||
@ -55,5 +58,7 @@
|
|||||||
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
|
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
|
||||||
<Color x:Key="ThemeForegroundColor">#FFFFFFFF</Color>
|
<Color x:Key="ThemeForegroundColor">#FFFFFFFF</Color>
|
||||||
<Color x:Key="MenuFlyoutPresenterBorderColor">#3D3D3D</Color>
|
<Color x:Key="MenuFlyoutPresenterBorderColor">#3D3D3D</Color>
|
||||||
|
<Color x:Key="AppListBackgroundColor">#0FFFFFFF</Color>
|
||||||
|
<Color x:Key="AppListHoverBackgroundColor">#1EFFFFFF</Color>
|
||||||
</Styles.Resources>
|
</Styles.Resources>
|
||||||
</Styles>
|
</Styles>
|
@ -50,5 +50,7 @@
|
|||||||
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
|
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
|
||||||
<Color x:Key="ThemeForegroundColor">#FF000000</Color>
|
<Color x:Key="ThemeForegroundColor">#FF000000</Color>
|
||||||
<Color x:Key="MenuFlyoutPresenterBorderColor">#C1C1C1</Color>
|
<Color x:Key="MenuFlyoutPresenterBorderColor">#C1C1C1</Color>
|
||||||
|
<Color x:Key="AppListBackgroundColor">#b3ffffff</Color>
|
||||||
|
<Color x:Key="AppListHoverBackgroundColor">#80cccccc</Color>
|
||||||
</Styles.Resources>
|
</Styles.Resources>
|
||||||
</Styles>
|
</Styles>
|
@ -1,7 +1,6 @@
|
|||||||
<Styles
|
<Styles
|
||||||
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:sys="clr-namespace:System;assembly=netstandard"
|
|
||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia">
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia">
|
||||||
<Design.PreviewWith>
|
<Design.PreviewWith>
|
||||||
<Border Height="2000" Padding="20">
|
<Border Height="2000" Padding="20">
|
||||||
@ -269,13 +268,15 @@
|
|||||||
<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>
|
||||||
<sys:Double x:Key="ScrollBarThickness">15</sys:Double>
|
<x:Double x:Key="ScrollBarThickness">15</x:Double>
|
||||||
<sys:Double x:Key="FontSizeSmall">8</sys:Double>
|
<x:Double x:Key="FontSizeSmall">8</x:Double>
|
||||||
<sys:Double x:Key="FontSizeNormal">10</sys:Double>
|
<x:Double x:Key="FontSizeNormal">10</x:Double>
|
||||||
<sys:Double x:Key="FontSize">12</sys:Double>
|
<x:Double x:Key="FontSize">12</x:Double>
|
||||||
<sys:Double x:Key="FontSizeLarge">15</sys:Double>
|
<x:Double x:Key="FontSizeLarge">15</x:Double>
|
||||||
<sys:Double x:Key="ControlContentThemeFontSize">13</sys:Double>
|
<x:Double x:Key="ControlContentThemeFontSize">13</x:Double>
|
||||||
<x:Double x:Key="MenuItemHeight">26</x:Double>
|
<x:Double x:Key="MenuItemHeight">26</x:Double>
|
||||||
<x:Double x:Key="TabItemMinHeight">28</x:Double>
|
<x:Double x:Key="TabItemMinHeight">28</x:Double>
|
||||||
|
<x:Double x:Key="ContentDialogMaxWidth">600</x:Double>
|
||||||
|
<x:Double x:Key="ContentDialogMaxHeight">756</x:Double>
|
||||||
</Styles.Resources>
|
</Styles.Resources>
|
||||||
</Styles>
|
</Styles>
|
@ -113,6 +113,11 @@ namespace Ryujinx.Ava.Common
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OpenSaveDir(saveDataId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void OpenSaveDir(ulong saveDataId)
|
||||||
|
{
|
||||||
string saveRootPath = Path.Combine(_virtualFileSystem.GetNandPath(), $"user/save/{saveDataId:x16}");
|
string saveRootPath = Path.Combine(_virtualFileSystem.GetNandPath(), $"user/save/{saveDataId:x16}");
|
||||||
|
|
||||||
if (!Directory.Exists(saveRootPath))
|
if (!Directory.Exists(saveRootPath))
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
using ARMeilleure.Translation.PTC;
|
using ARMeilleure.Translation.PTC;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Rendering;
|
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using Ryujinx.Ava.Ui.Controls;
|
|
||||||
using Ryujinx.Ava.Ui.Windows;
|
using Ryujinx.Ava.Ui.Windows;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
@ -11,6 +9,7 @@ using Ryujinx.Common.Logging;
|
|||||||
using Ryujinx.Common.System;
|
using Ryujinx.Common.System;
|
||||||
using Ryujinx.Common.SystemInfo;
|
using Ryujinx.Common.SystemInfo;
|
||||||
using Ryujinx.Modules;
|
using Ryujinx.Modules;
|
||||||
|
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;
|
||||||
@ -24,17 +23,14 @@ namespace Ryujinx.Ava
|
|||||||
internal class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
public static double WindowScaleFactor { get; set; }
|
public static double WindowScaleFactor { get; set; }
|
||||||
public static double ActualScaleFactor { get; set; }
|
|
||||||
public static string Version { get; private set; }
|
public static string Version { get; private set; }
|
||||||
public static string ConfigurationPath { get; private set; }
|
public static string ConfigurationPath { get; private set; }
|
||||||
public static bool PreviewerDetached { get; private set; }
|
public static bool PreviewerDetached { get; private set; }
|
||||||
public static RenderTimer RenderTimer { get; private set; }
|
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
public static extern int MessageBoxA(IntPtr hWnd, string text, string caption, uint type);
|
public static extern int MessageBoxA(IntPtr hWnd, string text, string caption, uint type);
|
||||||
|
|
||||||
private const uint MB_ICONWARNING = 0x30;
|
private const uint MB_ICONWARNING = 0x30;
|
||||||
private const int BaseDpi = 96;
|
|
||||||
|
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
@ -49,11 +45,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
Initialize(args);
|
Initialize(args);
|
||||||
|
|
||||||
RenderTimer = new RenderTimer();
|
|
||||||
|
|
||||||
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
|
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
|
||||||
|
|
||||||
RenderTimer.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AppBuilder BuildAvaloniaApp()
|
public static AppBuilder BuildAvaloniaApp()
|
||||||
@ -65,7 +57,7 @@ namespace Ryujinx.Ava
|
|||||||
EnableMultiTouch = true,
|
EnableMultiTouch = true,
|
||||||
EnableIme = true,
|
EnableIme = true,
|
||||||
UseEGL = false,
|
UseEGL = false,
|
||||||
UseGpu = false
|
UseGpu = true
|
||||||
})
|
})
|
||||||
.With(new Win32PlatformOptions
|
.With(new Win32PlatformOptions
|
||||||
{
|
{
|
||||||
@ -75,12 +67,6 @@ namespace Ryujinx.Ava
|
|||||||
CompositionBackdropCornerRadius = 8.0f,
|
CompositionBackdropCornerRadius = 8.0f,
|
||||||
})
|
})
|
||||||
.UseSkia()
|
.UseSkia()
|
||||||
.AfterSetup(_ =>
|
|
||||||
{
|
|
||||||
AvaloniaLocator.CurrentMutable
|
|
||||||
.Bind<IRenderTimer>().ToConstant(RenderTimer)
|
|
||||||
.Bind<IRenderLoop>().ToConstant(new RenderLoop(RenderTimer, Dispatcher.UIThread));
|
|
||||||
})
|
|
||||||
.LogToTrace();
|
.LogToTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,12 +96,14 @@ namespace Ryujinx.Ava
|
|||||||
// Initialize Discord integration.
|
// Initialize Discord integration.
|
||||||
DiscordIntegrationModule.Initialize();
|
DiscordIntegrationModule.Initialize();
|
||||||
|
|
||||||
|
// Initialize SDL2 driver
|
||||||
|
SDL2Driver.MainThreadDispatcher = action => Dispatcher.UIThread.InvokeAsync(action, DispatcherPriority.Input);
|
||||||
|
|
||||||
ReloadConfig();
|
ReloadConfig();
|
||||||
|
|
||||||
ForceDpiAware.Windows();
|
ForceDpiAware.Windows();
|
||||||
|
|
||||||
WindowScaleFactor = ForceDpiAware.GetWindowScaleFactor();
|
WindowScaleFactor = ForceDpiAware.GetWindowScaleFactor();
|
||||||
ActualScaleFactor = ForceDpiAware.GetActualScaleFactor() / BaseDpi;
|
|
||||||
|
|
||||||
// Logging system information.
|
// Logging system information.
|
||||||
PrintSystemInfo();
|
PrintSystemInfo();
|
||||||
|
@ -33,9 +33,9 @@
|
|||||||
<PackageReference Include="OpenTK.Core" Version="4.7.5" />
|
<PackageReference Include="OpenTK.Core" Version="4.7.5" />
|
||||||
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
|
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
|
||||||
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build10" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
|
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build10" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
|
||||||
<PackageReference Include="Silk.NET.Vulkan" Version="2.10.1" />
|
<PackageReference Include="Silk.NET.Vulkan" Version="2.16.0" />
|
||||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.10.1" />
|
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" />
|
||||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.10.1" />
|
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" />
|
||||||
<PackageReference Include="SPB" Version="0.0.4-build28" />
|
<PackageReference Include="SPB" Version="0.0.4-build28" />
|
||||||
<PackageReference Include="SharpZipLib" Version="1.4.1" />
|
<PackageReference Include="SharpZipLib" Version="1.4.1" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
||||||
|
@ -11,7 +11,8 @@
|
|||||||
Height="340"
|
Height="340"
|
||||||
CanResize="False"
|
CanResize="False"
|
||||||
SizeToContent="Height"
|
SizeToContent="Height"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
<Grid
|
<Grid
|
||||||
Margin="20"
|
Margin="20"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
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:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
||||||
Width="400"
|
Width="400"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
<Grid
|
<Grid
|
||||||
Margin="20"
|
Margin="20"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
|
@ -10,7 +10,8 @@
|
|||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
d:DesignHeight="450"
|
d:DesignHeight="450"
|
||||||
d:DesignWidth="800"
|
d:DesignWidth="800"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||||
<MenuFlyout x:Key="GameContextMenu" Opened="MenuBase_OnMenuOpened">
|
<MenuFlyout x:Key="GameContextMenu" Opened="MenuBase_OnMenuOpened">
|
||||||
@ -113,8 +114,8 @@
|
|||||||
<Style Selector="ListBoxItem">
|
<Style Selector="ListBoxItem">
|
||||||
<Setter Property="Padding" Value="0" />
|
<Setter Property="Padding" Value="0" />
|
||||||
<Setter Property="Margin" Value="5" />
|
<Setter Property="Margin" Value="5" />
|
||||||
<Setter Property="CornerRadius" Value="5" />
|
<Setter Property="CornerRadius" Value="4" />
|
||||||
<Setter Property="Background" Value="{DynamicResource SystemAccentColorDark3}" />
|
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
|
||||||
<Style.Animations>
|
<Style.Animations>
|
||||||
<Animation Duration="0:0:0.7">
|
<Animation Duration="0:0:0.7">
|
||||||
<KeyFrame Cue="0%">
|
<KeyFrame Cue="0%">
|
||||||
@ -132,27 +133,18 @@
|
|||||||
</Animation>
|
</Animation>
|
||||||
</Style.Animations>
|
</Style.Animations>
|
||||||
</Style>
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource AppListHoverBackgroundColor}" />
|
||||||
|
</Style>
|
||||||
</ListBox.Styles>
|
</ListBox.Styles>
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.Styles>
|
|
||||||
<Style Selector="ui|SymbolIcon.small.icon">
|
|
||||||
<Setter Property="FontSize" Value="15" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="ui|SymbolIcon.normal.icon">
|
|
||||||
<Setter Property="FontSize" Value="19" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="ui|SymbolIcon.large.icon">
|
|
||||||
<Setter Property="FontSize" Value="23" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="ui|SymbolIcon.huge.icon">
|
|
||||||
<Setter Property="FontSize" Value="26" />
|
|
||||||
</Style>
|
|
||||||
</Grid.Styles>
|
|
||||||
<Border
|
<Border
|
||||||
Margin="0"
|
Margin="10"
|
||||||
Padding="{Binding $parent[UserControl].DataContext.GridItemPadding}"
|
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
|
Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
|
||||||
@ -160,57 +152,41 @@
|
|||||||
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
|
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
|
||||||
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
|
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
|
||||||
ClipToBounds="True"
|
ClipToBounds="True"
|
||||||
CornerRadius="5">
|
CornerRadius="4">
|
||||||
<Grid Margin="0">
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Image
|
<Image
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Margin="0"
|
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
|
Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
|
||||||
<StackPanel
|
<Panel
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Height="50"
|
Height="50"
|
||||||
Margin="5"
|
Margin="0 10 0 0"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
IsVisible="{Binding $parent[UserControl].DataContext.ShowNames}">
|
IsVisible="{Binding $parent[UserControl].DataContext.ShowNames}">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{Binding TitleName}"
|
Text="{Binding TitleName}"
|
||||||
TextAlignment="Center"
|
TextAlignment="Center"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
</StackPanel>
|
</Panel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
<ui:SymbolIcon
|
<ui:SymbolIcon
|
||||||
Margin="5"
|
Margin="5,5,0,0"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
|
FontSize="16"
|
||||||
Classes.icon="true"
|
Foreground="{DynamicResource SystemAccentColor}"
|
||||||
Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}"
|
|
||||||
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
|
|
||||||
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
|
|
||||||
Foreground="Yellow"
|
|
||||||
IsVisible="{Binding Favorite}"
|
IsVisible="{Binding Favorite}"
|
||||||
Symbol="StarFilled" />
|
Symbol="StarFilled" />
|
||||||
<ui:SymbolIcon
|
|
||||||
Margin="5"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Top"
|
|
||||||
Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
|
|
||||||
Classes.icon="true"
|
|
||||||
Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}"
|
|
||||||
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
|
|
||||||
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
|
|
||||||
Foreground="Black"
|
|
||||||
IsVisible="{Binding Favorite}"
|
|
||||||
Symbol="Star" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListBox.ItemTemplate>
|
</ListBox.ItemTemplate>
|
||||||
|
@ -10,7 +10,8 @@
|
|||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
d:DesignHeight="450"
|
d:DesignHeight="450"
|
||||||
d:DesignWidth="800"
|
d:DesignWidth="800"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||||
<MenuFlyout x:Key="GameContextMenu" Opened="MenuBase_OnMenuOpened">
|
<MenuFlyout x:Key="GameContextMenu" Opened="MenuBase_OnMenuOpened">
|
||||||
@ -115,7 +116,7 @@
|
|||||||
<Setter Property="Padding" Value="0" />
|
<Setter Property="Padding" Value="0" />
|
||||||
<Setter Property="Margin" Value="0" />
|
<Setter Property="Margin" Value="0" />
|
||||||
<Setter Property="CornerRadius" Value="5" />
|
<Setter Property="CornerRadius" Value="5" />
|
||||||
<Setter Property="BorderBrush" Value="{DynamicResource SystemAccentColorDark3}" />
|
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
|
||||||
<Setter Property="BorderThickness" Value="2"/>
|
<Setter Property="BorderThickness" Value="2"/>
|
||||||
<Style.Animations>
|
<Style.Animations>
|
||||||
<Animation Duration="0:0:0.7">
|
<Animation Duration="0:0:0.7">
|
||||||
@ -134,6 +135,12 @@
|
|||||||
</Animation>
|
</Animation>
|
||||||
</Style.Animations>
|
</Style.Animations>
|
||||||
</Style>
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource AppListHoverBackgroundColor}" />
|
||||||
|
</Style>
|
||||||
</ListBox.Styles>
|
</ListBox.Styles>
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
@ -152,9 +159,6 @@
|
|||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<Image
|
<Image
|
||||||
Grid.RowSpan="3"
|
Grid.RowSpan="3"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
@ -214,20 +218,10 @@
|
|||||||
Margin="-5,-5,0,0"
|
Margin="-5,-5,0,0"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
FontSize="20"
|
FontSize="16"
|
||||||
Foreground="Yellow"
|
Foreground="{DynamicResource SystemAccentColor}"
|
||||||
IsVisible="{Binding Favorite}"
|
IsVisible="{Binding Favorite}"
|
||||||
Symbol="StarFilled" />
|
Symbol="StarFilled" />
|
||||||
<ui:SymbolIcon
|
|
||||||
Grid.Row="0"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="-5,-5,0,0"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Top"
|
|
||||||
FontSize="20"
|
|
||||||
Foreground="Black"
|
|
||||||
IsVisible="{Binding Favorite}"
|
|
||||||
Symbol="Star" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
<Grid
|
<Grid
|
||||||
Margin="5,10,5,5"
|
Margin="5,10,5,5"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
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:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Ryujinx.Ava.Ui.Controls.NavigationDialogHost">
|
x:Class="Ryujinx.Ava.Ui.Controls.NavigationDialogHost"
|
||||||
|
Focusable="True">
|
||||||
<ui:Frame HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
|
<ui:Frame HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
|
||||||
x:Name="ContentFrame" />
|
x:Name="ContentFrame" />
|
||||||
</UserControl>
|
</UserControl>
|
@ -1,6 +1,7 @@
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
|
using LibHac;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.Ui.ViewModels;
|
using Ryujinx.Ava.Ui.ViewModels;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
@ -14,6 +15,8 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
{
|
{
|
||||||
public AccountManager AccountManager { get; }
|
public AccountManager AccountManager { get; }
|
||||||
public ContentManager ContentManager { get; }
|
public ContentManager ContentManager { get; }
|
||||||
|
public VirtualFileSystem VirtualFileSystem { get; }
|
||||||
|
public HorizonClient HorizonClient { get; }
|
||||||
public UserProfileViewModel ViewModel { get; set; }
|
public UserProfileViewModel ViewModel { get; set; }
|
||||||
|
|
||||||
public NavigationDialogHost()
|
public NavigationDialogHost()
|
||||||
@ -22,10 +25,12 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
}
|
}
|
||||||
|
|
||||||
public NavigationDialogHost(AccountManager accountManager, ContentManager contentManager,
|
public NavigationDialogHost(AccountManager accountManager, ContentManager contentManager,
|
||||||
VirtualFileSystem virtualFileSystem)
|
VirtualFileSystem virtualFileSystem, HorizonClient horizonClient)
|
||||||
{
|
{
|
||||||
AccountManager = accountManager;
|
AccountManager = accountManager;
|
||||||
ContentManager = contentManager;
|
ContentManager = contentManager;
|
||||||
|
VirtualFileSystem = virtualFileSystem;
|
||||||
|
HorizonClient = horizonClient;
|
||||||
ViewModel = new UserProfileViewModel(this);
|
ViewModel = new UserProfileViewModel(this);
|
||||||
|
|
||||||
|
|
||||||
@ -54,9 +59,10 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
ContentFrame.Navigate(sourcePageType, parameter);
|
ContentFrame.Navigate(sourcePageType, parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task Show(AccountManager ownerAccountManager, ContentManager ownerContentManager, VirtualFileSystem ownerVirtualFileSystem)
|
public static async Task Show(AccountManager ownerAccountManager, ContentManager ownerContentManager,
|
||||||
|
VirtualFileSystem ownerVirtualFileSystem, HorizonClient ownerHorizonClient)
|
||||||
{
|
{
|
||||||
var content = new NavigationDialogHost(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem);
|
var content = new NavigationDialogHost(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem, ownerHorizonClient);
|
||||||
ContentDialog contentDialog = new ContentDialog
|
ContentDialog contentDialog = new ContentDialog
|
||||||
{
|
{
|
||||||
Title = LocaleManager.Instance["UserProfileWindowTitle"],
|
Title = LocaleManager.Instance["UserProfileWindowTitle"],
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
xmlns:Locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
xmlns:Locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
x:Class="Ryujinx.Ava.Ui.Controls.ProfileImageSelectionDialog">
|
x:Class="Ryujinx.Ava.Ui.Controls.ProfileImageSelectionDialog"
|
||||||
|
Focusable="True">
|
||||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="5,10,5, 5">
|
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="5,10,5, 5">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
@ -1,100 +0,0 @@
|
|||||||
using Avalonia.Rendering;
|
|
||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Timers;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Controls
|
|
||||||
{
|
|
||||||
internal class RenderTimer : IRenderTimer, IDisposable
|
|
||||||
{
|
|
||||||
public event Action<TimeSpan> Tick
|
|
||||||
{
|
|
||||||
add
|
|
||||||
{
|
|
||||||
_tick += value;
|
|
||||||
|
|
||||||
if (_subscriberCount++ == 0)
|
|
||||||
{
|
|
||||||
Start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
remove
|
|
||||||
{
|
|
||||||
if (--_subscriberCount == 0)
|
|
||||||
{
|
|
||||||
Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
_tick -= value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Thread _tickThread;
|
|
||||||
private readonly System.Timers.Timer _timer;
|
|
||||||
|
|
||||||
private Action<TimeSpan> _tick;
|
|
||||||
private int _subscriberCount;
|
|
||||||
|
|
||||||
private bool _isRunning;
|
|
||||||
|
|
||||||
private AutoResetEvent _resetEvent;
|
|
||||||
|
|
||||||
public RenderTimer()
|
|
||||||
{
|
|
||||||
_timer = new System.Timers.Timer(15);
|
|
||||||
_resetEvent = new AutoResetEvent(true);
|
|
||||||
_timer.Elapsed += Timer_Elapsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
|
|
||||||
{
|
|
||||||
TickNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Start()
|
|
||||||
{
|
|
||||||
_timer.Start();
|
|
||||||
if (_tickThread == null)
|
|
||||||
{
|
|
||||||
_tickThread = new Thread(RunTick);
|
|
||||||
_tickThread.Name = "RenderTimerTickThread";
|
|
||||||
_tickThread.IsBackground = true;
|
|
||||||
_isRunning = true;
|
|
||||||
_tickThread.Start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RunTick()
|
|
||||||
{
|
|
||||||
while (_isRunning)
|
|
||||||
{
|
|
||||||
_resetEvent.WaitOne();
|
|
||||||
_tick?.Invoke(TimeSpan.FromMilliseconds(Environment.TickCount));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void TickNow()
|
|
||||||
{
|
|
||||||
lock (_timer)
|
|
||||||
{
|
|
||||||
_resetEvent.Set();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Stop()
|
|
||||||
{
|
|
||||||
_timer.Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_timer.Elapsed -= Timer_Elapsed;
|
|
||||||
_timer.Stop();
|
|
||||||
_isRunning = false;
|
|
||||||
_resetEvent.Set();
|
|
||||||
_tickThread.Join();
|
|
||||||
_resetEvent.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,12 +3,6 @@
|
|||||||
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"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Ryujinx.Ava.Ui.Controls.RendererHost">
|
x:Class="Ryujinx.Ava.Ui.Controls.RendererHost"
|
||||||
<ContentControl
|
Focusable="True">
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
HorizontalContentAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
VerticalContentAlignment="Stretch"
|
|
||||||
Name="View"
|
|
||||||
/>
|
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
@ -41,7 +41,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
{
|
{
|
||||||
_currentWindow.WindowCreated += CurrentWindow_WindowCreated;
|
_currentWindow.WindowCreated += CurrentWindow_WindowCreated;
|
||||||
_currentWindow.SizeChanged += CurrentWindow_SizeChanged;
|
_currentWindow.SizeChanged += CurrentWindow_SizeChanged;
|
||||||
View.Content = _currentWindow;
|
Content = _currentWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CreateVulkan()
|
public void CreateVulkan()
|
||||||
|
103
Ryujinx.Ava/Ui/Controls/SaveManager.axaml
Normal file
103
Ryujinx.Ava/Ui/Controls/SaveManager.axaml
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<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:controls="clr-namespace:Ryujinx.Ava.Ui.Controls"
|
||||||
|
xmlns:models="clr-namespace:Ryujinx.Ava.Ui.Models"
|
||||||
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
Height="400"
|
||||||
|
Width="550"
|
||||||
|
x:Class="Ryujinx.Ava.Ui.Controls.SaveManager"
|
||||||
|
Focusable="True">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||||
|
</UserControl.Resources>
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid Grid.Row="0" HorizontalAlignment="Stretch">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<StackPanel Spacing="10" Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Center">
|
||||||
|
<Label Content="{locale:Locale CommonSort}" VerticalAlignment="Center" />
|
||||||
|
<ComboBox SelectedIndex="{Binding SortIndex}" Width="100">
|
||||||
|
<ComboBoxItem>
|
||||||
|
<Label VerticalAlignment="Center" HorizontalContentAlignment="Left"
|
||||||
|
Content="{locale:Locale Name}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<Label VerticalAlignment="Center" HorizontalContentAlignment="Left"
|
||||||
|
Content="{locale:Locale Size}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
</ComboBox>
|
||||||
|
<ComboBox SelectedIndex="{Binding OrderIndex}" Width="150">
|
||||||
|
<ComboBoxItem>
|
||||||
|
<Label VerticalAlignment="Center" HorizontalContentAlignment="Left"
|
||||||
|
Content="{locale:Locale OrderAscending}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<Label VerticalAlignment="Center" HorizontalContentAlignment="Left"
|
||||||
|
Content="{locale:Locale Descending}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
|
<Grid Grid.Column="1" HorizontalAlignment="Stretch" Margin="10,0, 0, 0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
<ColumnDefinition/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Label Content="{locale:Locale Search}" VerticalAlignment="Center"/>
|
||||||
|
<TextBox Margin="5,0,0,0" Grid.Column="1" HorizontalAlignment="Stretch" Text="{Binding Search}"/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Border Grid.Row="1" Margin="0,5" BorderThickness="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||||
|
<ListBox Name="SaveList" Items="{Binding View}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="models:SaveModel">
|
||||||
|
<Grid HorizontalAlignment="Stretch" Margin="0,5">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<StackPanel Grid.Column="0" Orientation="Horizontal">
|
||||||
|
<Border Height="42" Margin="2" Width="42" Padding="10"
|
||||||
|
IsVisible="{Binding !InGameList}">
|
||||||
|
<ui:SymbolIcon Symbol="Help" FontSize="30" HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
</Border>
|
||||||
|
<Image IsVisible="{Binding InGameList}"
|
||||||
|
Margin="2"
|
||||||
|
Width="42"
|
||||||
|
Height="42"
|
||||||
|
Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
|
||||||
|
<TextBlock MaxLines="3" Width="320" Margin="5" TextWrapping="Wrap"
|
||||||
|
Text="{Binding Title}" VerticalAlignment="Center" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Grid.Column="1" Spacing="10" HorizontalAlignment="Right"
|
||||||
|
Orientation="Horizontal">
|
||||||
|
<Label Content="{Binding SizeString}" IsVisible="{Binding SizeAvailable}"
|
||||||
|
VerticalAlignment="Center" HorizontalAlignment="Right" />
|
||||||
|
<Button VerticalAlignment="Center" HorizontalAlignment="Right" Padding="10"
|
||||||
|
MinWidth="0" MinHeight="0" Name="OpenLocation" Command="{Binding OpenLocation}">
|
||||||
|
<ui:SymbolIcon Symbol="OpenFolder" HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
</Button>
|
||||||
|
<Button VerticalAlignment="Center" HorizontalAlignment="Right" Padding="10"
|
||||||
|
MinWidth="0" MinHeight="0" Name="Delete" Command="{Binding Delete}">
|
||||||
|
<ui:SymbolIcon Symbol="Delete" HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
</Button>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
160
Ryujinx.Ava/Ui/Controls/SaveManager.axaml.cs
Normal file
160
Ryujinx.Ava/Ui/Controls/SaveManager.axaml.cs
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
using DynamicData;
|
||||||
|
using DynamicData.Binding;
|
||||||
|
using LibHac;
|
||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.Fs;
|
||||||
|
using LibHac.Fs.Shim;
|
||||||
|
using Ryujinx.Ava.Common;
|
||||||
|
using Ryujinx.Ava.Common.Locale;
|
||||||
|
using Ryujinx.Ava.Ui.Models;
|
||||||
|
using Ryujinx.HLE.FileSystem;
|
||||||
|
using Ryujinx.Ui.App.Common;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UserProfile = Ryujinx.Ava.Ui.Models.UserProfile;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.Ui.Controls
|
||||||
|
{
|
||||||
|
public partial class SaveManager : UserControl
|
||||||
|
{
|
||||||
|
private readonly UserProfile _userProfile;
|
||||||
|
private readonly HorizonClient _horizonClient;
|
||||||
|
private readonly VirtualFileSystem _virtualFileSystem;
|
||||||
|
private int _sortIndex;
|
||||||
|
private int _orderIndex;
|
||||||
|
private ObservableCollection<SaveModel> _view = new ObservableCollection<SaveModel>();
|
||||||
|
private string _search;
|
||||||
|
|
||||||
|
public ObservableCollection<SaveModel> Saves { get; set; } = new ObservableCollection<SaveModel>();
|
||||||
|
|
||||||
|
public ObservableCollection<SaveModel> View
|
||||||
|
{
|
||||||
|
get => _view;
|
||||||
|
set => _view = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int SortIndex
|
||||||
|
{
|
||||||
|
get => _sortIndex;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_sortIndex = value;
|
||||||
|
Sort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int OrderIndex
|
||||||
|
{
|
||||||
|
get => _orderIndex;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_orderIndex = value;
|
||||||
|
Sort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Search
|
||||||
|
{
|
||||||
|
get => _search;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_search = value;
|
||||||
|
Sort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SaveManager()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SaveManager(UserProfile userProfile, HorizonClient horizonClient, VirtualFileSystem virtualFileSystem)
|
||||||
|
{
|
||||||
|
_userProfile = userProfile;
|
||||||
|
_horizonClient = horizonClient;
|
||||||
|
_virtualFileSystem = virtualFileSystem;
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
DataContext = this;
|
||||||
|
|
||||||
|
Task.Run(LoadSaves);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadSaves()
|
||||||
|
{
|
||||||
|
Saves.Clear();
|
||||||
|
var saveDataFilter = SaveDataFilter.Make(programId: default, saveType: SaveDataType.Account,
|
||||||
|
new UserId((ulong)_userProfile.UserId.High, (ulong)_userProfile.UserId.Low), saveDataId: default, index: default);
|
||||||
|
|
||||||
|
using var saveDataIterator = new UniqueRef<SaveDataIterator>();
|
||||||
|
|
||||||
|
_horizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref(), SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure();
|
||||||
|
|
||||||
|
Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10];
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
saveDataIterator.Get.ReadSaveDataInfo(out long readCount, saveDataInfo).ThrowIfFailure();
|
||||||
|
|
||||||
|
if (readCount == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < readCount; i++)
|
||||||
|
{
|
||||||
|
var save = saveDataInfo[i];
|
||||||
|
if (save.ProgramId.Value != 0)
|
||||||
|
{
|
||||||
|
var saveModel = new SaveModel(save, _horizonClient, _virtualFileSystem);
|
||||||
|
Saves.Add(saveModel);
|
||||||
|
saveModel.DeleteAction = () => { Saves.Remove(saveModel); };
|
||||||
|
}
|
||||||
|
|
||||||
|
Sort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Sort()
|
||||||
|
{
|
||||||
|
Saves.AsObservableChangeSet()
|
||||||
|
.Filter(Filter)
|
||||||
|
.Sort(GetComparer())
|
||||||
|
.Bind(out var view).AsObservableList();
|
||||||
|
|
||||||
|
_view.Clear();
|
||||||
|
_view.AddRange(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IComparer<SaveModel> GetComparer()
|
||||||
|
{
|
||||||
|
switch (SortIndex)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return OrderIndex == 0
|
||||||
|
? SortExpressionComparer<SaveModel>.Ascending(save => save.Title)
|
||||||
|
: SortExpressionComparer<SaveModel>.Descending(save => save.Title);
|
||||||
|
case 1:
|
||||||
|
return OrderIndex == 0
|
||||||
|
? SortExpressionComparer<SaveModel>.Ascending(save => save.Size)
|
||||||
|
: SortExpressionComparer<SaveModel>.Descending(save => save.Size);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Filter(object arg)
|
||||||
|
{
|
||||||
|
if (arg is SaveModel save)
|
||||||
|
{
|
||||||
|
return string.IsNullOrWhiteSpace(_search) || save.Title.ToLower().Contains(_search.ToLower());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,8 @@
|
|||||||
Title="Ryujinx - Waiting"
|
Title="Ryujinx - Waiting"
|
||||||
SizeToContent="WidthAndHeight"
|
SizeToContent="WidthAndHeight"
|
||||||
WindowStartupLocation="CenterOwner"
|
WindowStartupLocation="CenterOwner"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
<Grid
|
<Grid
|
||||||
Margin="20"
|
Margin="20"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
|
@ -10,8 +10,10 @@
|
|||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
|
||||||
Margin="0"
|
Margin="0"
|
||||||
|
MinWidth="500"
|
||||||
Padding="0"
|
Padding="0"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
@ -63,7 +65,7 @@
|
|||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
MaxLength="{Binding MaxProfileNameLength}"
|
MaxLength="{Binding MaxProfileNameLength}"
|
||||||
Text="{Binding Name}" />
|
Text="{Binding Name}" />
|
||||||
<TextBlock Text="{Locale:Locale UserProfilesUserId}" />
|
<TextBlock Name="IdText" Text="{Locale:Locale UserProfilesUserId}" />
|
||||||
<TextBlock Name="IdLabel" Text="{Binding UserId}" />
|
<TextBlock Name="IdLabel" Text="{Binding UserId}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel
|
<StackPanel
|
||||||
|
@ -36,15 +36,8 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
case NavigationMode.New:
|
case NavigationMode.New:
|
||||||
var args = ((NavigationDialogHost parent, UserProfile profile, bool isNewUser))arg.Parameter;
|
var args = ((NavigationDialogHost parent, UserProfile profile, bool isNewUser))arg.Parameter;
|
||||||
_isNewUser = args.isNewUser;
|
_isNewUser = args.isNewUser;
|
||||||
if (!_isNewUser)
|
|
||||||
{
|
|
||||||
_profile = args.profile;
|
_profile = args.profile;
|
||||||
TempProfile = new TempProfile(_profile);
|
TempProfile = new TempProfile(_profile);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TempProfile = new TempProfile();
|
|
||||||
}
|
|
||||||
|
|
||||||
_parent = args.parent;
|
_parent = args.parent;
|
||||||
break;
|
break;
|
||||||
@ -53,7 +46,8 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
DataContext = TempProfile;
|
DataContext = TempProfile;
|
||||||
|
|
||||||
AddPictureButton.IsVisible = _isNewUser;
|
AddPictureButton.IsVisible = _isNewUser;
|
||||||
IdLabel.IsVisible = !_isNewUser;
|
IdLabel.IsVisible = _profile != null;
|
||||||
|
IdText.IsVisible = _profile != null;
|
||||||
ChangePictureButton.IsVisible = !_isNewUser;
|
ChangePictureButton.IsVisible = !_isNewUser;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,7 +81,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_profile != null)
|
if (_profile != null && !_isNewUser)
|
||||||
{
|
{
|
||||||
_profile.Name = TempProfile.Name;
|
_profile.Name = TempProfile.Name;
|
||||||
_profile.Image = TempProfile.Image;
|
_profile.Image = TempProfile.Image;
|
||||||
@ -97,7 +91,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
}
|
}
|
||||||
else if (_isNewUser)
|
else if (_isNewUser)
|
||||||
{
|
{
|
||||||
_parent.AccountManager.AddUser(TempProfile.Name, TempProfile.Image);
|
_parent.AccountManager.AddUser(TempProfile.Name, TempProfile.Image, TempProfile.UserId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
71
Ryujinx.Ava/Ui/Controls/UserRecoverer.axaml
Normal file
71
Ryujinx.Ava/Ui/Controls/UserRecoverer.axaml
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<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"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignWidth="800"
|
||||||
|
d:DesignHeight="450"
|
||||||
|
MinWidth="500"
|
||||||
|
MinHeight="400"
|
||||||
|
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"
|
||||||
|
x:Class="Ryujinx.Ava.Ui.Controls.UserRecoverer"
|
||||||
|
Focusable="True">
|
||||||
|
<Design.DataContext>
|
||||||
|
<viewModels:UserProfileViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
<Grid HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Button Grid.Row="0"
|
||||||
|
Margin="5"
|
||||||
|
Height="30"
|
||||||
|
Width="50"
|
||||||
|
MinWidth="50"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Command="{Binding GoBack}">
|
||||||
|
<ui:SymbolIcon Symbol="Back"/>
|
||||||
|
</Button>
|
||||||
|
<TextBlock Grid.Row="1"
|
||||||
|
Text="{Locale:Locale UserProfilesRecoverHeading}"/>
|
||||||
|
<ListBox
|
||||||
|
Margin="5"
|
||||||
|
Grid.Row="2"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
Items="{Binding LostProfiles}">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Border
|
||||||
|
Margin="2"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
ClipToBounds="True"
|
||||||
|
CornerRadius="5">
|
||||||
|
<Grid Margin="0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition/>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBlock
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Text="{Binding UserId}"
|
||||||
|
TextAlignment="Left"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
<Button Grid.Column="1"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Command="{Binding Recover}"
|
||||||
|
CommandParameter="{Binding}"
|
||||||
|
Content="{Locale:Locale Recover}"/>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
44
Ryujinx.Ava/Ui/Controls/UserRecoverer.axaml.cs
Normal file
44
Ryujinx.Ava/Ui/Controls/UserRecoverer.axaml.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using FluentAvalonia.UI.Controls;
|
||||||
|
using FluentAvalonia.UI.Navigation;
|
||||||
|
using Ryujinx.Ava.Ui.Models;
|
||||||
|
using Ryujinx.Ava.Ui.ViewModels;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.Ui.Controls
|
||||||
|
{
|
||||||
|
public partial class UserRecoverer : UserControl
|
||||||
|
{
|
||||||
|
private UserProfileViewModel _viewModel;
|
||||||
|
private NavigationDialogHost _parent;
|
||||||
|
|
||||||
|
public UserRecoverer()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
AddHandler(Frame.NavigatedToEvent, (s, e) =>
|
||||||
|
{
|
||||||
|
NavigatedTo(e);
|
||||||
|
}, RoutingStrategies.Direct);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NavigatedTo(NavigationEventArgs arg)
|
||||||
|
{
|
||||||
|
if (Program.PreviewerDetached)
|
||||||
|
{
|
||||||
|
switch (arg.NavigationMode)
|
||||||
|
{
|
||||||
|
case NavigationMode.New:
|
||||||
|
var args = ((NavigationDialogHost parent, UserProfileViewModel viewModel))arg.Parameter;
|
||||||
|
|
||||||
|
_viewModel = args.viewModel;
|
||||||
|
_parent = args.parent;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataContext = _viewModel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,8 +10,10 @@
|
|||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
|
||||||
d:DesignHeight="450"
|
d:DesignHeight="450"
|
||||||
|
MinWidth="500"
|
||||||
d:DesignWidth="800"
|
d:DesignWidth="800"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
@ -25,6 +27,7 @@
|
|||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<ListBox
|
<ListBox
|
||||||
Margin="5"
|
Margin="5"
|
||||||
|
MaxHeight="300"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
DoubleTapped="ProfilesList_DoubleTapped"
|
DoubleTapped="ProfilesList_DoubleTapped"
|
||||||
@ -88,21 +91,56 @@
|
|||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListBox.ItemTemplate>
|
</ListBox.ItemTemplate>
|
||||||
</ListBox>
|
</ListBox>
|
||||||
<StackPanel
|
<Grid
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Margin="10,0"
|
HorizontalAlignment="Center">
|
||||||
HorizontalAlignment="Center"
|
<Grid.RowDefinitions>
|
||||||
Orientation="Horizontal"
|
<RowDefinition Height="Auto"/>
|
||||||
Spacing="10">
|
<RowDefinition Height="Auto"/>
|
||||||
<Button Command="{Binding AddUser}" Content="{Locale:Locale UserProfilesAddNewProfile}" />
|
<RowDefinition Height="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
<Button
|
<Button
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="2"
|
||||||
|
Command="{Binding AddUser}"
|
||||||
|
Content="{Locale:Locale UserProfilesAddNewProfile}" />
|
||||||
|
<Button
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Grid.Row="0"
|
||||||
|
Margin="2"
|
||||||
|
Grid.Column="1"
|
||||||
Command="{Binding EditUser}"
|
Command="{Binding EditUser}"
|
||||||
Content="{Locale:Locale UserProfilesEditProfile}"
|
Content="{Locale:Locale UserProfilesEditProfile}"
|
||||||
IsEnabled="{Binding IsSelectedProfiledEditable}" />
|
IsEnabled="{Binding IsSelectedProfiledEditable}" />
|
||||||
<Button
|
<Button
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="2"
|
||||||
|
Content="{Locale:Locale UserProfilesManageSaves}"
|
||||||
|
Command="{Binding ManageSaves}" />
|
||||||
|
<Button
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="2"
|
||||||
Command="{Binding DeleteUser}"
|
Command="{Binding DeleteUser}"
|
||||||
Content="{Locale:Locale UserProfilesDeleteSelectedProfile}"
|
Content="{Locale:Locale UserProfilesDeleteSelectedProfile}"
|
||||||
IsEnabled="{Binding IsSelectedProfileDeletable}" />
|
IsEnabled="{Binding IsSelectedProfileDeletable}" />
|
||||||
</StackPanel>
|
<Button
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.ColumnSpan="2"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="2"
|
||||||
|
Command="{Binding RecoverLostAccounts}"
|
||||||
|
Content="{Locale:Locale UserProfilesRecoverLostAccounts}" />
|
||||||
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
122
Ryujinx.Ava/Ui/Models/SaveModel.cs
Normal file
122
Ryujinx.Ava/Ui/Models/SaveModel.cs
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
using LibHac;
|
||||||
|
using LibHac.Fs;
|
||||||
|
using LibHac.Fs.Shim;
|
||||||
|
using LibHac.Ncm;
|
||||||
|
using Ryujinx.Ava.Common;
|
||||||
|
using Ryujinx.Ava.Common.Locale;
|
||||||
|
using Ryujinx.Ava.Ui.Controls;
|
||||||
|
using Ryujinx.Ava.Ui.ViewModels;
|
||||||
|
using Ryujinx.Ava.Ui.Windows;
|
||||||
|
using Ryujinx.HLE.FileSystem;
|
||||||
|
using Ryujinx.Ui.App.Common;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.Ui.Models
|
||||||
|
{
|
||||||
|
public class SaveModel : BaseModel
|
||||||
|
{
|
||||||
|
private readonly HorizonClient _horizonClient;
|
||||||
|
private long _size;
|
||||||
|
|
||||||
|
public Action DeleteAction { get; set; }
|
||||||
|
public ulong SaveId { get; }
|
||||||
|
public ProgramId TitleId { get; }
|
||||||
|
public string TitleIdString => $"{TitleId.Value:X16}";
|
||||||
|
public UserId UserId { get; }
|
||||||
|
public bool InGameList { get; }
|
||||||
|
public string Title { get; }
|
||||||
|
public byte[] Icon { get; }
|
||||||
|
|
||||||
|
public long Size
|
||||||
|
{
|
||||||
|
get => _size; set
|
||||||
|
{
|
||||||
|
_size = value;
|
||||||
|
SizeAvailable = true;
|
||||||
|
OnPropertyChanged();
|
||||||
|
OnPropertyChanged(nameof(SizeString));
|
||||||
|
OnPropertyChanged(nameof(SizeAvailable));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SizeAvailable { get; set; }
|
||||||
|
|
||||||
|
public string SizeString => $"{((float)_size * 0.000000954):0.###}MB";
|
||||||
|
|
||||||
|
public SaveModel(SaveDataInfo info, HorizonClient horizonClient, VirtualFileSystem virtualFileSystem)
|
||||||
|
{
|
||||||
|
_horizonClient = horizonClient;
|
||||||
|
SaveId = info.SaveDataId;
|
||||||
|
TitleId = info.ProgramId;
|
||||||
|
UserId = info.UserId;
|
||||||
|
|
||||||
|
var appData = MainWindow.MainWindowViewModel.Applications.FirstOrDefault(x => x.TitleId.ToUpper() == TitleIdString);
|
||||||
|
|
||||||
|
InGameList = appData != null;
|
||||||
|
|
||||||
|
if (InGameList)
|
||||||
|
{
|
||||||
|
Icon = appData.Icon;
|
||||||
|
Title = appData.TitleName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var appMetadata = MainWindow.MainWindowViewModel.ApplicationLibrary.LoadAndSaveMetaData(TitleIdString);
|
||||||
|
Title = appMetadata.Title ?? TitleIdString;
|
||||||
|
}
|
||||||
|
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
var saveRoot = System.IO.Path.Combine(virtualFileSystem.GetNandPath(), $"user/save/{info.SaveDataId:x16}");
|
||||||
|
|
||||||
|
long total_size = GetDirectorySize(saveRoot);
|
||||||
|
long GetDirectorySize(string path)
|
||||||
|
{
|
||||||
|
long size = 0;
|
||||||
|
if (Directory.Exists(path))
|
||||||
|
{
|
||||||
|
var directories = Directory.GetDirectories(path);
|
||||||
|
foreach (var directory in directories)
|
||||||
|
{
|
||||||
|
size += GetDirectorySize(directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
var files = Directory.GetFiles(path);
|
||||||
|
foreach (var file in files)
|
||||||
|
{
|
||||||
|
size += new FileInfo(file).Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
Size = total_size;
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OpenLocation()
|
||||||
|
{
|
||||||
|
ApplicationHelper.OpenSaveDir(SaveId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void Delete()
|
||||||
|
{
|
||||||
|
var result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DeleteUserSave"],
|
||||||
|
LocaleManager.Instance["IrreversibleActionNote"],
|
||||||
|
LocaleManager.Instance["InputDialogYes"],
|
||||||
|
LocaleManager.Instance["InputDialogNo"], "");
|
||||||
|
|
||||||
|
if (result == UserResult.Yes)
|
||||||
|
{
|
||||||
|
_horizonClient.Fs.DeleteSaveData(SaveDataSpaceId.User, SaveId);
|
||||||
|
|
||||||
|
DeleteAction?.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -45,10 +45,13 @@ namespace Ryujinx.Ava.Ui.Models
|
|||||||
{
|
{
|
||||||
_profile = profile;
|
_profile = profile;
|
||||||
|
|
||||||
|
if (_profile != null)
|
||||||
|
{
|
||||||
Image = profile.Image;
|
Image = profile.Image;
|
||||||
Name = profile.Name;
|
Name = profile.Name;
|
||||||
UserId = profile.UserId;
|
UserId = profile.UserId;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public TempProfile(){}
|
public TempProfile(){}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using Ryujinx.Ava.Ui.Controls;
|
||||||
using Ryujinx.Ava.Ui.ViewModels;
|
using Ryujinx.Ava.Ui.ViewModels;
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||||
using Profile = Ryujinx.HLE.HOS.Services.Account.Acc.UserProfile;
|
using Profile = Ryujinx.HLE.HOS.Services.Account.Acc.UserProfile;
|
||||||
@ -7,6 +8,7 @@ namespace Ryujinx.Ava.Ui.Models
|
|||||||
public class UserProfile : BaseModel
|
public class UserProfile : BaseModel
|
||||||
{
|
{
|
||||||
private readonly Profile _profile;
|
private readonly Profile _profile;
|
||||||
|
private readonly NavigationDialogHost _owner;
|
||||||
private byte[] _image;
|
private byte[] _image;
|
||||||
private string _name;
|
private string _name;
|
||||||
private UserId _userId;
|
private UserId _userId;
|
||||||
@ -41,9 +43,10 @@ namespace Ryujinx.Ava.Ui.Models
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserProfile(Profile profile)
|
public UserProfile(Profile profile, NavigationDialogHost owner)
|
||||||
{
|
{
|
||||||
_profile = profile;
|
_profile = profile;
|
||||||
|
_owner = owner;
|
||||||
|
|
||||||
Image = profile.Image;
|
Image = profile.Image;
|
||||||
Name = profile.Name;
|
Name = profile.Name;
|
||||||
@ -57,5 +60,10 @@ namespace Ryujinx.Ava.Ui.Models
|
|||||||
OnPropertyChanged(nameof(IsOpened));
|
OnPropertyChanged(nameof(IsOpened));
|
||||||
OnPropertyChanged(nameof(Name));
|
OnPropertyChanged(nameof(Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Recover(UserProfile userProfile)
|
||||||
|
{
|
||||||
|
_owner.Navigate(typeof(UserEditor), (_owner, userProfile, true));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -76,6 +76,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
private bool _showAll;
|
private bool _showAll;
|
||||||
private string _lastScannedAmiiboId;
|
private string _lastScannedAmiiboId;
|
||||||
private ReadOnlyObservableCollection<ApplicationData> _appsObservableList;
|
private ReadOnlyObservableCollection<ApplicationData> _appsObservableList;
|
||||||
|
public ApplicationLibrary ApplicationLibrary => _owner.ApplicationLibrary;
|
||||||
|
|
||||||
public string TitleName { get; internal set; }
|
public string TitleName { get; internal set; }
|
||||||
|
|
||||||
@ -103,8 +104,8 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
_owner.ApplicationLibrary.ApplicationCountUpdated += ApplicationLibrary_ApplicationCountUpdated;
|
ApplicationLibrary.ApplicationCountUpdated += ApplicationLibrary_ApplicationCountUpdated;
|
||||||
_owner.ApplicationLibrary.ApplicationAdded += ApplicationLibrary_ApplicationAdded;
|
ApplicationLibrary.ApplicationAdded += ApplicationLibrary_ApplicationAdded;
|
||||||
|
|
||||||
Ptc.PtcStateChanged -= ProgressHandler;
|
Ptc.PtcStateChanged -= ProgressHandler;
|
||||||
Ptc.PtcStateChanged += ProgressHandler;
|
Ptc.PtcStateChanged += ProgressHandler;
|
||||||
@ -435,8 +436,6 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Thickness GridItemPadding => ShowNames ? new Thickness() : new Thickness(5);
|
|
||||||
|
|
||||||
public bool ShowMenuAndStatusBar
|
public bool ShowMenuAndStatusBar
|
||||||
{
|
{
|
||||||
get => _showMenuAndStatusBar;
|
get => _showMenuAndStatusBar;
|
||||||
@ -598,7 +597,6 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
ConfigurationState.Instance.Ui.ShowNames.Value = value;
|
ConfigurationState.Instance.Ui.ShowNames.Value = value;
|
||||||
|
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
OnPropertyChanged(nameof(GridItemPadding));
|
|
||||||
OnPropertyChanged(nameof(GridSizeScale));
|
OnPropertyChanged(nameof(GridSizeScale));
|
||||||
|
|
||||||
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
||||||
@ -715,7 +713,6 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
OnPropertyChanged(nameof(IsGridLarge));
|
OnPropertyChanged(nameof(IsGridLarge));
|
||||||
OnPropertyChanged(nameof(IsGridHuge));
|
OnPropertyChanged(nameof(IsGridHuge));
|
||||||
OnPropertyChanged(nameof(ShowNames));
|
OnPropertyChanged(nameof(ShowNames));
|
||||||
OnPropertyChanged(nameof(GridItemPadding));
|
|
||||||
|
|
||||||
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
||||||
}
|
}
|
||||||
@ -779,6 +776,11 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
{
|
{
|
||||||
_owner.LoadProgressBar.IsVisible = false;
|
_owner.LoadProgressBar.IsVisible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (e.NumAppsLoaded == e.NumAppsFound)
|
||||||
|
{
|
||||||
|
_owner.LoadProgressBar.IsVisible = false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -817,7 +819,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
|
|
||||||
Thread thread = new(() =>
|
Thread thread = new(() =>
|
||||||
{
|
{
|
||||||
_owner.ApplicationLibrary.LoadApplications(ConfigurationState.Instance.Ui.GameDirs.Value, ConfigurationState.Instance.System.Language);
|
ApplicationLibrary.LoadApplications(ConfigurationState.Instance.Ui.GameDirs.Value, ConfigurationState.Instance.System.Language);
|
||||||
|
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
})
|
})
|
||||||
@ -1005,7 +1007,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
|
|
||||||
public async void ManageProfiles()
|
public async void ManageProfiles()
|
||||||
{
|
{
|
||||||
await NavigationDialogHost.Show(_owner.AccountManager, _owner.ContentManager, _owner.VirtualFileSystem);
|
await NavigationDialogHost.Show(_owner.AccountManager, _owner.ContentManager, _owner.VirtualFileSystem, _owner.LibHacHorizonManager.RyujinxClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void OpenAboutWindow()
|
public async void OpenAboutWindow()
|
||||||
@ -1098,7 +1100,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
{
|
{
|
||||||
selection.Favorite = !selection.Favorite;
|
selection.Favorite = !selection.Favorite;
|
||||||
|
|
||||||
_owner.ApplicationLibrary.LoadAndSaveMetaData(selection.TitleId, appMetadata =>
|
ApplicationLibrary.LoadAndSaveMetaData(selection.TitleId, appMetadata =>
|
||||||
{
|
{
|
||||||
appMetadata.Favorite = selection.Favorite;
|
appMetadata.Favorite = selection.Favorite;
|
||||||
});
|
});
|
||||||
|
@ -119,6 +119,11 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsMacOS
|
||||||
|
{
|
||||||
|
get => OperatingSystem.IsMacOS();
|
||||||
|
}
|
||||||
|
|
||||||
public bool EnableDiscordIntegration { get; set; }
|
public bool EnableDiscordIntegration { get; set; }
|
||||||
public bool CheckUpdatesOnStart { get; set; }
|
public bool CheckUpdatesOnStart { get; set; }
|
||||||
public bool ShowConfirmExit { get; set; }
|
public bool ShowConfirmExit { get; set; }
|
||||||
@ -474,11 +479,40 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
MainWindow.UpdateGraphicsConfig();
|
MainWindow.UpdateGraphicsConfig();
|
||||||
|
|
||||||
_previousVolumeLevel = Volume;
|
_previousVolumeLevel = Volume;
|
||||||
|
|
||||||
|
if (_owner is SettingsWindow owner)
|
||||||
|
{
|
||||||
|
owner.ControllerSettings?.SaveCurrentProfile();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_owner.Owner is MainWindow window && _directoryChanged)
|
||||||
|
{
|
||||||
|
window.ViewModel.LoadApplications();
|
||||||
|
}
|
||||||
|
|
||||||
|
_directoryChanged = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RevertIfNotSaved()
|
public void RevertIfNotSaved()
|
||||||
{
|
{
|
||||||
Program.ReloadConfig();
|
Program.ReloadConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ApplyButton()
|
||||||
|
{
|
||||||
|
SaveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OkButton()
|
||||||
|
{
|
||||||
|
SaveSettings();
|
||||||
|
_owner.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CancelButton()
|
||||||
|
{
|
||||||
|
RevertIfNotSaved();
|
||||||
|
_owner.Close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,8 +1,14 @@
|
|||||||
|
using Avalonia;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
using FluentAvalonia.UI.Controls;
|
||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.Fs;
|
||||||
|
using LibHac.Fs.Shim;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.Ui.Controls;
|
using Ryujinx.Ava.Ui.Controls;
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using UserProfile = Ryujinx.Ava.Ui.Models.UserProfile;
|
using UserProfile = Ryujinx.Ava.Ui.Models.UserProfile;
|
||||||
@ -19,6 +25,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
public UserProfileViewModel()
|
public UserProfileViewModel()
|
||||||
{
|
{
|
||||||
Profiles = new ObservableCollection<UserProfile>();
|
Profiles = new ObservableCollection<UserProfile>();
|
||||||
|
LostProfiles = new ObservableCollection<UserProfile>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserProfileViewModel(NavigationDialogHost owner) : this()
|
public UserProfileViewModel(NavigationDialogHost owner) : this()
|
||||||
@ -30,6 +37,8 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
|
|
||||||
public ObservableCollection<UserProfile> Profiles { get; set; }
|
public ObservableCollection<UserProfile> Profiles { get; set; }
|
||||||
|
|
||||||
|
public ObservableCollection<UserProfile> LostProfiles { get; set; }
|
||||||
|
|
||||||
public UserProfile SelectedProfile
|
public UserProfile SelectedProfile
|
||||||
{
|
{
|
||||||
get => _selectedProfile;
|
get => _selectedProfile;
|
||||||
@ -65,12 +74,13 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
public void LoadProfiles()
|
public void LoadProfiles()
|
||||||
{
|
{
|
||||||
Profiles.Clear();
|
Profiles.Clear();
|
||||||
|
LostProfiles.Clear();
|
||||||
|
|
||||||
var profiles = _owner.AccountManager.GetAllUsers().OrderByDescending(x => x.AccountState == AccountState.Open);
|
var profiles = _owner.AccountManager.GetAllUsers().OrderByDescending(x => x.AccountState == AccountState.Open);
|
||||||
|
|
||||||
foreach (var profile in profiles)
|
foreach (var profile in profiles)
|
||||||
{
|
{
|
||||||
Profiles.Add(new UserProfile(profile));
|
Profiles.Add(new UserProfile(profile, _owner));
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectedProfile = Profiles.FirstOrDefault(x => x.UserId == _owner.AccountManager.LastOpenedUser.UserId);
|
SelectedProfile = Profiles.FirstOrDefault(x => x.UserId == _owner.AccountManager.LastOpenedUser.UserId);
|
||||||
@ -84,6 +94,42 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
_owner.AccountManager.OpenUser(_selectedProfile.UserId);
|
_owner.AccountManager.OpenUser(_selectedProfile.UserId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var saveDataFilter = SaveDataFilter.Make(programId: default, saveType: SaveDataType.Account,
|
||||||
|
default, saveDataId: default, index: default);
|
||||||
|
|
||||||
|
using var saveDataIterator = new UniqueRef<SaveDataIterator>();
|
||||||
|
|
||||||
|
_owner.HorizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref(), SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure();
|
||||||
|
|
||||||
|
Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10];
|
||||||
|
|
||||||
|
HashSet<HLE.HOS.Services.Account.Acc.UserId> lostAccounts = new HashSet<HLE.HOS.Services.Account.Acc.UserId>();
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
saveDataIterator.Get.ReadSaveDataInfo(out long readCount, saveDataInfo).ThrowIfFailure();
|
||||||
|
|
||||||
|
if (readCount == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < readCount; i++)
|
||||||
|
{
|
||||||
|
var save = saveDataInfo[i];
|
||||||
|
var id = new HLE.HOS.Services.Account.Acc.UserId((long)save.UserId.Id.Low, (long)save.UserId.Id.High);
|
||||||
|
if (Profiles.FirstOrDefault( x=> x.UserId == id) == null)
|
||||||
|
{
|
||||||
|
lostAccounts.Add(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(var account in lostAccounts)
|
||||||
|
{
|
||||||
|
LostProfiles.Add(new UserProfile(new HLE.HOS.Services.Account.Acc.UserProfile(account, "", null), _owner));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddUser()
|
public void AddUser()
|
||||||
@ -93,6 +139,25 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
_owner.Navigate(typeof(UserEditor), (this._owner, userProfile, true));
|
_owner.Navigate(typeof(UserEditor), (this._owner, userProfile, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async void ManageSaves()
|
||||||
|
{
|
||||||
|
UserProfile userProfile = _highlightedProfile ?? SelectedProfile;
|
||||||
|
|
||||||
|
SaveManager manager = new SaveManager(userProfile, _owner.HorizonClient, _owner.VirtualFileSystem);
|
||||||
|
|
||||||
|
ContentDialog contentDialog = new ContentDialog
|
||||||
|
{
|
||||||
|
Title = string.Format(LocaleManager.Instance["SaveManagerHeading"], userProfile.Name),
|
||||||
|
PrimaryButtonText = "",
|
||||||
|
SecondaryButtonText = "",
|
||||||
|
CloseButtonText = LocaleManager.Instance["UserProfilesClose"],
|
||||||
|
Content = manager,
|
||||||
|
Padding = new Thickness(0)
|
||||||
|
};
|
||||||
|
|
||||||
|
await contentDialog.ShowAsync();
|
||||||
|
}
|
||||||
|
|
||||||
public void EditUser()
|
public void EditUser()
|
||||||
{
|
{
|
||||||
_owner.Navigate(typeof(UserEditor), (this._owner, _highlightedProfile ?? SelectedProfile, false));
|
_owner.Navigate(typeof(UserEditor), (this._owner, _highlightedProfile ?? SelectedProfile, false));
|
||||||
@ -134,5 +199,15 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
|
|
||||||
LoadProfiles();
|
LoadProfiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void GoBack()
|
||||||
|
{
|
||||||
|
_owner.GoBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RecoverLostAccounts()
|
||||||
|
{
|
||||||
|
_owner.Navigate(typeof(UserRecoverer), (this._owner, this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -15,7 +15,8 @@
|
|||||||
CanResize="False"
|
CanResize="False"
|
||||||
SizeToContent="Width"
|
SizeToContent="Width"
|
||||||
WindowStartupLocation="CenterOwner"
|
WindowStartupLocation="CenterOwner"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
<Grid
|
<Grid
|
||||||
Margin="15"
|
Margin="15"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
|
@ -11,7 +11,8 @@
|
|||||||
WindowStartupLocation="CenterOwner"
|
WindowStartupLocation="CenterOwner"
|
||||||
Width="800" MinHeight="650" Height="650"
|
Width="800" MinHeight="650" Height="650"
|
||||||
SizeToContent="Manual"
|
SizeToContent="Manual"
|
||||||
MinWidth="600">
|
MinWidth="600"
|
||||||
|
Focusable="True">
|
||||||
<Design.DataContext>
|
<Design.DataContext>
|
||||||
<viewModels:AmiiboWindowViewModel />
|
<viewModels:AmiiboWindowViewModel />
|
||||||
</Design.DataContext>
|
</Design.DataContext>
|
||||||
|
@ -11,7 +11,8 @@
|
|||||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
|
||||||
xmlns:controls="clr-namespace:Ryujinx.Ava.Ui.Controls"
|
xmlns:controls="clr-namespace:Ryujinx.Ava.Ui.Controls"
|
||||||
x:CompileBindings="True"
|
x:CompileBindings="True"
|
||||||
x:DataType="viewModels:AvatarProfileViewModel">
|
x:DataType="viewModels:AvatarProfileViewModel"
|
||||||
|
Focusable="True">
|
||||||
<Design.DataContext>
|
<Design.DataContext>
|
||||||
<viewModels:AvatarProfileViewModel />
|
<viewModels:AvatarProfileViewModel />
|
||||||
</Design.DataContext>
|
</Design.DataContext>
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
MinWidth="500"
|
MinWidth="500"
|
||||||
MinHeight="500"
|
MinHeight="500"
|
||||||
WindowStartupLocation="CenterOwner"
|
WindowStartupLocation="CenterOwner"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
<Window.Styles>
|
<Window.Styles>
|
||||||
<Style Selector="TreeViewItem">
|
<Style Selector="TreeViewItem">
|
||||||
<Setter Property="IsExpanded" Value="True" />
|
<Setter Property="IsExpanded" Value="True" />
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
x:Class="Ryujinx.Ava.Ui.Windows.ContentDialogOverlayWindow"
|
x:Class="Ryujinx.Ava.Ui.Windows.ContentDialogOverlayWindow"
|
||||||
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
||||||
Title="ContentDialogOverlayWindow">
|
Title="ContentDialogOverlayWindow"
|
||||||
|
Focusable="True">
|
||||||
<window:StyleableWindow.Styles>
|
<window:StyleableWindow.Styles>
|
||||||
<Style Selector="ui|ContentDialog /template/ Panel#LayoutRoot">
|
<Style Selector="ui|ContentDialog /template/ Panel#LayoutRoot">
|
||||||
<Setter Property="Background"
|
<Setter Property="Background"
|
||||||
|
@ -13,7 +13,8 @@
|
|||||||
d:DesignHeight="800"
|
d:DesignHeight="800"
|
||||||
d:DesignWidth="800"
|
d:DesignWidth="800"
|
||||||
x:CompileBindings="False"
|
x:CompileBindings="False"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
<Design.DataContext>
|
<Design.DataContext>
|
||||||
<viewModels:ControllerSettingsViewModel />
|
<viewModels:ControllerSettingsViewModel />
|
||||||
</Design.DataContext>
|
</Design.DataContext>
|
||||||
|
@ -14,7 +14,8 @@
|
|||||||
MaxHeight="500"
|
MaxHeight="500"
|
||||||
SizeToContent="Height"
|
SizeToContent="Height"
|
||||||
WindowStartupLocation="CenterOwner"
|
WindowStartupLocation="CenterOwner"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
<Grid Name="DownloadableContentGrid" Margin="15">
|
<Grid Name="DownloadableContentGrid" Margin="15">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
@ -20,7 +20,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
|
|
||||||
private const int CutOffLuminosity = 64;
|
private const int CutOffLuminosity = 64;
|
||||||
|
|
||||||
private struct PaletteColor
|
private readonly struct PaletteColor
|
||||||
{
|
{
|
||||||
public int Qck { get; }
|
public int Qck { get; }
|
||||||
public byte R { get; }
|
public byte R { get; }
|
||||||
|
@ -13,14 +13,15 @@
|
|||||||
Title="Ryujinx"
|
Title="Ryujinx"
|
||||||
Width="1280"
|
Width="1280"
|
||||||
Height="785"
|
Height="785"
|
||||||
MinWidth="1024"
|
MinWidth="1092"
|
||||||
MinHeight="680"
|
MinHeight="680"
|
||||||
d:DesignHeight="720"
|
d:DesignHeight="720"
|
||||||
d:DesignWidth="1280"
|
d:DesignWidth="1280"
|
||||||
x:CompileBindings="True"
|
x:CompileBindings="True"
|
||||||
x:DataType="viewModels:MainWindowViewModel"
|
x:DataType="viewModels:MainWindowViewModel"
|
||||||
WindowStartupLocation="CenterScreen"
|
WindowStartupLocation="CenterScreen"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
<Window.Styles>
|
<Window.Styles>
|
||||||
<Style Selector="TitleBar:fullscreen">
|
<Style Selector="TitleBar:fullscreen">
|
||||||
<Setter Property="Background" Value="#000000" />
|
<Setter Property="Background" Value="#000000" />
|
||||||
@ -57,6 +58,8 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<StackPanel
|
<StackPanel
|
||||||
|
Name="MenuBar"
|
||||||
|
MinHeight="35"
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Margin="0"
|
Margin="0"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
@ -549,6 +552,7 @@
|
|||||||
<Grid
|
<Grid
|
||||||
Name="StatusBar"
|
Name="StatusBar"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
|
MinHeight="30"
|
||||||
Height="30"
|
Height="30"
|
||||||
Margin="0,0"
|
Margin="0,0"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
|
@ -36,6 +36,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
{
|
{
|
||||||
public partial class MainWindow : StyleableWindow
|
public partial class MainWindow : StyleableWindow
|
||||||
{
|
{
|
||||||
|
internal static MainWindowViewModel MainWindowViewModel { get; private set; }
|
||||||
private bool _canUpdate;
|
private bool _canUpdate;
|
||||||
private bool _isClosing;
|
private bool _isClosing;
|
||||||
private bool _isLoading;
|
private bool _isLoading;
|
||||||
@ -81,6 +82,8 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
{
|
{
|
||||||
ViewModel = new MainWindowViewModel(this);
|
ViewModel = new MainWindowViewModel(this);
|
||||||
|
|
||||||
|
MainWindowViewModel = ViewModel;
|
||||||
|
|
||||||
DataContext = ViewModel;
|
DataContext = ViewModel;
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@ -90,7 +93,9 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
|
|
||||||
Title = $"Ryujinx {Program.Version}";
|
Title = $"Ryujinx {Program.Version}";
|
||||||
|
|
||||||
Height /= Program.WindowScaleFactor;
|
// 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;
|
||||||
|
Height = ((Height - barHeight) / Program.WindowScaleFactor) + barHeight;
|
||||||
Width /= Program.WindowScaleFactor;
|
Width /= Program.WindowScaleFactor;
|
||||||
|
|
||||||
if (Program.PreviewerDetached)
|
if (Program.PreviewerDetached)
|
||||||
@ -261,6 +266,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CanUpdate = false;
|
||||||
ViewModel.LoadHeading = string.IsNullOrWhiteSpace(titleName) ? string.Format(LocaleManager.Instance["LoadingHeading"], AppHost.Device.Application.TitleName) : titleName;
|
ViewModel.LoadHeading = string.IsNullOrWhiteSpace(titleName) ? string.Format(LocaleManager.Instance["LoadingHeading"], AppHost.Device.Application.TitleName) : titleName;
|
||||||
ViewModel.TitleName = string.IsNullOrWhiteSpace(titleName) ? AppHost.Device.Application.TitleName : titleName;
|
ViewModel.TitleName = string.IsNullOrWhiteSpace(titleName) ? AppHost.Device.Application.TitleName : titleName;
|
||||||
|
|
||||||
@ -366,6 +372,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
ViewModel.ShowContent = true;
|
ViewModel.ShowContent = true;
|
||||||
ViewModel.ShowLoadProgress = false;
|
ViewModel.ShowLoadProgress = false;
|
||||||
ViewModel.IsLoadingIndeterminate = false;
|
ViewModel.IsLoadingIndeterminate = false;
|
||||||
|
CanUpdate = true;
|
||||||
Cursor = Cursor.Default;
|
Cursor = Cursor.Default;
|
||||||
|
|
||||||
if (MainContent.Content != _mainViewContent)
|
if (MainContent.Content != _mainViewContent)
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
x:Class="Ryujinx.Ava.Ui.Windows.MotionSettingsWindow">
|
x:Class="Ryujinx.Ava.Ui.Windows.MotionSettingsWindow"
|
||||||
|
Focusable="True">
|
||||||
<Grid Margin="10">
|
<Grid Margin="10">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
x:Class="Ryujinx.Ava.Ui.Windows.RumbleSettingsWindow">
|
x:Class="Ryujinx.Ava.Ui.Windows.RumbleSettingsWindow"
|
||||||
|
Focusable="True">
|
||||||
<Grid Margin="10">
|
<Grid Margin="10">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
@ -18,7 +18,8 @@
|
|||||||
WindowStartupLocation="CenterOwner"
|
WindowStartupLocation="CenterOwner"
|
||||||
x:CompileBindings="True"
|
x:CompileBindings="True"
|
||||||
x:DataType="viewModels:SettingsViewModel"
|
x:DataType="viewModels:SettingsViewModel"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
<Design.DataContext>
|
<Design.DataContext>
|
||||||
<viewModels:SettingsViewModel />
|
<viewModels:SettingsViewModel />
|
||||||
</Design.DataContext>
|
</Design.DataContext>
|
||||||
@ -955,16 +956,25 @@
|
|||||||
Icon="Document" />
|
Icon="Document" />
|
||||||
</ui:NavigationView.MenuItems>
|
</ui:NavigationView.MenuItems>
|
||||||
</ui:NavigationView>
|
</ui:NavigationView>
|
||||||
<StackPanel
|
<ReversibleStackPanel
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Margin="10"
|
Margin="10"
|
||||||
Spacing="10"
|
Spacing="10"
|
||||||
Orientation="Horizontal"
|
Orientation="Horizontal"
|
||||||
HorizontalAlignment="Right">
|
HorizontalAlignment="Right"
|
||||||
<Button Content="{locale:Locale SettingsButtonSave}" Click="SaveButton_Clicked" />
|
ReverseOrder="{ReflectionBinding IsMacOS}">
|
||||||
<Button Content="{locale:Locale SettingsButtonClose}" Click="CloseButton_Clicked" />
|
<Button
|
||||||
<Button Content="{locale:Locale SettingsButtonApply}"
|
HotKey="Enter"
|
||||||
Click="ApplyButton_Clicked" />
|
Classes="accent"
|
||||||
</StackPanel>
|
Content="{locale:Locale SettingsButtonOk}"
|
||||||
|
Command="{ReflectionBinding OkButton}" />
|
||||||
|
<Button
|
||||||
|
HotKey="Escape"
|
||||||
|
Content="{locale:Locale SettingsButtonCancel}"
|
||||||
|
Command="{ReflectionBinding CancelButton}" />
|
||||||
|
<Button
|
||||||
|
Content="{locale:Locale SettingsButtonApply}"
|
||||||
|
Command="{ReflectionBinding ApplyButton}" />
|
||||||
|
</ReversibleStackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</window:StyleableWindow>
|
</window:StyleableWindow>
|
@ -199,36 +199,6 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SaveButton_Clicked(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
SaveSettings();
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CloseButton_Clicked(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
ViewModel.RevertIfNotSaved();
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ApplyButton_Clicked(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
SaveSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SaveSettings()
|
|
||||||
{
|
|
||||||
ViewModel.SaveSettings();
|
|
||||||
ControllerSettings?.SaveCurrentProfile();
|
|
||||||
|
|
||||||
if (Owner is MainWindow window && ViewModel.DirectoryChanged)
|
|
||||||
{
|
|
||||||
window.ViewModel.LoadApplications();
|
|
||||||
}
|
|
||||||
|
|
||||||
ViewModel.DirectoryChanged = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnClosed(EventArgs e)
|
protected override void OnClosed(EventArgs e)
|
||||||
{
|
{
|
||||||
ControllerSettings.Dispose();
|
ControllerSettings.Dispose();
|
||||||
|
@ -14,7 +14,8 @@
|
|||||||
MaxHeight="400"
|
MaxHeight="400"
|
||||||
SizeToContent="Height"
|
SizeToContent="Height"
|
||||||
WindowStartupLocation="CenterOwner"
|
WindowStartupLocation="CenterOwner"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
<Grid Margin="15">
|
<Grid Margin="15">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
@ -16,7 +16,7 @@ namespace Ryujinx.Common.Logging
|
|||||||
|
|
||||||
public static event EventHandler<LogEventArgs> Updated;
|
public static event EventHandler<LogEventArgs> Updated;
|
||||||
|
|
||||||
public struct Log
|
public readonly struct Log
|
||||||
{
|
{
|
||||||
internal readonly LogLevel Level;
|
internal readonly LogLevel Level;
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ namespace Ryujinx.Common.Memory
|
|||||||
/// This is useful to keep the Array representation when possible to avoid copies.
|
/// This is useful to keep the Array representation when possible to avoid copies.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">Element Type</typeparam>
|
/// <typeparam name="T">Element Type</typeparam>
|
||||||
public ref struct SpanOrArray<T> where T : unmanaged
|
public readonly ref struct SpanOrArray<T> where T : unmanaged
|
||||||
{
|
{
|
||||||
public readonly T[] Array;
|
public readonly T[] Array;
|
||||||
public readonly ReadOnlySpan<T> Span;
|
public readonly ReadOnlySpan<T> Span;
|
||||||
|
@ -28,9 +28,39 @@ namespace Ryujinx.Common.SystemInfo
|
|||||||
|
|
||||||
CpuName = $"{cpuName} ; {LogicalCoreCount} logical";
|
CpuName = $"{cpuName} ; {LogicalCoreCount} logical";
|
||||||
RamTotal = totalRAM;
|
RamTotal = totalRAM;
|
||||||
|
RamAvailable = GetVMInfoAvailableMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport("libSystem.dylib", CharSet = CharSet.Ansi, SetLastError = true)]
|
static ulong GetVMInfoAvailableMemory()
|
||||||
|
{
|
||||||
|
var port = mach_host_self();
|
||||||
|
|
||||||
|
uint pageSize = 0;
|
||||||
|
var result = host_page_size(port, ref pageSize);
|
||||||
|
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, $"Failed to query Available RAM. host_page_size() error = {result}");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int flavor = 4; // HOST_VM_INFO64
|
||||||
|
uint count = (uint)(Marshal.SizeOf<VMStatistics64>() / sizeof(int)); // HOST_VM_INFO64_COUNT
|
||||||
|
VMStatistics64 stats = new();
|
||||||
|
result = host_statistics64(port, flavor, ref stats, ref count);
|
||||||
|
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, $"Failed to query Available RAM. host_statistics64() error = {result}");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ulong)(stats.FreeCount + stats.InactiveCount) * pageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
private const string SystemLibraryName = "libSystem.dylib";
|
||||||
|
|
||||||
|
[DllImport(SystemLibraryName, CharSet = CharSet.Ansi, SetLastError = true)]
|
||||||
private static extern int sysctlbyname(string name, IntPtr oldValue, ref ulong oldSize, IntPtr newValue, ulong newValueSize);
|
private static extern int sysctlbyname(string name, IntPtr oldValue, ref ulong oldSize, IntPtr newValue, ulong newValueSize);
|
||||||
|
|
||||||
private static int sysctlbyname(string name, IntPtr oldValue, ref ulong oldSize)
|
private static int sysctlbyname(string name, IntPtr oldValue, ref ulong oldSize)
|
||||||
@ -85,5 +115,43 @@ namespace Ryujinx.Common.SystemInfo
|
|||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[DllImport(SystemLibraryName, CharSet = CharSet.Ansi, SetLastError = true)]
|
||||||
|
private static extern uint mach_host_self();
|
||||||
|
|
||||||
|
[DllImport(SystemLibraryName, CharSet = CharSet.Ansi, SetLastError = true)]
|
||||||
|
private static extern int host_page_size(uint host, ref uint out_page_size);
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||||
|
struct VMStatistics64
|
||||||
|
{
|
||||||
|
public uint FreeCount;
|
||||||
|
public uint ActiveCount;
|
||||||
|
public uint InactiveCount;
|
||||||
|
public uint WireCount;
|
||||||
|
public ulong ZeroFillCount;
|
||||||
|
public ulong Reactivations;
|
||||||
|
public ulong Pageins;
|
||||||
|
public ulong Pageouts;
|
||||||
|
public ulong Faults;
|
||||||
|
public ulong CowFaults;
|
||||||
|
public ulong Lookups;
|
||||||
|
public ulong Hits;
|
||||||
|
public ulong Purges;
|
||||||
|
public uint PurgeableCount;
|
||||||
|
public uint SpeculativeCount;
|
||||||
|
public ulong Decompressions;
|
||||||
|
public ulong Compressions;
|
||||||
|
public ulong Swapins;
|
||||||
|
public ulong Swapouts;
|
||||||
|
public uint CompressorPageCount;
|
||||||
|
public uint ThrottledCount;
|
||||||
|
public uint ExternalPageCount;
|
||||||
|
public uint InternalPageCount;
|
||||||
|
public ulong TotalUncompressedPagesInCompressor;
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport(SystemLibraryName, CharSet = CharSet.Ansi, SetLastError = true)]
|
||||||
|
private static extern int host_statistics64(uint host_priv, int host_flavor, ref VMStatistics64 host_info64_out, ref uint host_info64_outCnt);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -17,7 +17,7 @@ namespace Ryujinx.Cpu
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stores handlers for the various CPU exceptions.
|
/// Stores handlers for the various CPU exceptions.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public struct ExceptionCallbacks
|
public readonly struct ExceptionCallbacks
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handler for CPU interrupts triggered using <see cref="IExecutionContext.RequestInterrupt"/>.
|
/// Handler for CPU interrupts triggered using <see cref="IExecutionContext.RequestInterrupt"/>.
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Ryujinx.Graphics.Device
|
namespace Ryujinx.Graphics.Device
|
||||||
{
|
{
|
||||||
public struct RwCallback
|
public readonly struct RwCallback
|
||||||
{
|
{
|
||||||
public Action<int> Write { get; }
|
public Action<int> Write { get; }
|
||||||
public Func<int> Read { get; }
|
public Func<int> Read { get; }
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace Ryujinx.Graphics.GAL
|
namespace Ryujinx.Graphics.GAL
|
||||||
{
|
{
|
||||||
public struct BlendDescriptor
|
public readonly struct BlendDescriptor
|
||||||
{
|
{
|
||||||
public bool Enable { get; }
|
public bool Enable { get; }
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace Ryujinx.Graphics.GAL
|
namespace Ryujinx.Graphics.GAL
|
||||||
{
|
{
|
||||||
public struct BufferAssignment
|
public readonly struct BufferAssignment
|
||||||
{
|
{
|
||||||
public readonly int Binding;
|
public readonly int Binding;
|
||||||
public readonly BufferRange Range;
|
public readonly BufferRange Range;
|
||||||
|
@ -1,22 +1,14 @@
|
|||||||
using System;
|
using System.Runtime.InteropServices;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.GAL
|
namespace Ryujinx.Graphics.GAL
|
||||||
{
|
{
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 8)]
|
[StructLayout(LayoutKind.Sequential, Size = 8)]
|
||||||
public struct BufferHandle : IEquatable<BufferHandle>
|
public readonly record struct BufferHandle
|
||||||
{
|
{
|
||||||
private readonly ulong _value;
|
private readonly ulong _value;
|
||||||
|
|
||||||
public static BufferHandle Null => new BufferHandle(0);
|
public static BufferHandle Null => new BufferHandle(0);
|
||||||
|
|
||||||
private BufferHandle(ulong value) => _value = value;
|
private BufferHandle(ulong value) => _value = value;
|
||||||
|
|
||||||
public override bool Equals(object obj) => obj is BufferHandle handle && Equals(handle);
|
|
||||||
public bool Equals([AllowNull] BufferHandle other) => other._value == _value;
|
|
||||||
public override int GetHashCode() => _value.GetHashCode();
|
|
||||||
public static bool operator ==(BufferHandle left, BufferHandle right) => left.Equals(right);
|
|
||||||
public static bool operator !=(BufferHandle left, BufferHandle right) => !(left == right);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace Ryujinx.Graphics.GAL
|
namespace Ryujinx.Graphics.GAL
|
||||||
{
|
{
|
||||||
public struct BufferRange
|
public readonly struct BufferRange
|
||||||
{
|
{
|
||||||
private static readonly BufferRange _empty = new BufferRange(BufferHandle.Null, 0, 0);
|
private static readonly BufferRange _empty = new BufferRange(BufferHandle.Null, 0, 0);
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ using Ryujinx.Graphics.Shader.Translation;
|
|||||||
|
|
||||||
namespace Ryujinx.Graphics.GAL
|
namespace Ryujinx.Graphics.GAL
|
||||||
{
|
{
|
||||||
public struct Capabilities
|
public readonly struct Capabilities
|
||||||
{
|
{
|
||||||
public readonly TargetApi Api;
|
public readonly TargetApi Api;
|
||||||
public readonly string VendorName;
|
public readonly string VendorName;
|
||||||
@ -17,6 +17,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
public readonly bool Supports3DTextureCompression;
|
public readonly bool Supports3DTextureCompression;
|
||||||
public readonly bool SupportsBgraFormat;
|
public readonly bool SupportsBgraFormat;
|
||||||
public readonly bool SupportsR4G4Format;
|
public readonly bool SupportsR4G4Format;
|
||||||
|
public readonly bool SupportsSnormBufferTextureFormat;
|
||||||
public readonly bool SupportsFragmentShaderInterlock;
|
public readonly bool SupportsFragmentShaderInterlock;
|
||||||
public readonly bool SupportsFragmentShaderOrderingIntel;
|
public readonly bool SupportsFragmentShaderOrderingIntel;
|
||||||
public readonly bool SupportsGeometryShaderPassthrough;
|
public readonly bool SupportsGeometryShaderPassthrough;
|
||||||
@ -52,6 +53,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
bool supports3DTextureCompression,
|
bool supports3DTextureCompression,
|
||||||
bool supportsBgraFormat,
|
bool supportsBgraFormat,
|
||||||
bool supportsR4G4Format,
|
bool supportsR4G4Format,
|
||||||
|
bool supportsSnormBufferTextureFormat,
|
||||||
bool supportsFragmentShaderInterlock,
|
bool supportsFragmentShaderInterlock,
|
||||||
bool supportsFragmentShaderOrderingIntel,
|
bool supportsFragmentShaderOrderingIntel,
|
||||||
bool supportsGeometryShaderPassthrough,
|
bool supportsGeometryShaderPassthrough,
|
||||||
@ -84,6 +86,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
Supports3DTextureCompression = supports3DTextureCompression;
|
Supports3DTextureCompression = supports3DTextureCompression;
|
||||||
SupportsBgraFormat = supportsBgraFormat;
|
SupportsBgraFormat = supportsBgraFormat;
|
||||||
SupportsR4G4Format = supportsR4G4Format;
|
SupportsR4G4Format = supportsR4G4Format;
|
||||||
|
SupportsSnormBufferTextureFormat = supportsSnormBufferTextureFormat;
|
||||||
SupportsFragmentShaderInterlock = supportsFragmentShaderInterlock;
|
SupportsFragmentShaderInterlock = supportsFragmentShaderInterlock;
|
||||||
SupportsFragmentShaderOrderingIntel = supportsFragmentShaderOrderingIntel;
|
SupportsFragmentShaderOrderingIntel = supportsFragmentShaderOrderingIntel;
|
||||||
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;
|
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;
|
||||||
|
@ -1,32 +1,4 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.GAL
|
namespace Ryujinx.Graphics.GAL
|
||||||
{
|
{
|
||||||
public struct ColorF : IEquatable<ColorF>
|
public readonly record struct ColorF(float Red, float Green, float Blue, float Alpha);
|
||||||
{
|
|
||||||
public float Red { get; }
|
|
||||||
public float Green { get; }
|
|
||||||
public float Blue { get; }
|
|
||||||
public float Alpha { get; }
|
|
||||||
|
|
||||||
public ColorF(float red, float green, float blue, float alpha)
|
|
||||||
{
|
|
||||||
Red = red;
|
|
||||||
Green = green;
|
|
||||||
Blue = blue;
|
|
||||||
Alpha = alpha;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Equals(ColorF color) => Red == color.Red &&
|
|
||||||
Green == color.Green &&
|
|
||||||
Blue == color.Blue &&
|
|
||||||
Alpha == color.Alpha;
|
|
||||||
|
|
||||||
public override bool Equals(object obj) => (obj is ColorF color) && Equals(color);
|
|
||||||
|
|
||||||
public override int GetHashCode() => HashCode.Combine(Red, Green, Blue, Alpha);
|
|
||||||
|
|
||||||
public static bool operator ==(ColorF l, ColorF r) => l.Equals(r);
|
|
||||||
public static bool operator !=(ColorF l, ColorF r) => !l.Equals(r);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace Ryujinx.Graphics.GAL
|
namespace Ryujinx.Graphics.GAL
|
||||||
{
|
{
|
||||||
public struct DepthTestDescriptor
|
public readonly struct DepthTestDescriptor
|
||||||
{
|
{
|
||||||
public bool TestEnable { get; }
|
public bool TestEnable { get; }
|
||||||
public bool WriteEnable { get; }
|
public bool WriteEnable { get; }
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace Ryujinx.Graphics.GAL
|
namespace Ryujinx.Graphics.GAL
|
||||||
{
|
{
|
||||||
public struct DeviceInfo
|
public readonly struct DeviceInfo
|
||||||
{
|
{
|
||||||
public readonly string Id;
|
public readonly string Id;
|
||||||
public readonly string Vendor;
|
public readonly string Vendor;
|
||||||
|
@ -2,7 +2,7 @@ using Ryujinx.Common;
|
|||||||
|
|
||||||
namespace Ryujinx.Graphics.GAL
|
namespace Ryujinx.Graphics.GAL
|
||||||
{
|
{
|
||||||
public struct Extents2D
|
public readonly struct Extents2D
|
||||||
{
|
{
|
||||||
public int X1 { get; }
|
public int X1 { get; }
|
||||||
public int Y1 { get; }
|
public int Y1 { get; }
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace Ryujinx.Graphics.GAL
|
namespace Ryujinx.Graphics.GAL
|
||||||
{
|
{
|
||||||
public struct Extents2DF
|
public readonly struct Extents2DF
|
||||||
{
|
{
|
||||||
public float X1 { get; }
|
public float X1 { get; }
|
||||||
public float Y1 { get; }
|
public float Y1 { get; }
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace Ryujinx.Graphics.GAL
|
namespace Ryujinx.Graphics.GAL
|
||||||
{
|
{
|
||||||
public struct HardwareInfo
|
public readonly struct HardwareInfo
|
||||||
{
|
{
|
||||||
public string GpuVendor { get; }
|
public string GpuVendor { get; }
|
||||||
public string GpuModel { get; }
|
public string GpuModel { get; }
|
||||||
|
@ -29,6 +29,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
ReadOnlySpan<byte> GetBufferData(BufferHandle buffer, int offset, int size);
|
ReadOnlySpan<byte> GetBufferData(BufferHandle buffer, int offset, int size);
|
||||||
|
|
||||||
Capabilities GetCapabilities();
|
Capabilities GetCapabilities();
|
||||||
|
ulong GetCurrentSync();
|
||||||
HardwareInfo GetHardwareInfo();
|
HardwareInfo GetHardwareInfo();
|
||||||
|
|
||||||
IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info);
|
IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace Ryujinx.Graphics.GAL
|
namespace Ryujinx.Graphics.GAL
|
||||||
{
|
{
|
||||||
public struct ImageCrop
|
public readonly struct ImageCrop
|
||||||
{
|
{
|
||||||
public int Left { get; }
|
public int Left { get; }
|
||||||
public int Right { get; }
|
public int Right { get; }
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user