Merge branch ryujinx:master into input-mapping-simplification

This commit is contained in:
Neo 2025-11-17 02:42:40 -06:00
commit 89bcc9e653
28 changed files with 469 additions and 269 deletions

View file

@ -361,10 +361,7 @@ namespace ARMeilleure.Translation
IntervalTreeNode<TK, TV> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode); IntervalTreeNode<TK, TV> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
if (tmp != null) tmp?.Parent = ParentOf(replacementNode);
{
tmp.Parent = ParentOf(replacementNode);
}
if (ParentOf(replacementNode) == null) if (ParentOf(replacementNode) == null)
{ {
@ -582,10 +579,7 @@ namespace ARMeilleure.Translation
{ {
IntervalTreeNode<TK, TV> right = RightOf(node); IntervalTreeNode<TK, TV> right = RightOf(node);
node.Right = LeftOf(right); node.Right = LeftOf(right);
if (node.Right != null) node.Right?.Parent = node;
{
node.Right.Parent = node;
}
IntervalTreeNode<TK, TV> nodeParent = ParentOf(node); IntervalTreeNode<TK, TV> nodeParent = ParentOf(node);
right.Parent = nodeParent; right.Parent = nodeParent;
@ -615,10 +609,7 @@ namespace ARMeilleure.Translation
{ {
IntervalTreeNode<TK, TV> left = LeftOf(node); IntervalTreeNode<TK, TV> left = LeftOf(node);
node.Left = RightOf(left); node.Left = RightOf(left);
if (node.Left != null) node.Left?.Parent = node;
{
node.Left.Parent = node;
}
IntervalTreeNode<TK, TV> nodeParent = ParentOf(node); IntervalTreeNode<TK, TV> nodeParent = ParentOf(node);
left.Parent = nodeParent; left.Parent = nodeParent;
@ -667,10 +658,7 @@ namespace ARMeilleure.Translation
/// <param name="color">Color (Boolean)</param> /// <param name="color">Color (Boolean)</param>
private static void SetColor(IntervalTreeNode<TK, TV> node, bool color) private static void SetColor(IntervalTreeNode<TK, TV> node, bool color)
{ {
if (node != null) node?.Color = color;
{
node.Color = color;
}
} }
/// <summary> /// <summary>

View file

@ -386,10 +386,7 @@ namespace Ryujinx.Common.Collections
IntervalTreeNode<TKey, TValue> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode); IntervalTreeNode<TKey, TValue> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
if (tmp != null) tmp?.Parent = ParentOf(replacementNode);
{
tmp.Parent = ParentOf(replacementNode);
}
if (ParentOf(replacementNode) == null) if (ParentOf(replacementNode) == null)
{ {

View file

@ -235,10 +235,7 @@ namespace Ryujinx.Common.Collections
parent = ParentOf(element); parent = ParentOf(element);
color = ColorOf(element); color = ColorOf(element);
if (child != null) child?.Parent = parent;
{
child.Parent = parent;
}
if (parent == null) if (parent == null)
{ {
@ -258,8 +255,7 @@ namespace Ryujinx.Common.Collections
element.Right = old.Right; element.Right = old.Right;
element.Parent = old.Parent; element.Parent = old.Parent;
element.Predecessor = old.Predecessor; element.Predecessor = old.Predecessor;
if (element.Predecessor != null) element.Predecessor?.Successor = element;
element.Predecessor.Successor = element;
if (ParentOf(old) == null) if (ParentOf(old) == null)
{ {
@ -292,10 +288,7 @@ namespace Ryujinx.Common.Collections
parent = ParentOf(nodeToDelete); parent = ParentOf(nodeToDelete);
color = ColorOf(nodeToDelete); color = ColorOf(nodeToDelete);
if (child != null) child?.Parent = parent;
{
child.Parent = parent;
}
if (parent == null) if (parent == null)
{ {
@ -314,11 +307,9 @@ namespace Ryujinx.Common.Collections
{ {
RestoreBalanceAfterRemoval(child); RestoreBalanceAfterRemoval(child);
} }
if (old.Successor != null) old.Successor?.Predecessor = old.Predecessor;
old.Successor.Predecessor = old.Predecessor; old.Predecessor?.Successor = old.Successor;
if (old.Predecessor != null)
old.Predecessor.Successor = old.Successor;
return old; return old;
} }

View file

@ -250,10 +250,7 @@ namespace Ryujinx.Common.Collections
{ {
T right = RightOf(node); T right = RightOf(node);
node.Right = LeftOf(right); node.Right = LeftOf(right);
if (node.Right != null) node.Right?.Parent = node;
{
node.Right.Parent = node;
}
T nodeParent = ParentOf(node); T nodeParent = ParentOf(node);
right.Parent = nodeParent; right.Parent = nodeParent;
@ -281,10 +278,7 @@ namespace Ryujinx.Common.Collections
{ {
T left = LeftOf(node); T left = LeftOf(node);
node.Left = RightOf(left); node.Left = RightOf(left);
if (node.Left != null) node.Left?.Parent = node;
{
node.Left.Parent = node;
}
T nodeParent = ParentOf(node); T nodeParent = ParentOf(node);
left.Parent = nodeParent; left.Parent = nodeParent;
@ -329,10 +323,7 @@ namespace Ryujinx.Common.Collections
/// <param name="color">Color (Boolean)</param> /// <param name="color">Color (Boolean)</param>
protected static void SetColor(T node, bool color) protected static void SetColor(T node, bool color)
{ {
if (node != null) node?.Color = color;
{
node.Color = color;
}
} }
/// <summary> /// <summary>

View file

@ -328,10 +328,7 @@ namespace Ryujinx.Common.Collections
Node<TKey, TValue> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode); Node<TKey, TValue> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
if (tmp != null) tmp?.Parent = ParentOf(replacementNode);
{
tmp.Parent = ParentOf(replacementNode);
}
if (ParentOf(replacementNode) == null) if (ParentOf(replacementNode) == null)
{ {

View file

@ -35,6 +35,7 @@ namespace Ryujinx.Common.Logging
ServiceBsd, ServiceBsd,
ServiceBtm, ServiceBtm,
ServiceCaps, ServiceCaps,
ServiceEctx,
ServiceFatal, ServiceFatal,
ServiceFriend, ServiceFriend,
ServiceFs, ServiceFs,

View file

@ -84,10 +84,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ICounterEvent evt = _items[index + i].Event; ICounterEvent evt = _items[index + i].Event;
if (evt != null) evt?.Invalid = true;
{
evt.Invalid = true;
}
} }
_items.RemoveRange(index, count); _items.RemoveRange(index, count);

View file

@ -26,12 +26,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
// - Both branches are jumping to the same location. // - Both branches are jumping to the same location.
// In this case, the branch on the current block can be removed, // In this case, the branch on the current block can be removed,
// as the next block is going to jump to the same place anyway. // as the next block is going to jump to the same place anyway.
if (nextBlock == null)
{
return false;
}
if (nextBlock.Operations.First?.Value is not Operation next) if (nextBlock?.Operations.First?.Value is not Operation next)
{ {
return false; return false;
} }

View file

@ -891,10 +891,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
result = new NestedName(name, prev); result = new NestedName(name, prev);
} }
if (context != null) context?.FinishWithTemplateArguments = false;
{
context.FinishWithTemplateArguments = false;
}
return result; return result;
} }
@ -1074,10 +1071,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
return null; return null;
} }
if (context != null) context?.CtorDtorConversion = true;
{
context.CtorDtorConversion = true;
}
return new ConversionOperatorType(type); return new ConversionOperatorType(type);
default: default:
@ -1349,10 +1343,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
_position++; _position++;
if (context != null) context?.CtorDtorConversion = true;
{
context.CtorDtorConversion = true;
}
if (isInherited && ParseName(context) == null) if (isInherited && ParseName(context) == null)
{ {
@ -1372,10 +1363,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
_position++; _position++;
if (context != null) context?.CtorDtorConversion = true;
{
context.CtorDtorConversion = true;
}
return new CtorDtorNameType(prev, true); return new CtorDtorNameType(prev, true);
} }
@ -3005,16 +2993,10 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
BaseNode result = null; BaseNode result = null;
CvType cv = new(ParseCvQualifiers(), null); CvType cv = new(ParseCvQualifiers(), null);
if (context != null) context?.Cv = cv;
{
context.Cv = cv;
}
SimpleReferenceType Ref = ParseRefQualifiers(); SimpleReferenceType Ref = ParseRefQualifiers();
if (context != null) context?.Ref = Ref;
{
context.Ref = Ref;
}
if (ConsumeIf("St")) if (ConsumeIf("St"))
{ {
@ -3060,10 +3042,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
} }
result = new NameTypeWithTemplateArguments(result, templateArgument); result = new NameTypeWithTemplateArguments(result, templateArgument);
if (context != null) context?.FinishWithTemplateArguments = true;
{
context.FinishWithTemplateArguments = true;
}
_substitutionList.Add(result); _substitutionList.Add(result);
continue; continue;
@ -3256,10 +3235,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
return null; return null;
} }
if (context != null) context?.FinishWithTemplateArguments = true;
{
context.FinishWithTemplateArguments = true;
}
return new NameTypeWithTemplateArguments(substitution, templateArguments); return new NameTypeWithTemplateArguments(substitution, templateArguments);
} }
@ -3279,10 +3255,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
return null; return null;
} }
if (context != null) context?.FinishWithTemplateArguments = true;
{
context.FinishWithTemplateArguments = true;
}
return new NameTypeWithTemplateArguments(result, templateArguments); return new NameTypeWithTemplateArguments(result, templateArguments);
} }

View file

@ -174,10 +174,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
if (previousThread != nextThread) if (previousThread != nextThread)
{ {
if (previousThread != null) previousThread?.LastScheduledTime = PerformanceCounter.ElapsedTicks;
{
previousThread.LastScheduledTime = PerformanceCounter.ElapsedTicks;
}
_state.SelectedThread = nextThread; _state.SelectedThread = nextThread;
_state.NeedsScheduling = true; _state.NeedsScheduling = true;

View file

@ -0,0 +1,32 @@
using System;
using Ryujinx.Common.Logging;
using Ryujinx.Horizon.Common;
namespace Ryujinx.HLE.HOS.Services.Ectx
{
class IContextRegistrar : DisposableIpcService
{
public IContextRegistrar(ServiceCtx context) { }
[CommandCmif(0)] // 11.0.0+
// Complete(nn::Result result, buffer<bytes, 5> raw_context) -> (i32 context_descriptor)
public ResultCode Complete(ServiceCtx context)
{
Result result = new(context.RequestData.ReadInt32());
ulong rawContextPosition = context.Request.SendBuff[0].Position;
ulong rawContextSize = context.Request.SendBuff[0].Size;
byte[] rawContext = new byte[rawContextSize];
context.Memory.Read(rawContextPosition, rawContext);
context.ResponseData.Write(0); // TODO: return context_descriptor
Logger.Stub?.PrintStub(LogClass.ServiceEctx, $"Result: {result}, rawContext: {Convert.ToHexString(rawContext)}" );
return ResultCode.Success;
}
protected override void Dispose(bool isDisposing) { }
}
}

View file

@ -4,5 +4,14 @@ namespace Ryujinx.HLE.HOS.Services.Ectx
class IWriterForApplication : IpcService class IWriterForApplication : IpcService
{ {
public IWriterForApplication(ServiceCtx context) { } public IWriterForApplication(ServiceCtx context) { }
[CommandCmif(0)]
// CreateContextRegistrar() -> object<nn::err::context::IContextRegistrar>
public ResultCode CreateContextRegistrar(ServiceCtx context)
{
MakeObject(context, new IContextRegistrar(context));
return ResultCode.Success;
}
} }
} }

View file

@ -1169,9 +1169,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
public override void DestroyAtExit() public override void DestroyAtExit()
{ {
if (_context != null) { _context?.Dispose();
_context.Dispose();
}
} }
} }
} }

View file

@ -58,10 +58,7 @@ namespace Ryujinx.Memory.Tracking
{ {
foreach (RegionHandle handle in _handles) foreach (RegionHandle handle in _handles)
{ {
if (handle != null) handle?.RegisterAction((address, size) => action(handle.Address, handle.Size));
{
handle?.RegisterAction((address, size) => action(handle.Address, handle.Size));
}
} }
} }
@ -69,10 +66,7 @@ namespace Ryujinx.Memory.Tracking
{ {
foreach (RegionHandle handle in _handles) foreach (RegionHandle handle in _handles)
{ {
if (handle != null) handle?.RegisterPreciseAction((address, size, write) => action(handle.Address, handle.Size, write));
{
handle?.RegisterPreciseAction((address, size, write) => action(handle.Address, handle.Size, write));
}
} }
} }

View file

@ -501,18 +501,12 @@ namespace Ryujinx.Ava.Systems
private void UpdateIgnoreMissingServicesState(object sender, ReactiveEventArgs<bool> args) private void UpdateIgnoreMissingServicesState(object sender, ReactiveEventArgs<bool> args)
{ {
if (Device != null) Device?.Configuration.IgnoreMissingServices = args.NewValue;
{
Device.Configuration.IgnoreMissingServices = args.NewValue;
}
} }
private void UpdateAspectRatioState(object sender, ReactiveEventArgs<AspectRatio> args) private void UpdateAspectRatioState(object sender, ReactiveEventArgs<AspectRatio> args)
{ {
if (Device != null) Device?.Configuration.AspectRatio = args.NewValue;
{
Device.Configuration.AspectRatio = args.NewValue;
}
} }
private void UpdateAntiAliasing(object sender, ReactiveEventArgs<AntiAliasing> e) private void UpdateAntiAliasing(object sender, ReactiveEventArgs<AntiAliasing> e)

View file

@ -88,14 +88,10 @@ namespace Ryujinx.Ava.Systems
{ {
if (showVersionUpToDate) if (showVersionUpToDate)
{ {
UserResult userResult = await ContentDialogHelper.CreateUpdaterUpToDateInfoDialog( await ContentDialogHelper.CreateUpdaterUpToDateInfoDialog(
LocaleManager.Instance[LocaleKeys.DialogUpdaterAlreadyOnLatestVersionMessage], LocaleManager.Instance[LocaleKeys.DialogUpdaterAlreadyOnLatestVersionMessage],
string.Empty); string.Empty,
_versionResponse.ReleaseUrlFormat.Format(currentVersion));
if (userResult is UserResult.Ok)
{
OpenHelper.OpenUrl(_versionResponse.ReleaseUrlFormat.Format(currentVersion));
}
} }
Logger.Info?.Print(LogClass.Application, "Up to date."); Logger.Info?.Print(LogClass.Application, "Up to date.");

View file

@ -60,14 +60,10 @@ namespace Ryujinx.Ava.Systems
{ {
if (showVersionUpToDate) if (showVersionUpToDate)
{ {
UserResult userResult = await ContentDialogHelper.CreateUpdaterUpToDateInfoDialog( await ContentDialogHelper.CreateUpdaterUpToDateInfoDialog(
LocaleManager.Instance[LocaleKeys.DialogUpdaterAlreadyOnLatestVersionMessage], LocaleManager.Instance[LocaleKeys.DialogUpdaterAlreadyOnLatestVersionMessage],
string.Empty); string.Empty,
changelogUrl: _versionResponse.ReleaseUrlFormat.Format(currentVersion));
if (userResult is UserResult.Ok)
{
OpenHelper.OpenUrl(_versionResponse.ReleaseUrlFormat.Format(currentVersion));
}
} }
Logger.Info?.Print(LogClass.Application, "Up to date."); Logger.Info?.Print(LogClass.Application, "Up to date.");
@ -106,22 +102,18 @@ namespace Ryujinx.Ava.Systems
Logger.Info?.Print(LogClass.Application, $"Version found: {newVersionString.Replace("", "->")}"); Logger.Info?.Print(LogClass.Application, $"Version found: {newVersionString.Replace("", "->")}");
RequestUserToUpdate:
// Show a message asking the user if they want to update // Show a message asking the user if they want to update
UserResult shouldUpdate = await ContentDialogHelper.CreateUpdaterChoiceDialog( UserResult shouldUpdate = await ContentDialogHelper.CreateUpdaterChoiceDialog(
LocaleManager.Instance[LocaleKeys.RyujinxUpdater], LocaleManager.Instance[LocaleKeys.RyujinxUpdater],
LocaleManager.Instance[LocaleKeys.RyujinxUpdaterMessage], LocaleManager.Instance[LocaleKeys.RyujinxUpdaterMessage],
newVersionString); newVersionString,
ReleaseInformation.GetChangelogUrl(currentVersion, newVersion));
switch (shouldUpdate) switch (shouldUpdate)
{ {
case UserResult.Yes: case UserResult.Yes:
await UpdateRyujinx(_versionResponse.ArtifactUrl); await UpdateRyujinx(_versionResponse.ArtifactUrl);
break; break;
// Secondary button maps to no, which in this case is the show changelog button.
case UserResult.No:
OpenHelper.OpenUrl(ReleaseInformation.GetChangelogUrl(currentVersion, newVersion));
goto RequestUserToUpdate;
default: default:
_running = false; _running = false;
break; break;

View file

@ -167,10 +167,7 @@ namespace Ryujinx.Ava.UI.Controls
private void Message_TextInput(object sender, TextInputEventArgs e) private void Message_TextInput(object sender, TextInputEventArgs e)
{ {
if (_host != null) _host?.IsPrimaryButtonEnabled = _checkLength(Message.Length) && _checkInput(Message);
{
_host.IsPrimaryButtonEnabled = _checkLength(Message.Length) && _checkInput(Message);
}
} }
private void Message_KeyUp(object sender, KeyEventArgs e) private void Message_KeyUp(object sender, KeyEventArgs e)

View file

@ -10,6 +10,7 @@ using FluentAvalonia.Core;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using Ryujinx.Common.Helper;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using System; using System;
using System.Threading; using System.Threading;
@ -102,6 +103,25 @@ namespace Ryujinx.Ava.UI.Helpers
return await ShowContentDialog(title, content, primaryButton, secondaryButton, closeButton, primaryButtonResult, deferResetEvent, deferCloseAction); return await ShowContentDialog(title, content, primaryButton, secondaryButton, closeButton, primaryButtonResult, deferResetEvent, deferCloseAction);
} }
public async static Task<UserResult> ShowTextDialogWithButton(
string title,
string primaryText,
string secondaryText,
string primaryButton,
string secondaryButton,
string closeButton,
int iconSymbol,
string buttonText,
Action onClick,
UserResult primaryButtonResult = UserResult.Ok,
ManualResetEvent deferResetEvent = null,
TypedEventHandler<ContentDialog, ContentDialogButtonClickEventArgs> deferCloseAction = null)
{
Grid content = CreateTextDialogContentWithButton(primaryText, secondaryText, iconSymbol, buttonText, onClick);
return await ShowContentDialog(title, content, primaryButton, secondaryButton, closeButton, primaryButtonResult, deferResetEvent, deferCloseAction);
}
public static async Task<UserResult> ShowDeferredContentDialog( public static async Task<UserResult> ShowDeferredContentDialog(
Window window, Window window,
@ -173,43 +193,109 @@ namespace Ryujinx.Ava.UI.Helpers
MinHeight = 80, MinHeight = 80,
}; };
SymbolIcon icon = new() content.Children.Add(new SymbolIcon
{ {
Symbol = (Symbol)symbol, Symbol = (Symbol)symbol,
Margin = new Thickness(10), Margin = new Thickness(10),
FontSize = 40, FontSize = 40,
FlowDirection = FlowDirection.LeftToRight, FlowDirection = FlowDirection.LeftToRight,
VerticalAlignment = VerticalAlignment.Center, VerticalAlignment = VerticalAlignment.Center,
}; GridColumn = 0,
GridRow = 0,
GridRowSpan = 2
});
Grid.SetColumn(icon, 0); content.Children.Add(new TextBlock
Grid.SetRowSpan(icon, 2);
Grid.SetRow(icon, 0);
TextBlock primaryLabel = new()
{ {
Text = primaryText, Text = primaryText,
Margin = new Thickness(5), Margin = new Thickness(5),
TextWrapping = TextWrapping.Wrap, TextWrapping = TextWrapping.Wrap,
MaxWidth = 450, MaxWidth = 450,
}; GridColumn = 1,
GridRow = 0
});
TextBlock secondaryLabel = new() content.Children.Add(new TextBlock
{ {
Text = secondaryText, Text = secondaryText,
Margin = new Thickness(5), Margin = new Thickness(5),
TextWrapping = TextWrapping.Wrap, TextWrapping = TextWrapping.Wrap,
MaxWidth = 450, MaxWidth = 450,
GridColumn = 1,
GridRow = 1
});
return content;
}
private static Grid CreateTextDialogContentWithButton(string primaryText, string secondaryText, int symbol, string buttonName, Action onClick)
{
Grid content = new()
{
RowDefinitions = [new(), new(), new(GridLength.Star), new()],
ColumnDefinitions = [new(GridLength.Auto), new()],
MinHeight = 80,
}; };
Grid.SetColumn(primaryLabel, 1); content.Children.Add(new SymbolIcon
Grid.SetColumn(secondaryLabel, 1); {
Grid.SetRow(primaryLabel, 0); Symbol = (Symbol)symbol,
Grid.SetRow(secondaryLabel, 1); Margin = new Thickness(10),
FontSize = 40,
FlowDirection = FlowDirection.LeftToRight,
VerticalAlignment = VerticalAlignment.Center,
GridColumn = 0,
GridRow = 0,
GridRowSpan = 2
});
content.Children.Add(icon); StackPanel buttonContent = new()
content.Children.Add(primaryLabel); {
content.Children.Add(secondaryLabel); Orientation = Orientation.Horizontal,
Spacing = 2
};
buttonContent.Children.Add(new TextBlock
{
Text = buttonName,
Margin = new Thickness(2)
});
buttonContent.Children.Add(new SymbolIcon
{
FlowDirection = FlowDirection.LeftToRight,
Symbol = Symbol.Open
});
content.Children.Add(new TextBlock
{
Text = primaryText,
Margin = new Thickness(5),
TextWrapping = TextWrapping.Wrap,
MaxWidth = 450,
GridColumn = 1,
GridRow = 0
});
content.Children.Add(new TextBlock
{
Text = secondaryText,
Margin = new Thickness(5),
TextWrapping = TextWrapping.Wrap,
MaxWidth = 450,
GridColumn = 1,
GridRow = 1
});
content.Children.Add(new Button
{
Content = buttonContent,
HorizontalAlignment = HorizontalAlignment.Center,
Command = Commands.Create(onClick),
GridRow = 2,
GridColumnSpan = 2,
});
return content; return content;
} }
@ -282,15 +368,20 @@ namespace Ryujinx.Ava.UI.Helpers
LocaleManager.Instance[LocaleKeys.InputDialogOk], LocaleManager.Instance[LocaleKeys.InputDialogOk],
(int)Symbol.Important); (int)Symbol.Important);
internal static async Task<UserResult> CreateUpdaterUpToDateInfoDialog(string primary, string secondaryText) internal static async Task CreateUpdaterUpToDateInfoDialog(string primary, string secondaryText,
=> await ShowTextDialog( string changelogUrl)
{
await ShowTextDialogWithButton(
LocaleManager.Instance[LocaleKeys.DialogUpdaterTitle], LocaleManager.Instance[LocaleKeys.DialogUpdaterTitle],
primary, primary,
secondaryText, secondaryText,
LocaleManager.Instance[LocaleKeys.DialogUpdaterShowChangelogMessage], string.Empty,
string.Empty, string.Empty,
LocaleManager.Instance[LocaleKeys.InputDialogOk], LocaleManager.Instance[LocaleKeys.InputDialogOk],
(int)Symbol.Important); (int)Symbol.Important,
LocaleManager.Instance[LocaleKeys.DialogUpdaterShowChangelogMessage],
() => OpenHelper.OpenUrl(changelogUrl));
}
internal static async Task CreateWarningDialog(string primary, string secondaryText) internal static async Task CreateWarningDialog(string primary, string secondaryText)
=> await ShowTextDialog( => await ShowTextDialog(
@ -340,7 +431,7 @@ namespace Ryujinx.Ava.UI.Helpers
return response == UserResult.Yes; return response == UserResult.Yes;
} }
internal static async Task<UserResult> CreateUpdaterChoiceDialog(string title, string primary, string secondaryText) internal static async Task<UserResult> CreateUpdaterChoiceDialog(string title, string primary, string secondaryText, string changelogUrl)
{ {
if (_isChoiceDialogOpen) if (_isChoiceDialogOpen)
{ {
@ -349,14 +440,16 @@ namespace Ryujinx.Ava.UI.Helpers
_isChoiceDialogOpen = true; _isChoiceDialogOpen = true;
UserResult response = await ShowTextDialog( UserResult response = await ShowTextDialogWithButton(
title, title,
primary, primary,
secondaryText, secondaryText,
LocaleManager.Instance[LocaleKeys.InputDialogYes], LocaleManager.Instance[LocaleKeys.InputDialogYes],
LocaleManager.Instance[LocaleKeys.DialogUpdaterShowChangelogMessage], string.Empty,
LocaleManager.Instance[LocaleKeys.InputDialogNo], LocaleManager.Instance[LocaleKeys.InputDialogNo],
(int)Symbol.Help, (int)Symbol.Help,
LocaleManager.Instance[LocaleKeys.DialogUpdaterShowChangelogMessage],
() => OpenHelper.OpenUrl(changelogUrl),
UserResult.Yes); UserResult.Yes);
_isChoiceDialogOpen = false; _isChoiceDialogOpen = false;

View file

@ -0,0 +1,40 @@
using Avalonia.Controls;
namespace Ryujinx.Ava.UI.Helpers
{
public static class ControlExtensions
{
extension(Control ctrl)
{
public int GridRow
{
get => Grid.GetRow(ctrl);
set => Grid.SetRow(ctrl, value);
}
public int GridColumn
{
get => Grid.GetColumn(ctrl);
set => Grid.SetColumn(ctrl, value);
}
public int GridRowSpan
{
get => Grid.GetRowSpan(ctrl);
set => Grid.SetRowSpan(ctrl, value);
}
public int GridColumnSpan
{
get => Grid.GetColumnSpan(ctrl);
set => Grid.SetColumnSpan(ctrl, value);
}
public bool GridIsSharedSizeScope
{
get => Grid.GetIsSharedSizeScope(ctrl);
set => Grid.SetIsSharedSizeScope(ctrl, value);
}
}
}
}

View file

@ -27,82 +27,136 @@ namespace Ryujinx.Ava.UI.Models.Input
public ControllerType ControllerType { get; set; } public ControllerType ControllerType { get; set; }
public PlayerIndex PlayerIndex { get; set; } public PlayerIndex PlayerIndex { get; set; }
[ObservableProperty] private StickInputId _leftJoystick; [ObservableProperty]
[ObservableProperty] private bool _leftInvertStickX; public partial StickInputId LeftJoystick { get; set; }
[ObservableProperty] private bool _leftInvertStickY;
[ObservableProperty] private bool _leftRotate90;
[ObservableProperty] private GamepadInputId _leftStickButton;
[ObservableProperty] private StickInputId _rightJoystick; [ObservableProperty]
[ObservableProperty] private bool _rightInvertStickX; public partial bool LeftInvertStickX { get; set; }
[ObservableProperty] private bool _rightInvertStickY;
[ObservableProperty] private bool _rightRotate90;
[ObservableProperty] private GamepadInputId _rightStickButton;
[ObservableProperty] private GamepadInputId _dpadUp; [ObservableProperty]
[ObservableProperty] private GamepadInputId _dpadDown; public partial bool LeftInvertStickY { get; set; }
[ObservableProperty] private GamepadInputId _dpadLeft;
[ObservableProperty] private GamepadInputId _dpadRight;
[ObservableProperty] private GamepadInputId _buttonMinus; [ObservableProperty]
[ObservableProperty] private GamepadInputId _buttonPlus; public partial bool LeftRotate90 { get; set; }
[ObservableProperty] private GamepadInputId _buttonA; [ObservableProperty]
[ObservableProperty] private GamepadInputId _buttonB; public partial GamepadInputId LeftStickButton { get; set; }
[ObservableProperty] private GamepadInputId _buttonX;
[ObservableProperty] private GamepadInputId _buttonY;
[ObservableProperty] private GamepadInputId _buttonZl; [ObservableProperty]
[ObservableProperty] private GamepadInputId _buttonZr; public partial StickInputId RightJoystick { get; set; }
[ObservableProperty] private GamepadInputId _buttonL; [ObservableProperty]
[ObservableProperty] private GamepadInputId _buttonR; public partial bool RightInvertStickX { get; set; }
[ObservableProperty] private GamepadInputId _leftButtonSl; [ObservableProperty]
[ObservableProperty] private GamepadInputId _leftButtonSr; public partial bool RightInvertStickY { get; set; }
[ObservableProperty] private GamepadInputId _rightButtonSl; [ObservableProperty]
[ObservableProperty] private GamepadInputId _rightButtonSr; public partial bool RightRotate90 { get; set; }
[ObservableProperty] private float _deadzoneLeft; [ObservableProperty]
[ObservableProperty] private float _deadzoneRight; public partial GamepadInputId RightStickButton { get; set; }
[ObservableProperty] private float _rangeLeft; [ObservableProperty]
[ObservableProperty] private float _rangeRight; public partial GamepadInputId DpadUp { get; set; }
[ObservableProperty] private float _triggerThreshold; [ObservableProperty]
public partial GamepadInputId DpadDown { get; set; }
[ObservableProperty] private bool _enableMotion; [ObservableProperty]
public partial GamepadInputId DpadLeft { get; set; }
[ObservableProperty] private bool _enableRumble; [ObservableProperty]
public partial GamepadInputId DpadRight { get; set; }
[ObservableProperty] private bool _enableLedChanging; [ObservableProperty]
public partial GamepadInputId ButtonMinus { get; set; }
[ObservableProperty] private Color _ledColor; [ObservableProperty]
public partial GamepadInputId ButtonPlus { get; set; }
[ObservableProperty]
public partial GamepadInputId ButtonA { get; set; }
[ObservableProperty]
public partial GamepadInputId ButtonB { get; set; }
[ObservableProperty]
public partial GamepadInputId ButtonX { get; set; }
[ObservableProperty]
public partial GamepadInputId ButtonY { get; set; }
[ObservableProperty]
public partial GamepadInputId ButtonZl { get; set; }
[ObservableProperty]
public partial GamepadInputId ButtonZr { get; set; }
[ObservableProperty]
public partial GamepadInputId ButtonL { get; set; }
[ObservableProperty]
public partial GamepadInputId ButtonR { get; set; }
[ObservableProperty]
public partial GamepadInputId LeftButtonSl { get; set; }
[ObservableProperty]
public partial GamepadInputId LeftButtonSr { get; set; }
[ObservableProperty]
public partial GamepadInputId RightButtonSl { get; set; }
[ObservableProperty]
public partial GamepadInputId RightButtonSr { get; set; }
[ObservableProperty]
public partial float DeadzoneLeft { get; set; }
[ObservableProperty]
public partial float DeadzoneRight { get; set; }
[ObservableProperty]
public partial float RangeLeft { get; set; }
[ObservableProperty]
public partial float RangeRight { get; set; }
[ObservableProperty]
public partial float TriggerThreshold { get; set; }
[ObservableProperty]
public partial bool EnableMotion { get; set; }
[ObservableProperty]
public partial bool EnableRumble { get; set; }
[ObservableProperty]
public partial bool EnableLedChanging { get; set; }
[ObservableProperty]
public partial Color LedColor { get; set; }
public bool ShowLedColorPicker => !TurnOffLed && !UseRainbowLed; public bool ShowLedColorPicker => !TurnOffLed && !UseRainbowLed;
private bool _turnOffLed;
public bool TurnOffLed public bool TurnOffLed
{ {
get => _turnOffLed; get;
set set
{ {
_turnOffLed = value; field = value;
OnPropertyChanged(); OnPropertyChanged();
OnPropertyChanged(nameof(ShowLedColorPicker)); OnPropertyChanged(nameof(ShowLedColorPicker));
} }
} }
private bool _useRainbowLed;
public bool UseRainbowLed public bool UseRainbowLed
{ {
get => _useRainbowLed; get;
set set
{ {
_useRainbowLed = value; field = value;
OnPropertyChanged(); OnPropertyChanged();
OnPropertyChanged(nameof(ShowLedColorPicker)); OnPropertyChanged(nameof(ShowLedColorPicker));
} }

View file

@ -6,31 +6,44 @@ namespace Ryujinx.Ava.UI.Models.Input
{ {
public partial class HotkeyConfig : BaseModel public partial class HotkeyConfig : BaseModel
{ {
[ObservableProperty] private Key _toggleVSyncMode; [ObservableProperty]
public partial Key ToggleVSyncMode { get; set; }
[ObservableProperty] private Key _screenshot; [ObservableProperty]
public partial Key Screenshot { get; set; }
[ObservableProperty] private Key _showUI; [ObservableProperty]
public partial Key ShowUI { get; set; }
[ObservableProperty] private Key _pause; [ObservableProperty]
public partial Key Pause { get; set; }
[ObservableProperty] private Key _toggleMute; [ObservableProperty]
public partial Key ToggleMute { get; set; }
[ObservableProperty] private Key _resScaleUp; [ObservableProperty]
public partial Key ResScaleUp { get; set; }
[ObservableProperty] private Key _resScaleDown; [ObservableProperty]
public partial Key ResScaleDown { get; set; }
[ObservableProperty] private Key _volumeUp; [ObservableProperty]
public partial Key VolumeUp { get; set; }
[ObservableProperty] private Key _volumeDown; [ObservableProperty]
public partial Key VolumeDown { get; set; }
[ObservableProperty] private Key _customVSyncIntervalIncrement; [ObservableProperty]
public partial Key CustomVSyncIntervalIncrement { get; set; }
[ObservableProperty] private Key _customVSyncIntervalDecrement; [ObservableProperty]
public partial Key CustomVSyncIntervalDecrement { get; set; }
[ObservableProperty] private Key _turboMode; [ObservableProperty]
public partial Key TurboMode { get; set; }
[ObservableProperty] private bool _turboModeWhileHeld; [ObservableProperty]
public partial bool TurboModeWhileHeld { get; set; }
public HotkeyConfig(KeyboardHotkeys config) public HotkeyConfig(KeyboardHotkeys config)
{ {

View file

@ -12,42 +12,89 @@ namespace Ryujinx.Ava.UI.Models.Input
public ControllerType ControllerType { get; set; } public ControllerType ControllerType { get; set; }
public PlayerIndex PlayerIndex { get; set; } public PlayerIndex PlayerIndex { get; set; }
[ObservableProperty] private Key _leftStickUp; [ObservableProperty]
[ObservableProperty] private Key _leftStickDown; public partial Key LeftStickUp { get; set; }
[ObservableProperty] private Key _leftStickLeft;
[ObservableProperty] private Key _leftStickRight;
[ObservableProperty] private Key _leftStickButton;
[ObservableProperty] private Key _rightStickUp; [ObservableProperty]
[ObservableProperty] private Key _rightStickDown; public partial Key LeftStickDown { get; set; }
[ObservableProperty] private Key _rightStickLeft;
[ObservableProperty] private Key _rightStickRight;
[ObservableProperty] private Key _rightStickButton;
[ObservableProperty] private Key _dpadUp; [ObservableProperty]
[ObservableProperty] private Key _dpadDown; public partial Key LeftStickLeft { get; set; }
[ObservableProperty] private Key _dpadLeft;
[ObservableProperty] private Key _dpadRight;
[ObservableProperty] private Key _buttonMinus; [ObservableProperty]
[ObservableProperty] private Key _buttonPlus; public partial Key LeftStickRight { get; set; }
[ObservableProperty] private Key _buttonA; [ObservableProperty]
[ObservableProperty] private Key _buttonB; public partial Key LeftStickButton { get; set; }
[ObservableProperty] private Key _buttonX;
[ObservableProperty] private Key _buttonY;
[ObservableProperty] private Key _buttonL; [ObservableProperty]
[ObservableProperty] private Key _buttonR; public partial Key RightStickUp { get; set; }
[ObservableProperty] private Key _buttonZl; [ObservableProperty]
[ObservableProperty] private Key _buttonZr; public partial Key RightStickDown { get; set; }
[ObservableProperty] private Key _leftButtonSl; [ObservableProperty]
[ObservableProperty] private Key _leftButtonSr; public partial Key RightStickLeft { get; set; }
[ObservableProperty] private Key _rightButtonSl; [ObservableProperty]
[ObservableProperty] private Key _rightButtonSr; public partial Key RightStickRight { get; set; }
[ObservableProperty]
public partial Key RightStickButton { get; set; }
[ObservableProperty]
public partial Key DpadUp { get; set; }
[ObservableProperty]
public partial Key DpadDown { get; set; }
[ObservableProperty]
public partial Key DpadLeft { get; set; }
[ObservableProperty]
public partial Key DpadRight { get; set; }
[ObservableProperty]
public partial Key ButtonMinus { get; set; }
[ObservableProperty]
public partial Key ButtonPlus { get; set; }
[ObservableProperty]
public partial Key ButtonA { get; set; }
[ObservableProperty]
public partial Key ButtonB { get; set; }
[ObservableProperty]
public partial Key ButtonX { get; set; }
[ObservableProperty]
public partial Key ButtonY { get; set; }
[ObservableProperty]
public partial Key ButtonL { get; set; }
[ObservableProperty]
public partial Key ButtonR { get; set; }
[ObservableProperty]
public partial Key ButtonZl { get; set; }
[ObservableProperty]
public partial Key ButtonZr { get; set; }
[ObservableProperty]
public partial Key LeftButtonSl { get; set; }
[ObservableProperty]
public partial Key LeftButtonSr { get; set; }
[ObservableProperty]
public partial Key RightButtonSl { get; set; }
[ObservableProperty]
public partial Key RightButtonSr { get; set; }
public KeyboardInputConfig(InputConfig config) public KeyboardInputConfig(InputConfig config)
{ {

View file

@ -6,8 +6,8 @@ namespace Ryujinx.Ava.UI.Models
{ {
public partial class ModModel : BaseModel public partial class ModModel : BaseModel
{ {
[ObservableProperty] private bool _enabled; [ObservableProperty]
public partial bool Enabled { get; set; }
public bool InSd { get; } public bool InSd { get; }
public string Path { get; } public string Path { get; }
public string Name { get; } public string Name { get; }

View file

@ -15,6 +15,7 @@ namespace Ryujinx.Ava.UI.Models
public string Name { get; set; } public string Name { get; set; }
public byte[] Data { get; set; } public byte[] Data { get; set; }
[ObservableProperty] private SolidColorBrush _backgroundColor = new(Colors.White); [ObservableProperty]
public partial SolidColorBrush BackgroundColor { get; set; } = new(Colors.White);
} }
} }

View file

@ -7,24 +7,26 @@ namespace Ryujinx.Ava.UI.Models
{ {
public partial class TempProfile : BaseModel public partial class TempProfile : BaseModel
{ {
[ObservableProperty] private byte[] _image; [ObservableProperty]
[ObservableProperty] private string _name = String.Empty; public partial byte[] Image { get; set; }
private UserId _userId;
[ObservableProperty]
public partial string Name { get; set; } = string.Empty;
public static uint MaxProfileNameLength => 0x20; public static uint MaxProfileNameLength => 0x20;
public UserId UserId public UserId UserId
{ {
get => _userId; get;
set set
{ {
_userId = value; field = value;
OnPropertyChanged(); OnPropertyChanged();
OnPropertyChanged(nameof(UserIdString)); OnPropertyChanged(nameof(UserIdString));
} }
} }
public string UserIdString => _userId.ToString(); public string UserIdString => UserId.ToString();
public TempProfile(UserProfile profile) public TempProfile(UserProfile profile)
{ {

View file

@ -13,11 +13,20 @@ namespace Ryujinx.Ava.UI.Models
{ {
private readonly Profile _profile; private readonly Profile _profile;
private readonly NavigationDialogHost _owner; private readonly NavigationDialogHost _owner;
[ObservableProperty] private byte[] _image; [ObservableProperty]
[ObservableProperty] private string _name; public partial byte[] Image { get; set; }
[ObservableProperty] private UserId _userId;
[ObservableProperty] private bool _isPointerOver; [ObservableProperty]
[ObservableProperty] private IBrush _backgroundColor; public partial string Name { get; set; }
[ObservableProperty]
public partial UserId UserId { get; set; }
[ObservableProperty]
public partial bool IsPointerOver { get; set; }
[ObservableProperty]
public partial IBrush BackgroundColor { get; set; }
public UserProfile(Profile profile, NavigationDialogHost owner) public UserProfile(Profile profile, NavigationDialogHost owner)
{ {
@ -39,7 +48,7 @@ namespace Ryujinx.Ava.UI.Models
private void UpdateBackground() private void UpdateBackground()
{ {
Application currentApplication = Avalonia.Application.Current; Application currentApplication = Application.Current;
currentApplication.Styles.TryGetResource("ControlFillColorSecondary", currentApplication.ActualThemeVariant, out object color); currentApplication.Styles.TryGetResource("ControlFillColorSecondary", currentApplication.ActualThemeVariant, out object color);
if (color is not null) if (color is not null)

View file

@ -359,8 +359,9 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
[ObservableProperty] private bool _matchSystemTime; [ObservableProperty]
public partial bool MatchSystemTime { get; set; }
public DateTimeOffset CurrentDate { get; set; } public DateTimeOffset CurrentDate { get; set; }
public TimeSpan CurrentTime { get; set; } public TimeSpan CurrentTime { get; set; }