Ava UI: Better Controller Applet (#5756)

* Start work on better Controller Applet

* Don’t require title

* UI improvements

* Border around TBD area

* Formatting

* Better SVGs

* Add missing margin

* Use Locale

* Rename function

* Make buttons ourselves

* Make the buttons do shit

* Formatting

* Adjust SVGs

* Fix Open Settings Window

* Make field readonly

* Final tweaks

* Update src/Ryujinx.Ava/UI/Applet/AvaHostUiHandler.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Update src/Ryujinx.Ava/UI/Applet/ControllerAppletDialog.axaml.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Apply suggestions from code review

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Update src/Ryujinx.Ava/UI/Applet/ControllerAppletDialog.axaml.cs

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>

* Move icons to Ava project

* Reorder arguments

* Try to focus Settings Window

* Fix icons

Project shenangians

* Add ContentDialogHelper.ShowWindowAsync method

* Fix closed SettingsWindow reference in MainWindow

* Fix SettingsWindow dialog

* Suggestion

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
This commit is contained in:
Isaac Marovitz
2024-01-13 00:41:57 +00:00
committed by GitHub
parent 59a0c7cfd8
commit f037fcba9a
11 changed files with 1108 additions and 24 deletions

View File

@@ -29,14 +29,24 @@ namespace Ryujinx.Ava.UI.Applet
public bool DisplayMessageDialog(ControllerAppletUiArgs args)
{
string message = LocaleManager.Instance.UpdateAndGetDynamicValue(
args.PlayerCountMin == args.PlayerCountMax ? LocaleKeys.DialogControllerAppletMessage : LocaleKeys.DialogControllerAppletMessagePlayerRange,
args.PlayerCountMin == args.PlayerCountMax ? args.PlayerCountMin.ToString() : $"{args.PlayerCountMin}-{args.PlayerCountMax}",
args.SupportedStyles,
string.Join(", ", args.SupportedPlayers),
args.IsDocked ? LocaleManager.Instance[LocaleKeys.DialogControllerAppletDockModeSet] : "");
ManualResetEvent dialogCloseEvent = new(false);
return DisplayMessageDialog(LocaleManager.Instance[LocaleKeys.DialogControllerAppletTitle], message);
bool okPressed = false;
Dispatcher.UIThread.InvokeAsync(async () =>
{
var response = await ControllerAppletDialog.ShowControllerAppletDialog(_parent, args);
if (response == UserResult.Ok)
{
okPressed = true;
}
dialogCloseEvent.Set();
});
dialogCloseEvent.WaitOne();
return okPressed;
}
public bool DisplayMessageDialog(string title, string message)
@@ -75,6 +85,8 @@ namespace Ryujinx.Ava.UI.Applet
await _parent.SettingsWindow.ShowDialog(window);
_parent.SettingsWindow = null;
opened = false;
});

View File

@@ -0,0 +1,145 @@
<UserControl
x:Class="Ryujinx.Ava.UI.Applet.ControllerAppletDialog"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:applet="using:Ryujinx.Ava.UI.Applet"
mc:Ignorable="d"
Width="400"
Focusable="True"
x:DataType="applet:ControllerAppletDialog">
<Grid
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Border
Grid.Column="0"
Grid.Row="0"
Grid.ColumnSpan="2"
Margin="0 0 0 10"
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
CornerRadius="5">
<StackPanel
Spacing="10"
Margin="10">
<TextBlock
Text="{locale:Locale ControllerAppletDescription}" />
<TextBlock
IsVisible="{Binding IsDocked}"
FontWeight="Bold"
Text="{locale:Locale ControllerAppletDocked}" />
</StackPanel>
</Border>
<Border
Grid.Column="0"
Grid.Row="1"
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
CornerRadius="5"
Margin="0 0 10 0">
<StackPanel
Margin="10"
Spacing="10"
Orientation="Vertical">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
TextAlignment="Center"
FontWeight="Bold"
Text="{locale:Locale ControllerAppletControllers}" />
<StackPanel
Spacing="10"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Orientation="Horizontal">
<Image
Height="50"
Width="50"
Stretch="Uniform"
Source="{Binding ProControllerImage}"
IsVisible="{Binding SupportsProController}" />
<Image
Height="50"
Width="50"
Stretch="Uniform"
Source="{Binding JoyconPairImage}"
IsVisible="{Binding SupportsJoyconPair}" />
<Image
Height="50"
Width="50"
Stretch="Uniform"
Source="{Binding JoyconLeftImage}"
IsVisible="{Binding SupportsLeftJoycon}" />
<Image
Height="50"
Width="50"
Stretch="Uniform"
Source="{Binding JoyconRightImage}"
IsVisible="{Binding SupportsRightJoycon}" />
</StackPanel>
</StackPanel>
</Border>
<Border
Grid.Column="1"
Grid.Row="1"
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
CornerRadius="5">
<StackPanel
Margin="10"
Spacing="10"
Orientation="Vertical">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
TextAlignment="Center"
FontWeight="Bold"
Text="{locale:Locale ControllerAppletPlayers}" />
<Border Height="50">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
TextAlignment="Center"
FontSize="40"
FontWeight="Thin"
Text="{Binding PlayerCount}" />
</Border>
</StackPanel>
</Border>
<Panel
Margin="0 24 0 0"
Grid.Column="0"
Grid.Row="2"
Grid.ColumnSpan="2">
<StackPanel
Orientation="Horizontal"
Spacing="10"
HorizontalAlignment="Right">
<Button
Name="SaveButton"
MinWidth="90"
Command="{Binding OpenSettingsWindow}">
<TextBlock Text="{locale:Locale DialogOpenSettingsWindowLabel}" />
</Button>
<Button
Name="CancelButton"
MinWidth="90"
Command="{Binding Close}">
<TextBlock Text="{locale:Locale SettingsButtonClose}" />
</Button>
</StackPanel>
</Panel>
</Grid>
</UserControl>

View File

@@ -0,0 +1,139 @@
using Avalonia.Controls;
using Avalonia.Styling;
using Avalonia.Svg.Skia;
using Avalonia.Threading;
using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Windows;
using Ryujinx.Common;
using Ryujinx.HLE.HOS.Applets;
using Ryujinx.HLE.HOS.Services.Hid;
using System.Linq;
using System.Threading.Tasks;
namespace Ryujinx.Ava.UI.Applet
{
internal partial class ControllerAppletDialog : UserControl
{
private const string ProControllerResource = "Ryujinx.Ava/Assets/Icons/Controller_ProCon.svg";
private const string JoyConPairResource = "Ryujinx.Ava/Assets/Icons/Controller_JoyConPair.svg";
private const string JoyConLeftResource = "Ryujinx.Ava/Assets/Icons/Controller_JoyConLeft.svg";
private const string JoyConRightResource = "Ryujinx.Ava/Assets/Icons/Controller_JoyConRight.svg";
public static SvgImage ProControllerImage => GetResource(ProControllerResource);
public static SvgImage JoyconPairImage => GetResource(JoyConPairResource);
public static SvgImage JoyconLeftImage => GetResource(JoyConLeftResource);
public static SvgImage JoyconRightImage => GetResource(JoyConRightResource);
public string PlayerCount { get; set; } = "";
public bool SupportsProController { get; set; }
public bool SupportsLeftJoycon { get; set; }
public bool SupportsRightJoycon { get; set; }
public bool SupportsJoyconPair { get; set; }
public bool IsDocked { get; set; }
private readonly MainWindow _mainWindow;
public ControllerAppletDialog(MainWindow mainWindow, ControllerAppletUiArgs args)
{
if (args.PlayerCountMin == args.PlayerCountMax)
{
PlayerCount = args.PlayerCountMin.ToString();
}
else
{
PlayerCount = $"{args.PlayerCountMin} - {args.PlayerCountMax}";
}
SupportsProController = (args.SupportedStyles & ControllerType.ProController) != 0;
SupportsLeftJoycon = (args.SupportedStyles & ControllerType.JoyconLeft) != 0;
SupportsRightJoycon = (args.SupportedStyles & ControllerType.JoyconRight) != 0;
SupportsJoyconPair = (args.SupportedStyles & ControllerType.JoyconPair) != 0;
IsDocked = args.IsDocked;
_mainWindow = mainWindow;
DataContext = this;
InitializeComponent();
}
public ControllerAppletDialog(MainWindow mainWindow)
{
_mainWindow = mainWindow;
DataContext = this;
InitializeComponent();
}
public static async Task<UserResult> ShowControllerAppletDialog(MainWindow window, ControllerAppletUiArgs args)
{
ContentDialog contentDialog = new();
UserResult result = UserResult.Cancel;
ControllerAppletDialog content = new(window, args);
contentDialog.Title = LocaleManager.Instance[LocaleKeys.DialogControllerAppletTitle];
contentDialog.Content = content;
void Handler(ContentDialog sender, ContentDialogClosedEventArgs eventArgs)
{
if (eventArgs.Result == ContentDialogResult.Primary)
{
result = UserResult.Ok;
}
}
contentDialog.Closed += Handler;
Style bottomBorder = new(x => x.OfType<Grid>().Name("DialogSpace").Child().OfType<Border>());
bottomBorder.Setters.Add(new Setter(IsVisibleProperty, false));
contentDialog.Styles.Add(bottomBorder);
await ContentDialogHelper.ShowAsync(contentDialog);
return result;
}
private static SvgImage GetResource(string path)
{
SvgImage image = new();
if (!string.IsNullOrWhiteSpace(path))
{
SvgSource source = new();
source.Load(EmbeddedResources.GetStream(path));
image.Source = source;
}
return image;
}
public void OpenSettingsWindow()
{
if (_mainWindow.SettingsWindow == null)
{
Dispatcher.UIThread.InvokeAsync(async () =>
{
_mainWindow.SettingsWindow = new SettingsWindow(_mainWindow.VirtualFileSystem, _mainWindow.ContentManager);
_mainWindow.SettingsWindow.NavPanel.Content = _mainWindow.SettingsWindow.InputPage;
_mainWindow.SettingsWindow.NavPanel.SelectedItem = _mainWindow.SettingsWindow.NavPanel.MenuItems.ElementAt(1);
await ContentDialogHelper.ShowWindowAsync(_mainWindow.SettingsWindow, _mainWindow);
_mainWindow.SettingsWindow = null;
this.Close();
});
}
}
public void Close()
{
((ContentDialog)Parent)?.Hide();
}
}
}