diff --git a/src/ARMeilleure/Translation/IntervalTree.cs b/src/ARMeilleure/Translation/IntervalTree.cs index f4abe3bd5..5af487e28 100644 --- a/src/ARMeilleure/Translation/IntervalTree.cs +++ b/src/ARMeilleure/Translation/IntervalTree.cs @@ -361,10 +361,7 @@ namespace ARMeilleure.Translation IntervalTreeNode tmp = LeftOf(replacementNode) ?? RightOf(replacementNode); - if (tmp != null) - { - tmp.Parent = ParentOf(replacementNode); - } + tmp?.Parent = ParentOf(replacementNode); if (ParentOf(replacementNode) == null) { @@ -582,10 +579,7 @@ namespace ARMeilleure.Translation { IntervalTreeNode right = RightOf(node); node.Right = LeftOf(right); - if (node.Right != null) - { - node.Right.Parent = node; - } + node.Right?.Parent = node; IntervalTreeNode nodeParent = ParentOf(node); right.Parent = nodeParent; @@ -615,10 +609,7 @@ namespace ARMeilleure.Translation { IntervalTreeNode left = LeftOf(node); node.Left = RightOf(left); - if (node.Left != null) - { - node.Left.Parent = node; - } + node.Left?.Parent = node; IntervalTreeNode nodeParent = ParentOf(node); left.Parent = nodeParent; @@ -667,10 +658,7 @@ namespace ARMeilleure.Translation /// Color (Boolean) private static void SetColor(IntervalTreeNode node, bool color) { - if (node != null) - { - node.Color = color; - } + node?.Color = color; } /// diff --git a/src/Ryujinx.Common/Collections/IntervalTree.cs b/src/Ryujinx.Common/Collections/IntervalTree.cs index a094a5a61..cc2062d48 100644 --- a/src/Ryujinx.Common/Collections/IntervalTree.cs +++ b/src/Ryujinx.Common/Collections/IntervalTree.cs @@ -386,10 +386,7 @@ namespace Ryujinx.Common.Collections IntervalTreeNode tmp = LeftOf(replacementNode) ?? RightOf(replacementNode); - if (tmp != null) - { - tmp.Parent = ParentOf(replacementNode); - } + tmp?.Parent = ParentOf(replacementNode); if (ParentOf(replacementNode) == null) { diff --git a/src/Ryujinx.Common/Collections/IntrusiveRedBlackTree.cs b/src/Ryujinx.Common/Collections/IntrusiveRedBlackTree.cs index d951a6024..55bfe0019 100644 --- a/src/Ryujinx.Common/Collections/IntrusiveRedBlackTree.cs +++ b/src/Ryujinx.Common/Collections/IntrusiveRedBlackTree.cs @@ -235,10 +235,7 @@ namespace Ryujinx.Common.Collections parent = ParentOf(element); color = ColorOf(element); - if (child != null) - { - child.Parent = parent; - } + child?.Parent = parent; if (parent == null) { @@ -258,8 +255,7 @@ namespace Ryujinx.Common.Collections element.Right = old.Right; element.Parent = old.Parent; element.Predecessor = old.Predecessor; - if (element.Predecessor != null) - element.Predecessor.Successor = element; + element.Predecessor?.Successor = element; if (ParentOf(old) == null) { @@ -292,10 +288,7 @@ namespace Ryujinx.Common.Collections parent = ParentOf(nodeToDelete); color = ColorOf(nodeToDelete); - if (child != null) - { - child.Parent = parent; - } + child?.Parent = parent; if (parent == null) { @@ -314,11 +307,9 @@ namespace Ryujinx.Common.Collections { RestoreBalanceAfterRemoval(child); } - - if (old.Successor != null) - old.Successor.Predecessor = old.Predecessor; - if (old.Predecessor != null) - old.Predecessor.Successor = old.Successor; + + old.Successor?.Predecessor = old.Predecessor; + old.Predecessor?.Successor = old.Successor; return old; } diff --git a/src/Ryujinx.Common/Collections/IntrusiveRedBlackTreeImpl.cs b/src/Ryujinx.Common/Collections/IntrusiveRedBlackTreeImpl.cs index abd3723fe..58bcc4fe5 100644 --- a/src/Ryujinx.Common/Collections/IntrusiveRedBlackTreeImpl.cs +++ b/src/Ryujinx.Common/Collections/IntrusiveRedBlackTreeImpl.cs @@ -250,10 +250,7 @@ namespace Ryujinx.Common.Collections { T right = RightOf(node); node.Right = LeftOf(right); - if (node.Right != null) - { - node.Right.Parent = node; - } + node.Right?.Parent = node; T nodeParent = ParentOf(node); right.Parent = nodeParent; @@ -281,10 +278,7 @@ namespace Ryujinx.Common.Collections { T left = LeftOf(node); node.Left = RightOf(left); - if (node.Left != null) - { - node.Left.Parent = node; - } + node.Left?.Parent = node; T nodeParent = ParentOf(node); left.Parent = nodeParent; @@ -329,10 +323,7 @@ namespace Ryujinx.Common.Collections /// Color (Boolean) protected static void SetColor(T node, bool color) { - if (node != null) - { - node.Color = color; - } + node?.Color = color; } /// diff --git a/src/Ryujinx.Common/Collections/TreeDictionary.cs b/src/Ryujinx.Common/Collections/TreeDictionary.cs index 453f128d3..ef818167d 100644 --- a/src/Ryujinx.Common/Collections/TreeDictionary.cs +++ b/src/Ryujinx.Common/Collections/TreeDictionary.cs @@ -328,10 +328,7 @@ namespace Ryujinx.Common.Collections Node tmp = LeftOf(replacementNode) ?? RightOf(replacementNode); - if (tmp != null) - { - tmp.Parent = ParentOf(replacementNode); - } + tmp?.Parent = ParentOf(replacementNode); if (ParentOf(replacementNode) == null) { diff --git a/src/Ryujinx.Common/Logging/LogClass.cs b/src/Ryujinx.Common/Logging/LogClass.cs index 89f0336dc..eb0821db6 100644 --- a/src/Ryujinx.Common/Logging/LogClass.cs +++ b/src/Ryujinx.Common/Logging/LogClass.cs @@ -35,6 +35,7 @@ namespace Ryujinx.Common.Logging ServiceBsd, ServiceBtm, ServiceCaps, + ServiceEctx, ServiceFatal, ServiceFriend, ServiceFs, diff --git a/src/Ryujinx.Graphics.Gpu/Memory/CounterCache.cs b/src/Ryujinx.Graphics.Gpu/Memory/CounterCache.cs index 2d67c2c28..33381dd55 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/CounterCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/CounterCache.cs @@ -84,10 +84,7 @@ namespace Ryujinx.Graphics.Gpu.Memory for (int i = 0; i < count; i++) { ICounterEvent evt = _items[index + i].Event; - if (evt != null) - { - evt.Invalid = true; - } + evt?.Invalid = true; } _items.RemoveRange(index, count); diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BranchElimination.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BranchElimination.cs index bd2eceda5..ab988f70e 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BranchElimination.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BranchElimination.cs @@ -26,12 +26,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations // - Both branches are jumping to the same location. // 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. - 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; } diff --git a/src/Ryujinx.HLE/HOS/Diagnostics/Demangler/Demangler.cs b/src/Ryujinx.HLE/HOS/Diagnostics/Demangler/Demangler.cs index 5424342fb..98f122e37 100644 --- a/src/Ryujinx.HLE/HOS/Diagnostics/Demangler/Demangler.cs +++ b/src/Ryujinx.HLE/HOS/Diagnostics/Demangler/Demangler.cs @@ -891,10 +891,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler result = new NestedName(name, prev); } - if (context != null) - { - context.FinishWithTemplateArguments = false; - } + context?.FinishWithTemplateArguments = false; return result; } @@ -1074,10 +1071,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler return null; } - if (context != null) - { - context.CtorDtorConversion = true; - } + context?.CtorDtorConversion = true; return new ConversionOperatorType(type); default: @@ -1349,10 +1343,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler _position++; - if (context != null) - { - context.CtorDtorConversion = true; - } + context?.CtorDtorConversion = true; if (isInherited && ParseName(context) == null) { @@ -1372,10 +1363,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler _position++; - if (context != null) - { - context.CtorDtorConversion = true; - } + context?.CtorDtorConversion = true; return new CtorDtorNameType(prev, true); } @@ -3005,16 +2993,10 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler BaseNode result = null; CvType cv = new(ParseCvQualifiers(), null); - if (context != null) - { - context.Cv = cv; - } + context?.Cv = cv; SimpleReferenceType Ref = ParseRefQualifiers(); - if (context != null) - { - context.Ref = Ref; - } + context?.Ref = Ref; if (ConsumeIf("St")) { @@ -3060,10 +3042,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler } result = new NameTypeWithTemplateArguments(result, templateArgument); - if (context != null) - { - context.FinishWithTemplateArguments = true; - } + context?.FinishWithTemplateArguments = true; _substitutionList.Add(result); continue; @@ -3256,10 +3235,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler return null; } - if (context != null) - { - context.FinishWithTemplateArguments = true; - } + context?.FinishWithTemplateArguments = true; return new NameTypeWithTemplateArguments(substitution, templateArguments); } @@ -3279,10 +3255,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler return null; } - if (context != null) - { - context.FinishWithTemplateArguments = true; - } + context?.FinishWithTemplateArguments = true; return new NameTypeWithTemplateArguments(result, templateArguments); } diff --git a/src/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs b/src/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs index b97ba705c..330624b2b 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs @@ -174,10 +174,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading if (previousThread != nextThread) { - if (previousThread != null) - { - previousThread.LastScheduledTime = PerformanceCounter.ElapsedTicks; - } + previousThread?.LastScheduledTime = PerformanceCounter.ElapsedTicks; _state.SelectedThread = nextThread; _state.NeedsScheduling = true; diff --git a/src/Ryujinx.HLE/HOS/Services/Ectx/IContextRegistrar.cs b/src/Ryujinx.HLE/HOS/Services/Ectx/IContextRegistrar.cs new file mode 100644 index 000000000..34adfe9be --- /dev/null +++ b/src/Ryujinx.HLE/HOS/Services/Ectx/IContextRegistrar.cs @@ -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 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) { } + } +} diff --git a/src/Ryujinx.HLE/HOS/Services/Ectx/IWriterForApplication.cs b/src/Ryujinx.HLE/HOS/Services/Ectx/IWriterForApplication.cs index cf2cdddc2..c8ef155e3 100644 --- a/src/Ryujinx.HLE/HOS/Services/Ectx/IWriterForApplication.cs +++ b/src/Ryujinx.HLE/HOS/Services/Ectx/IWriterForApplication.cs @@ -4,5 +4,14 @@ namespace Ryujinx.HLE.HOS.Services.Ectx class IWriterForApplication : IpcService { public IWriterForApplication(ServiceCtx context) { } + + [CommandCmif(0)] + // CreateContextRegistrar() -> object + public ResultCode CreateContextRegistrar(ServiceCtx context) + { + MakeObject(context, new IContextRegistrar(context)); + + return ResultCode.Success; + } } } diff --git a/src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs b/src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs index f22b1eb14..ef3b68b27 100644 --- a/src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs +++ b/src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs @@ -1169,9 +1169,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd public override void DestroyAtExit() { - if (_context != null) { - _context.Dispose(); - } + _context?.Dispose(); } } } diff --git a/src/Ryujinx.Memory/Tracking/SmartMultiRegionHandle.cs b/src/Ryujinx.Memory/Tracking/SmartMultiRegionHandle.cs index ccd60e8da..7e350712b 100644 --- a/src/Ryujinx.Memory/Tracking/SmartMultiRegionHandle.cs +++ b/src/Ryujinx.Memory/Tracking/SmartMultiRegionHandle.cs @@ -58,10 +58,7 @@ namespace Ryujinx.Memory.Tracking { 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) { - 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)); } } diff --git a/src/Ryujinx/Systems/AppHost.cs b/src/Ryujinx/Systems/AppHost.cs index f9e99c62b..2eba0d26b 100644 --- a/src/Ryujinx/Systems/AppHost.cs +++ b/src/Ryujinx/Systems/AppHost.cs @@ -501,18 +501,12 @@ namespace Ryujinx.Ava.Systems private void UpdateIgnoreMissingServicesState(object sender, ReactiveEventArgs args) { - if (Device != null) - { - Device.Configuration.IgnoreMissingServices = args.NewValue; - } + Device?.Configuration.IgnoreMissingServices = args.NewValue; } private void UpdateAspectRatioState(object sender, ReactiveEventArgs args) { - if (Device != null) - { - Device.Configuration.AspectRatio = args.NewValue; - } + Device?.Configuration.AspectRatio = args.NewValue; } private void UpdateAntiAliasing(object sender, ReactiveEventArgs e) diff --git a/src/Ryujinx/Systems/Updater/Updater.GitLab.cs b/src/Ryujinx/Systems/Updater/Updater.GitLab.cs index 17f01c136..deb515797 100644 --- a/src/Ryujinx/Systems/Updater/Updater.GitLab.cs +++ b/src/Ryujinx/Systems/Updater/Updater.GitLab.cs @@ -88,14 +88,10 @@ namespace Ryujinx.Ava.Systems { if (showVersionUpToDate) { - UserResult userResult = await ContentDialogHelper.CreateUpdaterUpToDateInfoDialog( + await ContentDialogHelper.CreateUpdaterUpToDateInfoDialog( LocaleManager.Instance[LocaleKeys.DialogUpdaterAlreadyOnLatestVersionMessage], - string.Empty); - - if (userResult is UserResult.Ok) - { - OpenHelper.OpenUrl(_versionResponse.ReleaseUrlFormat.Format(currentVersion)); - } + string.Empty, + _versionResponse.ReleaseUrlFormat.Format(currentVersion)); } Logger.Info?.Print(LogClass.Application, "Up to date."); diff --git a/src/Ryujinx/Systems/Updater/Updater.cs b/src/Ryujinx/Systems/Updater/Updater.cs index a02d3c940..bc45f8ff6 100644 --- a/src/Ryujinx/Systems/Updater/Updater.cs +++ b/src/Ryujinx/Systems/Updater/Updater.cs @@ -60,14 +60,10 @@ namespace Ryujinx.Ava.Systems { if (showVersionUpToDate) { - UserResult userResult = await ContentDialogHelper.CreateUpdaterUpToDateInfoDialog( + await ContentDialogHelper.CreateUpdaterUpToDateInfoDialog( LocaleManager.Instance[LocaleKeys.DialogUpdaterAlreadyOnLatestVersionMessage], - string.Empty); - - if (userResult is UserResult.Ok) - { - OpenHelper.OpenUrl(_versionResponse.ReleaseUrlFormat.Format(currentVersion)); - } + string.Empty, + changelogUrl: _versionResponse.ReleaseUrlFormat.Format(currentVersion)); } 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("→", "->")}"); - RequestUserToUpdate: // Show a message asking the user if they want to update UserResult shouldUpdate = await ContentDialogHelper.CreateUpdaterChoiceDialog( LocaleManager.Instance[LocaleKeys.RyujinxUpdater], LocaleManager.Instance[LocaleKeys.RyujinxUpdaterMessage], - newVersionString); + newVersionString, + ReleaseInformation.GetChangelogUrl(currentVersion, newVersion)); switch (shouldUpdate) { case UserResult.Yes: await UpdateRyujinx(_versionResponse.ArtifactUrl); 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: _running = false; break; diff --git a/src/Ryujinx/UI/Applet/SwkbdAppletDialog.axaml.cs b/src/Ryujinx/UI/Applet/SwkbdAppletDialog.axaml.cs index dd5b7d9f1..bef6fc47d 100644 --- a/src/Ryujinx/UI/Applet/SwkbdAppletDialog.axaml.cs +++ b/src/Ryujinx/UI/Applet/SwkbdAppletDialog.axaml.cs @@ -167,10 +167,7 @@ namespace Ryujinx.Ava.UI.Controls 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) diff --git a/src/Ryujinx/UI/Helpers/ContentDialogHelper.cs b/src/Ryujinx/UI/Helpers/ContentDialogHelper.cs index e8730913c..65de07e6e 100644 --- a/src/Ryujinx/UI/Helpers/ContentDialogHelper.cs +++ b/src/Ryujinx/UI/Helpers/ContentDialogHelper.cs @@ -10,6 +10,7 @@ using FluentAvalonia.Core; using FluentAvalonia.UI.Controls; using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.UI.Windows; +using Ryujinx.Common.Helper; using Ryujinx.Common.Logging; using System; using System.Threading; @@ -102,6 +103,25 @@ namespace Ryujinx.Ava.UI.Helpers return await ShowContentDialog(title, content, primaryButton, secondaryButton, closeButton, primaryButtonResult, deferResetEvent, deferCloseAction); } + + public async static Task 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 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 ShowDeferredContentDialog( Window window, @@ -173,43 +193,109 @@ namespace Ryujinx.Ava.UI.Helpers MinHeight = 80, }; - SymbolIcon icon = new() + content.Children.Add(new SymbolIcon { Symbol = (Symbol)symbol, Margin = new Thickness(10), FontSize = 40, FlowDirection = FlowDirection.LeftToRight, VerticalAlignment = VerticalAlignment.Center, - }; + GridColumn = 0, + GridRow = 0, + GridRowSpan = 2 + }); - Grid.SetColumn(icon, 0); - Grid.SetRowSpan(icon, 2); - Grid.SetRow(icon, 0); - - TextBlock primaryLabel = new() + content.Children.Add(new TextBlock { Text = primaryText, Margin = new Thickness(5), TextWrapping = TextWrapping.Wrap, MaxWidth = 450, - }; + GridColumn = 1, + GridRow = 0 + }); - TextBlock secondaryLabel = new() + content.Children.Add(new TextBlock { Text = secondaryText, Margin = new Thickness(5), TextWrapping = TextWrapping.Wrap, 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); - Grid.SetColumn(secondaryLabel, 1); - Grid.SetRow(primaryLabel, 0); - Grid.SetRow(secondaryLabel, 1); + content.Children.Add(new SymbolIcon + { + Symbol = (Symbol)symbol, + Margin = new Thickness(10), + FontSize = 40, + FlowDirection = FlowDirection.LeftToRight, + VerticalAlignment = VerticalAlignment.Center, + GridColumn = 0, + GridRow = 0, + GridRowSpan = 2 + }); - content.Children.Add(icon); - content.Children.Add(primaryLabel); - content.Children.Add(secondaryLabel); + StackPanel buttonContent = new() + { + 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; } @@ -282,15 +368,20 @@ namespace Ryujinx.Ava.UI.Helpers LocaleManager.Instance[LocaleKeys.InputDialogOk], (int)Symbol.Important); - internal static async Task CreateUpdaterUpToDateInfoDialog(string primary, string secondaryText) - => await ShowTextDialog( + internal static async Task CreateUpdaterUpToDateInfoDialog(string primary, string secondaryText, + string changelogUrl) + { + await ShowTextDialogWithButton( LocaleManager.Instance[LocaleKeys.DialogUpdaterTitle], primary, secondaryText, - LocaleManager.Instance[LocaleKeys.DialogUpdaterShowChangelogMessage], + string.Empty, string.Empty, 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) => await ShowTextDialog( @@ -340,7 +431,7 @@ namespace Ryujinx.Ava.UI.Helpers return response == UserResult.Yes; } - internal static async Task CreateUpdaterChoiceDialog(string title, string primary, string secondaryText) + internal static async Task CreateUpdaterChoiceDialog(string title, string primary, string secondaryText, string changelogUrl) { if (_isChoiceDialogOpen) { @@ -349,14 +440,16 @@ namespace Ryujinx.Ava.UI.Helpers _isChoiceDialogOpen = true; - UserResult response = await ShowTextDialog( + UserResult response = await ShowTextDialogWithButton( title, primary, secondaryText, LocaleManager.Instance[LocaleKeys.InputDialogYes], - LocaleManager.Instance[LocaleKeys.DialogUpdaterShowChangelogMessage], + string.Empty, LocaleManager.Instance[LocaleKeys.InputDialogNo], (int)Symbol.Help, + LocaleManager.Instance[LocaleKeys.DialogUpdaterShowChangelogMessage], + () => OpenHelper.OpenUrl(changelogUrl), UserResult.Yes); _isChoiceDialogOpen = false; diff --git a/src/Ryujinx/UI/Helpers/ControlExtensions.cs b/src/Ryujinx/UI/Helpers/ControlExtensions.cs new file mode 100644 index 000000000..734128757 --- /dev/null +++ b/src/Ryujinx/UI/Helpers/ControlExtensions.cs @@ -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); + } + } + } +} diff --git a/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs b/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs index fa08156af..0eeef45f5 100644 --- a/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs +++ b/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs @@ -27,82 +27,136 @@ namespace Ryujinx.Ava.UI.Models.Input public ControllerType ControllerType { get; set; } public PlayerIndex PlayerIndex { get; set; } - [ObservableProperty] private StickInputId _leftJoystick; - [ObservableProperty] private bool _leftInvertStickX; - [ObservableProperty] private bool _leftInvertStickY; - [ObservableProperty] private bool _leftRotate90; - [ObservableProperty] private GamepadInputId _leftStickButton; + [ObservableProperty] + public partial StickInputId LeftJoystick { get; set; } - [ObservableProperty] private StickInputId _rightJoystick; - [ObservableProperty] private bool _rightInvertStickX; - [ObservableProperty] private bool _rightInvertStickY; - [ObservableProperty] private bool _rightRotate90; - [ObservableProperty] private GamepadInputId _rightStickButton; + [ObservableProperty] + public partial bool LeftInvertStickX { get; set; } - [ObservableProperty] private GamepadInputId _dpadUp; - [ObservableProperty] private GamepadInputId _dpadDown; - [ObservableProperty] private GamepadInputId _dpadLeft; - [ObservableProperty] private GamepadInputId _dpadRight; + [ObservableProperty] + public partial bool LeftInvertStickY { get; set; } - [ObservableProperty] private GamepadInputId _buttonMinus; - [ObservableProperty] private GamepadInputId _buttonPlus; + [ObservableProperty] + public partial bool LeftRotate90 { get; set; } - [ObservableProperty] private GamepadInputId _buttonA; - [ObservableProperty] private GamepadInputId _buttonB; - [ObservableProperty] private GamepadInputId _buttonX; - [ObservableProperty] private GamepadInputId _buttonY; + [ObservableProperty] + public partial GamepadInputId LeftStickButton { get; set; } - [ObservableProperty] private GamepadInputId _buttonZl; - [ObservableProperty] private GamepadInputId _buttonZr; + [ObservableProperty] + public partial StickInputId RightJoystick { get; set; } - [ObservableProperty] private GamepadInputId _buttonL; - [ObservableProperty] private GamepadInputId _buttonR; + [ObservableProperty] + public partial bool RightInvertStickX { get; set; } - [ObservableProperty] private GamepadInputId _leftButtonSl; - [ObservableProperty] private GamepadInputId _leftButtonSr; + [ObservableProperty] + public partial bool RightInvertStickY { get; set; } - [ObservableProperty] private GamepadInputId _rightButtonSl; - [ObservableProperty] private GamepadInputId _rightButtonSr; + [ObservableProperty] + public partial bool RightRotate90 { get; set; } - [ObservableProperty] private float _deadzoneLeft; - [ObservableProperty] private float _deadzoneRight; + [ObservableProperty] + public partial GamepadInputId RightStickButton { get; set; } - [ObservableProperty] private float _rangeLeft; - [ObservableProperty] private float _rangeRight; + [ObservableProperty] + 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; - private bool _turnOffLed; - public bool TurnOffLed { - get => _turnOffLed; + get; set { - _turnOffLed = value; + field = value; OnPropertyChanged(); OnPropertyChanged(nameof(ShowLedColorPicker)); } } - private bool _useRainbowLed; - public bool UseRainbowLed { - get => _useRainbowLed; + get; set { - _useRainbowLed = value; + field = value; OnPropertyChanged(); OnPropertyChanged(nameof(ShowLedColorPicker)); } diff --git a/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs b/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs index 9e557d7b1..545af7876 100644 --- a/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs +++ b/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs @@ -6,31 +6,44 @@ namespace Ryujinx.Ava.UI.Models.Input { 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) { diff --git a/src/Ryujinx/UI/Models/Input/KeyboardInputConfig.cs b/src/Ryujinx/UI/Models/Input/KeyboardInputConfig.cs index c8169b6d5..de51d9d70 100644 --- a/src/Ryujinx/UI/Models/Input/KeyboardInputConfig.cs +++ b/src/Ryujinx/UI/Models/Input/KeyboardInputConfig.cs @@ -12,42 +12,89 @@ namespace Ryujinx.Ava.UI.Models.Input public ControllerType ControllerType { get; set; } public PlayerIndex PlayerIndex { get; set; } - [ObservableProperty] private Key _leftStickUp; - [ObservableProperty] private Key _leftStickDown; - [ObservableProperty] private Key _leftStickLeft; - [ObservableProperty] private Key _leftStickRight; - [ObservableProperty] private Key _leftStickButton; + [ObservableProperty] + public partial Key LeftStickUp { get; set; } - [ObservableProperty] private Key _rightStickUp; - [ObservableProperty] private Key _rightStickDown; - [ObservableProperty] private Key _rightStickLeft; - [ObservableProperty] private Key _rightStickRight; - [ObservableProperty] private Key _rightStickButton; + [ObservableProperty] + public partial Key LeftStickDown { get; set; } - [ObservableProperty] private Key _dpadUp; - [ObservableProperty] private Key _dpadDown; - [ObservableProperty] private Key _dpadLeft; - [ObservableProperty] private Key _dpadRight; + [ObservableProperty] + public partial Key LeftStickLeft { get; set; } - [ObservableProperty] private Key _buttonMinus; - [ObservableProperty] private Key _buttonPlus; + [ObservableProperty] + public partial Key LeftStickRight { get; set; } - [ObservableProperty] private Key _buttonA; - [ObservableProperty] private Key _buttonB; - [ObservableProperty] private Key _buttonX; - [ObservableProperty] private Key _buttonY; + [ObservableProperty] + public partial Key LeftStickButton { get; set; } - [ObservableProperty] private Key _buttonL; - [ObservableProperty] private Key _buttonR; + [ObservableProperty] + public partial Key RightStickUp { get; set; } - [ObservableProperty] private Key _buttonZl; - [ObservableProperty] private Key _buttonZr; + [ObservableProperty] + public partial Key RightStickDown { get; set; } - [ObservableProperty] private Key _leftButtonSl; - [ObservableProperty] private Key _leftButtonSr; + [ObservableProperty] + public partial Key RightStickLeft { get; set; } - [ObservableProperty] private Key _rightButtonSl; - [ObservableProperty] private Key _rightButtonSr; + [ObservableProperty] + 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) { diff --git a/src/Ryujinx/UI/Models/ModModel.cs b/src/Ryujinx/UI/Models/ModModel.cs index 91804d365..307674d81 100644 --- a/src/Ryujinx/UI/Models/ModModel.cs +++ b/src/Ryujinx/UI/Models/ModModel.cs @@ -6,8 +6,8 @@ namespace Ryujinx.Ava.UI.Models { public partial class ModModel : BaseModel { - [ObservableProperty] private bool _enabled; - + [ObservableProperty] + public partial bool Enabled { get; set; } public bool InSd { get; } public string Path { get; } public string Name { get; } diff --git a/src/Ryujinx/UI/Models/ProfileImageModel.cs b/src/Ryujinx/UI/Models/ProfileImageModel.cs index f12aa7bd4..ef313d225 100644 --- a/src/Ryujinx/UI/Models/ProfileImageModel.cs +++ b/src/Ryujinx/UI/Models/ProfileImageModel.cs @@ -15,6 +15,7 @@ namespace Ryujinx.Ava.UI.Models public string Name { get; set; } public byte[] Data { get; set; } - [ObservableProperty] private SolidColorBrush _backgroundColor = new(Colors.White); + [ObservableProperty] + public partial SolidColorBrush BackgroundColor { get; set; } = new(Colors.White); } } diff --git a/src/Ryujinx/UI/Models/TempProfile.cs b/src/Ryujinx/UI/Models/TempProfile.cs index 51e86fb7f..a4a4fe32f 100644 --- a/src/Ryujinx/UI/Models/TempProfile.cs +++ b/src/Ryujinx/UI/Models/TempProfile.cs @@ -7,24 +7,26 @@ namespace Ryujinx.Ava.UI.Models { public partial class TempProfile : BaseModel { - [ObservableProperty] private byte[] _image; - [ObservableProperty] private string _name = String.Empty; - private UserId _userId; + [ObservableProperty] + public partial byte[] Image { get; set; } + + [ObservableProperty] + public partial string Name { get; set; } = string.Empty; public static uint MaxProfileNameLength => 0x20; public UserId UserId { - get => _userId; + get; set { - _userId = value; + field = value; OnPropertyChanged(); OnPropertyChanged(nameof(UserIdString)); } } - public string UserIdString => _userId.ToString(); + public string UserIdString => UserId.ToString(); public TempProfile(UserProfile profile) { diff --git a/src/Ryujinx/UI/Models/UserProfile.cs b/src/Ryujinx/UI/Models/UserProfile.cs index f14e74d07..9ebecf8d4 100644 --- a/src/Ryujinx/UI/Models/UserProfile.cs +++ b/src/Ryujinx/UI/Models/UserProfile.cs @@ -13,11 +13,20 @@ namespace Ryujinx.Ava.UI.Models { private readonly Profile _profile; private readonly NavigationDialogHost _owner; - [ObservableProperty] private byte[] _image; - [ObservableProperty] private string _name; - [ObservableProperty] private UserId _userId; - [ObservableProperty] private bool _isPointerOver; - [ObservableProperty] private IBrush _backgroundColor; + [ObservableProperty] + public partial byte[] Image { get; set; } + + [ObservableProperty] + 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) { @@ -39,7 +48,7 @@ namespace Ryujinx.Ava.UI.Models private void UpdateBackground() { - Application currentApplication = Avalonia.Application.Current; + Application currentApplication = Application.Current; currentApplication.Styles.TryGetResource("ControlFillColorSecondary", currentApplication.ActualThemeVariant, out object color); if (color is not null) diff --git a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs index 894f06969..233c30bad 100644 --- a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs @@ -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 TimeSpan CurrentTime { get; set; }