aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Ava/UI/Views/Main
diff options
context:
space:
mode:
authorTSR Berry <20988865+TSRBerry@users.noreply.github.com>2023-04-08 01:22:00 +0200
committerMary <thog@protonmail.com>2023-04-27 23:51:14 +0200
commitcee712105850ac3385cd0091a923438167433f9f (patch)
tree4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /src/Ryujinx.Ava/UI/Views/Main
parentcd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff)
Move solution and projects to src
Diffstat (limited to 'src/Ryujinx.Ava/UI/Views/Main')
-rw-r--r--src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml164
-rw-r--r--src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs236
-rw-r--r--src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml232
-rw-r--r--src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml.cs52
-rw-r--r--src/Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml175
-rw-r--r--src/Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml.cs54
6 files changed, 913 insertions, 0 deletions
diff --git a/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml b/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml
new file mode 100644
index 00000000..d5b5efcd
--- /dev/null
+++ b/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml
@@ -0,0 +1,164 @@
+<UserControl
+ xmlns="https://github.com/avaloniaui"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
+ mc:Ignorable="d"
+ xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
+ x:DataType="viewModels:MainWindowViewModel"
+ x:Class="Ryujinx.Ava.UI.Views.Main.MainMenuBarView"
+ x:CompileBindings="True">
+ <Design.DataContext>
+ <viewModels:MainWindowViewModel />
+ </Design.DataContext>
+ <DockPanel HorizontalAlignment="Stretch">
+ <Menu
+ Name="Menu"
+ Height="35"
+ Margin="0"
+ HorizontalAlignment="Left">
+ <Menu.ItemsPanel>
+ <ItemsPanelTemplate>
+ <DockPanel Margin="0" HorizontalAlignment="Stretch" />
+ </ItemsPanelTemplate>
+ </Menu.ItemsPanel>
+ <MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarFile}">
+ <MenuItem
+ Command="{ReflectionBinding OpenFile}"
+ Header="{locale:Locale MenuBarFileOpenFromFile}"
+ IsEnabled="{Binding EnableNonGameRunningControls}"
+ ToolTip.Tip="{locale:Locale LoadApplicationFileTooltip}" />
+ <MenuItem
+ Command="{ReflectionBinding OpenFolder}"
+ Header="{locale:Locale MenuBarFileOpenUnpacked}"
+ IsEnabled="{Binding EnableNonGameRunningControls}"
+ ToolTip.Tip="{locale:Locale LoadApplicationFolderTooltip}" />
+ <MenuItem Header="{locale:Locale MenuBarFileOpenApplet}" IsEnabled="{Binding IsAppletMenuActive}">
+ <MenuItem
+ Click="OpenMiiApplet"
+ Header="Mii Edit Applet"
+ ToolTip.Tip="{locale:Locale MenuBarFileOpenAppletOpenMiiAppletToolTip}" />
+ </MenuItem>
+ <Separator />
+ <MenuItem
+ Command="{ReflectionBinding OpenRyujinxFolder}"
+ Header="{locale:Locale MenuBarFileOpenEmuFolder}"
+ ToolTip.Tip="{locale:Locale OpenRyujinxFolderTooltip}" />
+ <MenuItem
+ Command="{ReflectionBinding OpenLogsFolder}"
+ Header="{locale:Locale MenuBarFileOpenLogsFolder}"
+ ToolTip.Tip="{locale:Locale OpenRyujinxLogsTooltip}" />
+ <Separator />
+ <MenuItem
+ Click="CloseWindow"
+ Header="{locale:Locale MenuBarFileExit}"
+ ToolTip.Tip="{locale:Locale ExitTooltip}" />
+ </MenuItem>
+ <MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarOptions}">
+ <MenuItem
+ Command="{ReflectionBinding ToggleFullscreen}"
+ Header="{locale:Locale MenuBarOptionsToggleFullscreen}"
+ InputGesture="F11" />
+ <MenuItem>
+ <MenuItem.Icon>
+ <CheckBox IsChecked="{Binding StartGamesInFullscreen, Mode=TwoWay}"
+ MinWidth="250">
+ <TextBlock Text="{locale:Locale MenuBarOptionsStartGamesInFullscreen}"/>
+ </CheckBox>
+ </MenuItem.Icon>
+ </MenuItem>
+ <MenuItem IsVisible="{Binding ShowConsoleVisible}">
+ <MenuItem.Icon>
+ <CheckBox IsChecked="{Binding ShowConsole, Mode=TwoWay}"
+ MinWidth="250">
+ <TextBlock Text="{locale:Locale MenuBarOptionsShowConsole}"/>
+ </CheckBox>
+ </MenuItem.Icon>
+ </MenuItem>
+ <Separator />
+ <MenuItem Name="ChangeLanguageMenuItem" Header="{locale:Locale MenuBarOptionsChangeLanguage}" />
+ <MenuItem Name="ToggleFileTypesMenuItem" Header="{locale:Locale MenuBarShowFileTypes}" />
+ <Separator />
+ <MenuItem
+ Click="OpenSettings"
+ Header="{locale:Locale MenuBarOptionsSettings}"
+ ToolTip.Tip="{locale:Locale OpenSettingsTooltip}" />
+ <MenuItem
+ Command="{ReflectionBinding ManageProfiles}"
+ Header="{locale:Locale MenuBarOptionsManageUserProfiles}"
+ IsEnabled="{Binding EnableNonGameRunningControls}"
+ ToolTip.Tip="{locale:Locale OpenProfileManagerTooltip}" />
+ </MenuItem>
+ <MenuItem
+ Name="ActionsMenuItem"
+ VerticalAlignment="Center"
+ Header="{locale:Locale MenuBarActions}"
+ IsEnabled="{Binding IsGameRunning}">
+ <MenuItem
+ Click="PauseEmulation_Click"
+ Header="{locale:Locale MenuBarOptionsPauseEmulation}"
+ InputGesture="{Binding PauseKey}"
+ IsEnabled="{Binding !IsPaused}"
+ IsVisible="{Binding !IsPaused}" />
+ <MenuItem
+ Click="ResumeEmulation_Click"
+ Header="{locale:Locale MenuBarOptionsResumeEmulation}"
+ InputGesture="{Binding PauseKey}"
+ IsEnabled="{Binding IsPaused}"
+ IsVisible="{Binding IsPaused}" />
+ <MenuItem
+ Click="StopEmulation_Click"
+ Header="{locale:Locale MenuBarOptionsStopEmulation}"
+ InputGesture="Escape"
+ IsEnabled="{Binding IsGameRunning}"
+ ToolTip.Tip="{locale:Locale StopEmulationTooltip}" />
+ <MenuItem Command="{ReflectionBinding SimulateWakeUpMessage}" Header="{locale:Locale MenuBarOptionsSimulateWakeUpMessage}" />
+ <Separator />
+ <MenuItem
+ Name="ScanAmiiboMenuItem"
+ AttachedToVisualTree="ScanAmiiboMenuItem_AttachedToVisualTree"
+ Click="OpenAmiiboWindow"
+ Header="{locale:Locale MenuBarActionsScanAmiibo}"
+ IsEnabled="{Binding IsAmiiboRequested}" />
+ <MenuItem
+ Command="{ReflectionBinding TakeScreenshot}"
+ Header="{locale:Locale MenuBarFileToolsTakeScreenshot}"
+ InputGesture="{Binding ScreenshotKey}"
+ IsEnabled="{Binding IsGameRunning}" />
+ <MenuItem
+ Command="{ReflectionBinding HideUi}"
+ Header="{locale:Locale MenuBarFileToolsHideUi}"
+ InputGesture="{Binding ShowUiKey}"
+ IsEnabled="{Binding IsGameRunning}" />
+ <MenuItem
+ Click="OpenCheatManagerForCurrentApp"
+ Header="{locale:Locale GameListContextMenuManageCheat}"
+ IsEnabled="{Binding IsGameRunning}" />
+ </MenuItem>
+ <MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarTools}">
+ <MenuItem Header="{locale:Locale MenuBarToolsInstallFirmware}" IsEnabled="{Binding EnableNonGameRunningControls}">
+ <MenuItem Command="{ReflectionBinding InstallFirmwareFromFile}" Header="{locale:Locale MenuBarFileToolsInstallFirmwareFromFile}" />
+ <MenuItem Command="{ReflectionBinding InstallFirmwareFromFolder}" Header="{locale:Locale MenuBarFileToolsInstallFirmwareFromDirectory}" />
+ </MenuItem>
+ <MenuItem Header="{locale:Locale MenuBarToolsManageFileTypes}" IsVisible="{Binding ManageFileTypesVisible}">
+ <MenuItem Header="{locale:Locale MenuBarToolsInstallFileTypes}" Click="InstallFileTypes_Click"/>
+ <MenuItem Header="{locale:Locale MenuBarToolsUninstallFileTypes}" Click="UninstallFileTypes_Click"/>
+ </MenuItem>
+ </MenuItem>
+ <MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarHelp}">
+ <MenuItem
+ Name="UpdateMenuItem"
+ IsEnabled="{Binding CanUpdate}"
+ Click="CheckForUpdates"
+ Header="{locale:Locale MenuBarHelpCheckForUpdates}"
+ ToolTip.Tip="{locale:Locale CheckUpdatesTooltip}" />
+ <Separator />
+ <MenuItem
+ Click="OpenAboutWindow"
+ Header="{locale:Locale MenuBarHelpAbout}"
+ ToolTip.Tip="{locale:Locale OpenAboutTooltip}" />
+ </MenuItem>
+ </Menu>
+ </DockPanel>
+</UserControl>
diff --git a/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs
new file mode 100644
index 00000000..bdf2cf9f
--- /dev/null
+++ b/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs
@@ -0,0 +1,236 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+using LibHac.Ncm;
+using LibHac.Tools.FsSystem.NcaUtils;
+using Ryujinx.Ava.Common.Locale;
+using Ryujinx.Ava.UI.Helpers;
+using Ryujinx.Ava.UI.ViewModels;
+using Ryujinx.Ava.UI.Windows;
+using Ryujinx.Common;
+using Ryujinx.Common.Utilities;
+using Ryujinx.HLE.HOS;
+using Ryujinx.Modules;
+using Ryujinx.Ui.Common;
+using Ryujinx.Ui.Common.Configuration;
+using Ryujinx.Ui.Common.Helper;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Ryujinx.Ava.UI.Views.Main
+{
+ public partial class MainMenuBarView : UserControl
+ {
+ public MainWindow Window { get; private set; }
+ public MainWindowViewModel ViewModel { get; private set; }
+
+ public MainMenuBarView()
+ {
+ InitializeComponent();
+
+ ToggleFileTypesMenuItem.Items = GenerateToggleFileTypeItems();
+ ChangeLanguageMenuItem.Items = GenerateLanguageMenuItems();
+ }
+
+ private CheckBox[] GenerateToggleFileTypeItems()
+ {
+ List<CheckBox> checkBoxes = new();
+
+ foreach (var item in Enum.GetValues(typeof (FileTypes)))
+ {
+ string fileName = Enum.GetName(typeof (FileTypes), item);
+ checkBoxes.Add(new CheckBox()
+ {
+ Content = $".{fileName}",
+ IsChecked = ((FileTypes)item).GetConfigValue(ConfigurationState.Instance.Ui.ShownFileTypes),
+ Command = MiniCommand.Create(() => ViewModel.ToggleFileType(fileName))
+ });
+ }
+
+ return checkBoxes.ToArray();
+ }
+
+ private MenuItem[] GenerateLanguageMenuItems()
+ {
+ List<MenuItem> menuItems = new();
+
+ string localePath = "Ryujinx.Ava/Assets/Locales";
+ string localeExt = ".json";
+
+ string[] localesPath = EmbeddedResources.GetAllAvailableResources(localePath, localeExt);
+
+ Array.Sort(localesPath);
+
+ foreach (string locale in localesPath)
+ {
+ string languageCode = Path.GetFileNameWithoutExtension(locale).Split('.').Last();
+ string languageJson = EmbeddedResources.ReadAllText($"{localePath}/{languageCode}{localeExt}");
+ var strings = JsonHelper.Deserialize(languageJson, CommonJsonContext.Default.StringDictionary);
+
+ if (!strings.TryGetValue("Language", out string languageName))
+ {
+ languageName = languageCode;
+ }
+
+ MenuItem menuItem = new()
+ {
+ Header = languageName,
+ Command = MiniCommand.Create(() =>
+ {
+ ViewModel.ChangeLanguage(languageCode);
+ })
+ };
+
+ menuItems.Add(menuItem);
+ }
+
+ return menuItems.ToArray();
+ }
+
+ protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
+ {
+ base.OnAttachedToVisualTree(e);
+
+ if (VisualRoot is MainWindow window)
+ {
+ Window = window;
+ }
+
+ ViewModel = Window.ViewModel;
+ DataContext = ViewModel;
+ }
+
+ private async void StopEmulation_Click(object sender, RoutedEventArgs e)
+ {
+ await Window.ViewModel.AppHost?.ShowExitPrompt();
+ }
+
+ private async void PauseEmulation_Click(object sender, RoutedEventArgs e)
+ {
+ await Task.Run(() =>
+ {
+ Window.ViewModel.AppHost?.Pause();
+ });
+ }
+
+ private async void ResumeEmulation_Click(object sender, RoutedEventArgs e)
+ {
+ await Task.Run(() =>
+ {
+ Window.ViewModel.AppHost?.Resume();
+ });
+ }
+
+ public async void OpenSettings(object sender, RoutedEventArgs e)
+ {
+ Window.SettingsWindow = new(Window.VirtualFileSystem, Window.ContentManager);
+
+ await Window.SettingsWindow.ShowDialog(Window);
+
+ ViewModel.LoadConfigurableHotKeys();
+ }
+
+ public void OpenMiiApplet(object sender, RoutedEventArgs e)
+ {
+ string contentPath = ViewModel.ContentManager.GetInstalledContentPath(0x0100000000001009, StorageId.BuiltInSystem, NcaContentType.Program);
+
+ if (!string.IsNullOrEmpty(contentPath))
+ {
+ ViewModel.LoadApplication(contentPath, false, "Mii Applet");
+ }
+ }
+
+ public async void OpenAmiiboWindow(object sender, RoutedEventArgs e)
+ {
+ if (!ViewModel.IsAmiiboRequested)
+ {
+ return;
+ }
+
+ if (ViewModel.AppHost.Device.System.SearchingForAmiibo(out int deviceId))
+ {
+ string titleId = ViewModel.AppHost.Device.Processes.ActiveApplication.ProgramIdText.ToUpper();
+ AmiiboWindow window = new(ViewModel.ShowAll, ViewModel.LastScannedAmiiboId, titleId);
+
+ await window.ShowDialog(Window);
+
+ if (window.IsScanned)
+ {
+ ViewModel.ShowAll = window.ViewModel.ShowAllAmiibo;
+ ViewModel.LastScannedAmiiboId = window.ScannedAmiibo.GetId();
+
+ ViewModel.AppHost.Device.System.ScanAmiibo(deviceId, ViewModel.LastScannedAmiiboId, window.ViewModel.UseRandomUuid);
+ }
+ }
+ }
+
+ public async void OpenCheatManagerForCurrentApp(object sender, RoutedEventArgs e)
+ {
+ if (!ViewModel.IsGameRunning)
+ {
+ return;
+ }
+
+ string name = ViewModel.AppHost.Device.Processes.ActiveApplication.ApplicationControlProperties.Title[(int)ViewModel.AppHost.Device.System.State.DesiredTitleLanguage].NameString.ToString();
+
+ await new CheatWindow(Window.VirtualFileSystem, ViewModel.AppHost.Device.Processes.ActiveApplication.ProgramIdText, name).ShowDialog(Window);
+
+ ViewModel.AppHost.Device.EnableCheats();
+ }
+
+ private void ScanAmiiboMenuItem_AttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e)
+ {
+ if (sender is MenuItem)
+ {
+ ViewModel.IsAmiiboRequested = Window.ViewModel.AppHost.Device.System.SearchingForAmiibo(out _);
+ }
+ }
+
+ private async void InstallFileTypes_Click(object sender, RoutedEventArgs e)
+ {
+ if (FileAssociationHelper.Install())
+ {
+ await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogInstallFileTypesSuccessMessage],
+ string.Empty, LocaleManager.Instance[LocaleKeys.InputDialogOk], string.Empty, string.Empty);
+ }
+ else
+ {
+ await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogInstallFileTypesErrorMessage]);
+ }
+ }
+
+ private async void UninstallFileTypes_Click(object sender, RoutedEventArgs e)
+ {
+ if (FileAssociationHelper.Uninstall())
+ {
+ await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogUninstallFileTypesSuccessMessage],
+ string.Empty, LocaleManager.Instance[LocaleKeys.InputDialogOk], string.Empty, string.Empty);
+ }
+ else
+ {
+ await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUninstallFileTypesErrorMessage]);
+ }
+ }
+
+ public async void CheckForUpdates(object sender, RoutedEventArgs e)
+ {
+ if (Updater.CanUpdate(true))
+ {
+ await Updater.BeginParse(Window, true);
+ }
+ }
+
+ public async void OpenAboutWindow(object sender, RoutedEventArgs e)
+ {
+ await AboutWindow.Show();
+ }
+
+ public void CloseWindow(object sender, RoutedEventArgs e)
+ {
+ Window.Close();
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml b/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml
new file mode 100644
index 00000000..16705695
--- /dev/null
+++ b/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml
@@ -0,0 +1,232 @@
+<UserControl
+ xmlns="https://github.com/avaloniaui"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
+ xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
+ xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
+ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+ x:Class="Ryujinx.Ava.UI.Views.Main.MainStatusBarView"
+ x:CompileBindings="True"
+ x:DataType="viewModels:MainWindowViewModel">
+ <Design.DataContext>
+ <viewModels:MainWindowViewModel />
+ </Design.DataContext>
+ <Grid
+ Name="StatusBar"
+ Margin="0"
+ MinHeight="22"
+ HorizontalAlignment="Stretch"
+ VerticalAlignment="Bottom"
+ Background="{DynamicResource ThemeContentBackgroundColor}"
+ DockPanel.Dock="Bottom"
+ IsVisible="{Binding ShowMenuAndStatusBar}">
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="Auto" />
+ <ColumnDefinition Width="Auto" />
+ <ColumnDefinition Width="*" />
+ <ColumnDefinition Width="Auto" />
+ </Grid.ColumnDefinitions>
+ <StackPanel
+ Grid.Column="0"
+ Margin="5"
+ VerticalAlignment="Center"
+ IsVisible="{Binding EnableNonGameRunningControls}">
+ <Grid Margin="0">
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="Auto" />
+ <ColumnDefinition Width="Auto" />
+ <ColumnDefinition />
+ </Grid.ColumnDefinitions>
+ <Button
+ Width="25"
+ Height="25"
+ MinWidth="0"
+ Margin="0,0,5,0"
+ VerticalAlignment="Center"
+ Background="Transparent"
+ Command="{ReflectionBinding LoadApplications}">
+ <ui:SymbolIcon
+ Width="50"
+ Height="100"
+ Symbol="Refresh" />
+ </Button>
+ <TextBlock
+ Name="LoadStatus"
+ Grid.Column="1"
+ Margin="0,0,5,0"
+ VerticalAlignment="Center"
+ IsVisible="{Binding EnableNonGameRunningControls}"
+ Text="{locale:Locale StatusBarGamesLoaded}" />
+ <ProgressBar
+ Name="LoadProgressBar"
+ Grid.Column="2"
+ Height="6"
+ VerticalAlignment="Center"
+ Foreground="{DynamicResource HighlightColor}"
+ IsVisible="{Binding StatusBarVisible}"
+ Maximum="{Binding StatusBarProgressMaximum}"
+ Value="{Binding StatusBarProgressValue}" />
+ </Grid>
+ </StackPanel>
+ <StackPanel
+ Grid.Column="1"
+ Margin="0,2"
+ HorizontalAlignment="Left"
+ VerticalAlignment="Center"
+ IsVisible="{Binding IsGameRunning}"
+ MaxHeight="18"
+ Orientation="Horizontal">
+ <TextBlock
+ Name="VsyncStatus"
+ Margin="5,0,5,0"
+ HorizontalAlignment="Left"
+ VerticalAlignment="Center"
+ Foreground="{Binding VsyncColor}"
+ IsVisible="{Binding !ShowLoadProgress}"
+ PointerReleased="VsyncStatus_PointerReleased"
+ Text="VSync"
+ TextAlignment="Left" />
+ <Border
+ Width="2"
+ Height="12"
+ Margin="0"
+ BorderBrush="Gray"
+ BorderThickness="1"
+ IsVisible="{Binding !ShowLoadProgress}" />
+ <TextBlock
+ Name="DockedStatus"
+ Margin="5,0,5,0"
+ HorizontalAlignment="Left"
+ VerticalAlignment="Center"
+ IsVisible="{Binding !ShowLoadProgress}"
+ PointerReleased="DockedStatus_PointerReleased"
+ Text="{Binding DockedStatusText}"
+ TextAlignment="Left" />
+ <Border
+ Width="2"
+ Height="12"
+ Margin="0"
+ BorderBrush="Gray"
+ BorderThickness="1"
+ IsVisible="{Binding !ShowLoadProgress}" />
+ <TextBlock
+ Name="AspectRatioStatus"
+ Margin="5,0,5,0"
+ HorizontalAlignment="Left"
+ VerticalAlignment="Center"
+ IsVisible="{Binding !ShowLoadProgress}"
+ PointerReleased="AspectRatioStatus_PointerReleased"
+ Text="{Binding AspectRatioStatusText}"
+ TextAlignment="Left" />
+ <Border
+ Width="2"
+ Height="12"
+ Margin="0"
+ BorderBrush="Gray"
+ BorderThickness="1"
+ IsVisible="{Binding !ShowLoadProgress}" />
+ <ui:ToggleSplitButton
+ Name="VolumeStatus"
+ Padding="5,0,5,0"
+ HorizontalAlignment="Left"
+ VerticalAlignment="Center"
+ VerticalContentAlignment="Center"
+ Background="{DynamicResource ThemeContentBackgroundColor}"
+ BorderThickness="0"
+ Content="{Binding VolumeStatusText}"
+ IsChecked="{Binding VolumeMuted}"
+ IsVisible="{Binding !ShowLoadProgress}">
+ <ui:ToggleSplitButton.Flyout>
+ <Flyout Placement="Bottom" ShowMode="TransientWithDismissOnPointerMoveAway">
+ <Grid Margin="0">
+ <Slider
+ MaxHeight="40"
+ Width="150"
+ Margin="0"
+ Padding="0"
+ IsSnapToTickEnabled="True"
+ LargeChange="0.05"
+ Maximum="1"
+ Minimum="0"
+ SmallChange="0.01"
+ TickFrequency="0.05"
+ ToolTip.Tip="{locale:Locale AudioVolumeTooltip}"
+ Value="{Binding Volume}" />
+ </Grid>
+ </Flyout>
+ </ui:ToggleSplitButton.Flyout>
+ </ui:ToggleSplitButton>
+ <Border
+ Width="2"
+ Height="12"
+ Margin="0"
+ BorderBrush="Gray"
+ BorderThickness="1"
+ IsVisible="{Binding !ShowLoadProgress}" />
+ <TextBlock
+ Margin="5,0,5,0"
+ HorizontalAlignment="Left"
+ VerticalAlignment="Center"
+ IsVisible="{Binding !ShowLoadProgress}"
+ Text="{Binding GameStatusText}"
+ TextAlignment="Left" />
+ <Border
+ Width="2"
+ Height="12"
+ Margin="0"
+ BorderBrush="Gray"
+ BorderThickness="1"
+ IsVisible="{Binding !ShowLoadProgress}" />
+ <TextBlock
+ Margin="5,0,5,0"
+ HorizontalAlignment="Left"
+ VerticalAlignment="Center"
+ IsVisible="{Binding !ShowLoadProgress}"
+ Text="{Binding FifoStatusText}"
+ TextAlignment="Left" />
+ <Border
+ Width="2"
+ Height="12"
+ Margin="0"
+ BorderBrush="Gray"
+ BorderThickness="1"
+ IsVisible="{Binding !ShowLoadProgress}" />
+ <TextBlock
+ Margin="5,0,5,0"
+ HorizontalAlignment="Left"
+ VerticalAlignment="Center"
+ IsVisible="{Binding !ShowLoadProgress}"
+ Text="{Binding BackendText}"
+ TextAlignment="Left" />
+ <Border
+ Width="2"
+ Height="12"
+ Margin="0"
+ BorderBrush="Gray"
+ BorderThickness="1"
+ IsVisible="{Binding !ShowLoadProgress}" />
+ <TextBlock
+ Margin="5,0,5,0"
+ HorizontalAlignment="Left"
+ VerticalAlignment="Center"
+ IsVisible="{Binding !ShowLoadProgress}"
+ Text="{Binding GpuNameText}"
+ TextAlignment="Left" />
+ </StackPanel>
+ <StackPanel
+ Grid.Column="3"
+ Margin="0,0,5,0"
+ VerticalAlignment="Center"
+ IsVisible="{Binding ShowFirmwareStatus}"
+ Orientation="Horizontal">
+ <TextBlock
+ Name="FirmwareStatus"
+ Margin="0"
+ HorizontalAlignment="Right"
+ VerticalAlignment="Center"
+ Text="{locale:Locale StatusBarSystemVersion}" />
+ </StackPanel>
+ </Grid>
+</UserControl> \ No newline at end of file
diff --git a/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml.cs
new file mode 100644
index 00000000..473de0ee
--- /dev/null
+++ b/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml.cs
@@ -0,0 +1,52 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Input;
+using Ryujinx.Ava.UI.Windows;
+using Ryujinx.Common.Configuration;
+using Ryujinx.Common.Logging;
+using Ryujinx.Ui.Common.Configuration;
+using System;
+
+namespace Ryujinx.Ava.UI.Views.Main
+{
+ public partial class MainStatusBarView : UserControl
+ {
+ public MainWindow Window;
+
+ public MainStatusBarView()
+ {
+ InitializeComponent();
+ }
+
+ protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
+ {
+ base.OnAttachedToVisualTree(e);
+
+ if (VisualRoot is MainWindow window)
+ {
+ Window = window;
+ }
+
+ DataContext = Window.ViewModel;
+ }
+
+ private void VsyncStatus_PointerReleased(object sender, PointerReleasedEventArgs e)
+ {
+ Window.ViewModel.AppHost.Device.EnableDeviceVsync = !Window.ViewModel.AppHost.Device.EnableDeviceVsync;
+
+ Logger.Info?.Print(LogClass.Application, $"VSync toggled to: {Window.ViewModel.AppHost.Device.EnableDeviceVsync}");
+ }
+
+ private void DockedStatus_PointerReleased(object sender, PointerReleasedEventArgs e)
+ {
+ ConfigurationState.Instance.System.EnableDockedMode.Value = !ConfigurationState.Instance.System.EnableDockedMode.Value;
+ }
+
+ private void AspectRatioStatus_PointerReleased(object sender, PointerReleasedEventArgs e)
+ {
+ AspectRatio aspectRatio = ConfigurationState.Instance.Graphics.AspectRatio.Value;
+
+ ConfigurationState.Instance.Graphics.AspectRatio.Value = (int)aspectRatio + 1 > Enum.GetNames(typeof(AspectRatio)).Length - 1 ? AspectRatio.Fixed4x3 : aspectRatio + 1;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml b/src/Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml
new file mode 100644
index 00000000..ac8ede7a
--- /dev/null
+++ b/src/Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml
@@ -0,0 +1,175 @@
+<UserControl
+ xmlns="https://github.com/avaloniaui"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
+ xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
+ xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
+ xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
+ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+ x:Class="Ryujinx.Ava.UI.Views.Main.MainViewControls"
+ x:CompileBindings="True"
+ x:DataType="viewModels:MainWindowViewModel">
+ <Design.DataContext>
+ <viewModels:MainWindowViewModel />
+ </Design.DataContext>
+ <DockPanel
+ Margin="0,0,0,5"
+ HorizontalAlignment="Stretch">
+ <Button
+ Width="40"
+ MinWidth="40"
+ Margin="5,2,0,2"
+ VerticalAlignment="Stretch"
+ Command="{ReflectionBinding SetListMode}"
+ IsEnabled="{Binding IsGrid}">
+ <ui:FontIcon
+ Margin="0"
+ HorizontalAlignment="Stretch"
+ VerticalAlignment="Center"
+ FontFamily="avares://FluentAvalonia/Fonts#Symbols"
+ Glyph="{helpers:GlyphValueConverter List}" />
+ </Button>
+ <Button
+ Width="40"
+ MinWidth="40"
+ Margin="5,2,5,2"
+ VerticalAlignment="Stretch"
+ Command="{ReflectionBinding SetGridMode}"
+ IsEnabled="{Binding IsList}">
+ <ui:FontIcon
+ Margin="0"
+ HorizontalAlignment="Stretch"
+ VerticalAlignment="Center"
+ FontFamily="avares://FluentAvalonia/Fonts#Symbols"
+ Glyph="{helpers:GlyphValueConverter Grid}" />
+ </Button>
+ <TextBlock
+ Margin="10,0"
+ VerticalAlignment="Center"
+ Text="{locale:Locale IconSize}"
+ ToolTip.Tip="{locale:Locale IconSizeTooltip}" />
+ <Slider
+ Width="150"
+ Height="35"
+ Margin="5,-10,5,0"
+ VerticalAlignment="Center"
+ IsSnapToTickEnabled="True"
+ Maximum="4"
+ Minimum="1"
+ TickFrequency="1"
+ ToolTip.Tip="{locale:Locale IconSizeTooltip}"
+ Value="{Binding GridSizeScale}" />
+ <CheckBox
+ Margin="0"
+ VerticalAlignment="Center"
+ IsChecked="{Binding ShowNames, Mode=TwoWay}"
+ IsVisible="{Binding IsGrid}">
+ <TextBlock Margin="5,3,0,0" Text="{locale:Locale CommonShowNames}" />
+ </CheckBox>
+ <TextBox
+ Name="SearchBox"
+ MinWidth="200"
+ Margin="5,0,5,0"
+ HorizontalAlignment="Right"
+ VerticalAlignment="Center"
+ DockPanel.Dock="Right"
+ KeyUp="SearchBox_OnKeyUp"
+ Text="{Binding SearchText}"
+ Watermark="{locale:Locale MenuSearch}" />
+ <ui:DropDownButton
+ Width="150"
+ HorizontalAlignment="Right"
+ VerticalAlignment="Center"
+ Content="{Binding SortName}"
+ DockPanel.Dock="Right">
+ <ui:DropDownButton.Flyout>
+ <Flyout Placement="Bottom">
+ <StackPanel
+ Margin="0"
+ HorizontalAlignment="Stretch"
+ Orientation="Vertical">
+ <StackPanel>
+ <RadioButton
+ Checked="Sort_Checked"
+ Content="{locale:Locale CommonFavorite}"
+ GroupName="Sort"
+ IsChecked="{Binding IsSortedByFavorite, Mode=OneTime}"
+ Tag="Favorite" />
+ <RadioButton
+ Checked="Sort_Checked"
+ Content="{locale:Locale GameListHeaderApplication}"
+ GroupName="Sort"
+ IsChecked="{Binding IsSortedByTitle, Mode=OneTime}"
+ Tag="Title" />
+ <RadioButton
+ Checked="Sort_Checked"
+ Content="{locale:Locale GameListHeaderDeveloper}"
+ GroupName="Sort"
+ IsChecked="{Binding IsSortedByDeveloper, Mode=OneTime}"
+ Tag="Developer" />
+ <RadioButton
+ Checked="Sort_Checked"
+ Content="{locale:Locale GameListHeaderTimePlayed}"
+ GroupName="Sort"
+ IsChecked="{Binding IsSortedByTimePlayed, Mode=OneTime}"
+ Tag="TotalTimePlayed" />
+ <RadioButton
+ Checked="Sort_Checked"
+ Content="{locale:Locale GameListHeaderLastPlayed}"
+ GroupName="Sort"
+ IsChecked="{Binding IsSortedByLastPlayed, Mode=OneTime}"
+ Tag="LastPlayed" />
+ <RadioButton
+ Checked="Sort_Checked"
+ Content="{locale:Locale GameListHeaderFileExtension}"
+ GroupName="Sort"
+ IsChecked="{Binding IsSortedByType, Mode=OneTime}"
+ Tag="FileType" />
+ <RadioButton
+ Checked="Sort_Checked"
+ Content="{locale:Locale GameListHeaderFileSize}"
+ GroupName="Sort"
+ IsChecked="{Binding IsSortedBySize, Mode=OneTime}"
+ Tag="FileSize" />
+ <RadioButton
+ Checked="Sort_Checked"
+ Content="{locale:Locale GameListHeaderPath}"
+ GroupName="Sort"
+ IsChecked="{Binding IsSortedByPath, Mode=OneTime}"
+ Tag="Path" />
+ </StackPanel>
+ <Border
+ Width="60"
+ Height="2"
+ Margin="5"
+ HorizontalAlignment="Stretch"
+ BorderBrush="White"
+ BorderThickness="0,1,0,0">
+ <Separator Height="0" HorizontalAlignment="Stretch" />
+ </Border>
+ <RadioButton
+ Checked="Order_Checked"
+ Content="{locale:Locale OrderAscending}"
+ GroupName="Order"
+ IsChecked="{Binding IsAscending, Mode=OneTime}"
+ Tag="Ascending" />
+ <RadioButton
+ Checked="Order_Checked"
+ Content="{locale:Locale OrderDescending}"
+ GroupName="Order"
+ IsChecked="{Binding !IsAscending, Mode=OneTime}"
+ Tag="Descending" />
+ </StackPanel>
+ </Flyout>
+ </ui:DropDownButton.Flyout>
+ </ui:DropDownButton>
+ <TextBlock
+ Margin="10,0"
+ HorizontalAlignment="Right"
+ VerticalAlignment="Center"
+ DockPanel.Dock="Right"
+ Text="{locale:Locale CommonSort}" />
+ </DockPanel>
+</UserControl> \ No newline at end of file
diff --git a/src/Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml.cs b/src/Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml.cs
new file mode 100644
index 00000000..fd757893
--- /dev/null
+++ b/src/Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml.cs
@@ -0,0 +1,54 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Interactivity;
+using Ryujinx.Ava.Common;
+using Ryujinx.Ava.UI.ViewModels;
+using Ryujinx.Ava.UI.Windows;
+using System;
+
+namespace Ryujinx.Ava.UI.Views.Main
+{
+ public partial class MainViewControls : UserControl
+ {
+ public MainWindowViewModel ViewModel;
+
+ public MainViewControls()
+ {
+ InitializeComponent();
+ }
+
+ protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
+ {
+ base.OnAttachedToVisualTree(e);
+
+ if (VisualRoot is MainWindow window)
+ {
+ ViewModel = window.ViewModel;
+ }
+
+ DataContext = ViewModel;
+ }
+
+ public void Sort_Checked(object sender, RoutedEventArgs args)
+ {
+ if (sender is RadioButton button)
+ {
+ ViewModel.Sort(Enum.Parse<ApplicationSort>(button.Tag.ToString()));
+ }
+ }
+
+ public void Order_Checked(object sender, RoutedEventArgs args)
+ {
+ if (sender is RadioButton button)
+ {
+ ViewModel.Sort(button.Tag.ToString() != "Descending");
+ }
+ }
+
+ private void SearchBox_OnKeyUp(object sender, KeyEventArgs e)
+ {
+ ViewModel.SearchText = SearchBox.Text;
+ }
+ }
+} \ No newline at end of file