aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Ava/UI/Views/Main
diff options
context:
space:
mode:
authorIsaac Marovitz <42140194+IsaacMarovitz@users.noreply.github.com>2023-01-08 12:46:25 -0500
committerGitHub <noreply@github.com>2023-01-08 18:46:25 +0100
commiteeb2af9953f48479c3a902664f31634e6a2148be (patch)
tree3a861bbe80e48bce520ff022cc7421469bc8d38d /Ryujinx.Ava/UI/Views/Main
parent550747eac6c0f6da14070c8b6d208bde6f1d1eb9 (diff)
Ava GUI: `MainWindow` Refactor (#4178)
* Fix redundancies * Add back elses * `MainWindow` Refactor * Switch commands to `ReflectionBinding` Not required in Ava 11 * Update Ryujinx.Ava/AppHost.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update Ryujinx.Ava/AppHost.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update Ryujinx.Ava/UI/Windows/MainWindow.axaml.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update Ryujinx.Ava/UI/Windows/MainWindow.axaml.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update Ryujinx.Ava/UI/Windows/MainWindow.axaml.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update Ryujinx.Ava/AppHost.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update Ryujinx.Ava/AppHost.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update Ryujinx.Ava/AppHost.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update Ryujinx.Ava/AppHost.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Resolve issues * Remove Ava 11 Fix * Update Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs Co-authored-by: gdkchan <gab.dark.100@gmail.com> * Update Ryujinx.Ava/UI/Windows/MainWindow.axaml.cs Co-authored-by: gdkchan <gab.dark.100@gmail.com> * Fix whitespace + other suggestions * Move Vsync colours to `Styles.xaml` * Remove catch all * Use `switch` instead of `if` * Update locale keys * Use block-scoped namespaces * Fix improper Ava api usage then * Static PTC * Fix `GridItemSelectorSize` with `ShowNames` * Update for new About Window * Add back search fix Co-authored-by: Ac_K <Acoustik666@gmail.com> Co-authored-by: gdkchan <gab.dark.100@gmail.com>
Diffstat (limited to 'Ryujinx.Ava/UI/Views/Main')
-rw-r--r--Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml216
-rw-r--r--Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs146
-rw-r--r--Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml232
-rw-r--r--Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml.cs52
-rw-r--r--Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml176
-rw-r--r--Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml.cs54
6 files changed, 876 insertions, 0 deletions
diff --git a/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml b/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml
new file mode 100644
index 00000000..0d0ae119
--- /dev/null
+++ b/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml
@@ -0,0 +1,216 @@
+<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 Header="{locale:Locale MenuBarOptionsChangeLanguage}">
+ <MenuItem
+ Command="{ReflectionBinding ChangeLanguage}"
+ CommandParameter="de_DE"
+ Header="Deutsch" />
+ <MenuItem
+ Command="{ReflectionBinding ChangeLanguage}"
+ CommandParameter="en_US"
+ Header="English (US)" />
+ <MenuItem
+ Command="{ReflectionBinding ChangeLanguage}"
+ CommandParameter="es_ES"
+ Header="Español (ES)" />
+ <MenuItem
+ Command="{ReflectionBinding ChangeLanguage}"
+ CommandParameter="fr_FR"
+ Header="Français" />
+ <MenuItem
+ Command="{ReflectionBinding ChangeLanguage}"
+ CommandParameter="it_IT"
+ Header="Italiano" />
+ <MenuItem
+ Command="{ReflectionBinding ChangeLanguage}"
+ CommandParameter="pt_BR"
+ Header="Português (BR)" />
+ <MenuItem
+ Command="{ReflectionBinding ChangeLanguage}"
+ CommandParameter="tr_TR"
+ Header="Türkçe" />
+ <MenuItem
+ Command="{ReflectionBinding ChangeLanguage}"
+ CommandParameter="el_GR"
+ Header="Ελληνικά" />
+ <MenuItem
+ Command="{ReflectionBinding ChangeLanguage}"
+ CommandParameter="pl_PL"
+ Header="Polski" />
+ <MenuItem
+ Command="{ReflectionBinding ChangeLanguage}"
+ CommandParameter="ru_RU"
+ Header="Русский" />
+ <MenuItem
+ Command="{ReflectionBinding ChangeLanguage}"
+ CommandParameter="zh_CN"
+ Header="简体中文" />
+ <MenuItem
+ Command="{ReflectionBinding ChangeLanguage}"
+ CommandParameter="zh_TW"
+ Header="繁體中文" />
+ <MenuItem
+ Command="{ReflectionBinding ChangeLanguage}"
+ CommandParameter="ja_JP"
+ Header="日本語" />
+ <MenuItem
+ Command="{ReflectionBinding ChangeLanguage}"
+ CommandParameter="ko_KR"
+ Header="한국어" />
+ </MenuItem>
+ <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>
+ <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> \ No newline at end of file
diff --git a/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs b/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs
new file mode 100644
index 00000000..8c28abff
--- /dev/null
+++ b/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs
@@ -0,0 +1,146 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+using Ryujinx.Ava.UI.ViewModels;
+using Ryujinx.Ava.UI.Windows;
+using System.Threading.Tasks;
+using LibHac.FsSystem;
+using LibHac.Ncm;
+using Ryujinx.HLE.HOS;
+using Ryujinx.Modules;
+
+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();
+ }
+
+ protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
+ {
+ base.OnAttachedToVisualTree(e);
+
+ if (this.VisualRoot is MainWindow window)
+ {
+ Window = window;
+ }
+
+ ViewModel = Window.ViewModel;
+ DataContext = ViewModel;
+ }
+
+ private async void StopEmulation_Click(object sender, RoutedEventArgs e)
+ {
+ await Task.Run(() =>
+ {
+ 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.Application.TitleIdText.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;
+ }
+
+ ApplicationLoader application = ViewModel.AppHost.Device.Application;
+ if (application != null)
+ {
+ await new CheatWindow(Window.VirtualFileSystem, application.TitleIdText, application.TitleName).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 _);
+ }
+ }
+
+ public async void CheckForUpdates(object sender, RoutedEventArgs e)
+ {
+ if (Updater.CanUpdate(true, Window))
+ {
+ 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/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml b/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml
new file mode 100644
index 00000000..16705695
--- /dev/null
+++ b/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/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml.cs b/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml.cs
new file mode 100644
index 00000000..d1050ddd
--- /dev/null
+++ b/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 (this.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/Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml b/Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml
new file mode 100644
index 00000000..e83a6504
--- /dev/null
+++ b/Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml
@@ -0,0 +1,176 @@
+<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"
+ VerticalContentAlignment="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/Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml.cs b/Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml.cs
new file mode 100644
index 00000000..841d59de
--- /dev/null
+++ b/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 (this.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