Files
sharpemu/src/SharpEmu.GUI/MainWindow.axaml
T

1560 lines
89 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!--
Copyright (C) 2026 SharpEmu Emulator Project
SPDX-License-Identifier: GPL-2.0-or-later
-->
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SharpEmu.GUI"
xmlns:settingsControls="using:SharpEmu.GUI.Controls.Settings"
x:Class="SharpEmu.GUI.MainWindow"
Title="SharpEmu"
Width="1280" Height="820"
MinWidth="980" MinHeight="640"
WindowState="Maximized"
WindowStartupLocation="CenterScreen"
Background="{StaticResource BgBrush}"
WindowDecorations="None"
Icon="avares://SharpEmu.GUI/Assets/SharpEmu.ico"
KeyDown="OnKeyDown">
<Window.Resources>
<DataTemplate x:Key="LocalizedChoiceTemplate" x:DataType="local:LocalizedChoice">
<TextBlock Text="{Binding Label}"
HorizontalAlignment="Left"
TextAlignment="Left" />
</DataTemplate>
</Window.Resources>
<Grid x:Name="RootLayout" RowDefinitions="Auto,*">
<!-- Selected-game backdrop: key art behind the main content, dimmed by
a scrim so tiles and text stay readable. Fades on selection. -->
<Panel x:Name="BackdropLayer"
Grid.Row="1"
Classes="backdropLayer"
ClipToBounds="True"
RenderTransformOrigin="50%,50%">
<Panel.Transitions>
<Transitions>
<TransformOperationsTransition Property="RenderTransform"
Duration="0:0:0.72"
Easing="CubicEaseOut" />
</Transitions>
</Panel.Transitions>
<Image x:Name="BackdropImage" Stretch="UniformToFill" Opacity="0"
HorizontalAlignment="Center" VerticalAlignment="Center">
<Image.Transitions>
<Transitions>
<DoubleTransition Property="Opacity" Duration="0:0:0.35" />
</Transitions>
</Image.Transitions>
</Image>
<Border>
<Border.Background>
<LinearGradientBrush StartPoint="0%,0%" EndPoint="0%,100%">
<GradientStop Offset="0" Color="#730C0C0C" />
<GradientStop Offset="0.55" Color="#BF0C0C0C" />
<GradientStop Offset="1" Color="#EB0C0C0C" />
</LinearGradientBrush>
</Border.Background>
</Border>
</Panel>
<!-- Title bar; hidden in fullscreen (F11) so the game gets the whole screen. -->
<Grid x:Name="TitleBar"
Grid.Row="0"
Height="44"
ColumnDefinitions="*,Auto"
Background="{StaticResource ChromeBrush}">
<StackPanel Orientation="Horizontal" Spacing="10" Margin="16,0" VerticalAlignment="Center">
<Image Source="avares://SharpEmu.GUI/Assets/SharpEmu.ico" Width="20" Height="20"
RenderOptions.BitmapInterpolationMode="HighQuality" />
<TextBlock Text="SharpEmu" FontSize="14" FontWeight="SemiBold" VerticalAlignment="Center" />
<Border Classes="pill">
<TextBlock x:Name="VersionText" Text="v0.0.1" FontSize="11" Foreground="{StaticResource MutedBrush}" />
</Border>
</StackPanel>
<StackPanel x:Name="WindowChromeButtons"
Grid.Column="1"
Orientation="Horizontal"
HorizontalAlignment="Right">
<Button x:Name="MinimizeButton"
Classes="windowChrome"
ToolTip.Tip="Minimize"
AutomationProperties.Name="Minimize window">
<TextBlock Classes="materialSymbol compact windowChromeGlyph"
Text="minimize" />
</Button>
<Button x:Name="MaximizeButton"
Classes="windowChrome"
ToolTip.Tip="Restore"
AutomationProperties.Name="Restore window">
<TextBlock x:Name="MaximizeGlyph"
Classes="materialSymbol compact windowChromeGlyph"
Text="filter_none" />
</Button>
<Button x:Name="CloseButton"
Classes="windowChrome windowClose"
ToolTip.Tip="Close"
AutomationProperties.Name="Close window">
<TextBlock Classes="materialSymbol windowChromeGlyph windowCloseGlyph"
Text="close" />
</Button>
</StackPanel>
</Grid>
<!-- Main content -->
<Grid x:Name="MainContent" Grid.Row="1" Margin="32,24,32,20" RowDefinitions="Auto,*,Auto">
<!-- Settings use the same opaque neutral surface as contextual
per-game settings, keeping both views in one visual system -->
<Border x:Name="OptionsPageSurface"
Grid.RowSpan="3"
Margin="-32,-24,-32,-20"
Background="{StaticResource GameOptionsMenuBrush}"
IsVisible="False" />
<!-- Library / Options page switcher, with the library toolbar sharing
the same row on the right. Plain buttons (not TabItem) so there is
no underline; LB/RB hint chips flank the pair and the gamepad's
shoulder buttons actually switch pages from anywhere. -->
<Grid x:Name="ContentToolbar" Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Margin="0,0,0,20">
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="14" VerticalAlignment="Center">
<Border Classes="padHint" VerticalAlignment="Center">
<TextBlock Text="LB" FontSize="11" FontWeight="Bold" Foreground="{StaticResource MutedBrush}" />
</Border>
<Button x:Name="LibraryTabButton"
Classes="segment active"
Content="{Binding [Page.Library], Source={x:Static local:Localization.Instance}}" />
<Button x:Name="OptionsTabButton"
Classes="segment"
Content="{Binding [Page.Options], Source={x:Static local:Localization.Instance}}" />
<Border Classes="padHint" VerticalAlignment="Center">
<TextBlock Text="RB" FontSize="11" FontWeight="Bold" Foreground="{StaticResource MutedBrush}" />
</Border>
</StackPanel>
<StackPanel Grid.Column="2" x:Name="LibraryToolbar" Orientation="Horizontal" Spacing="8"
VerticalAlignment="Center">
<Button x:Name="LibraryLayoutButton"
Classes="iconGhost"
VerticalAlignment="Center">
<TextBlock x:Name="LibraryLayoutGlyph"
Classes="materialSymbol compact"
Text="grid_view" />
</Button>
<TextBox x:Name="SearchBox"
PlaceholderText="{Binding [Library.SearchWatermark], Source={x:Static local:Localization.Instance}}"
Width="240"
VerticalAlignment="Center" />
<Button x:Name="OpenFileButton"
Classes="ghost"
Content="{Binding [Library.OpenFile], Source={x:Static local:Localization.Instance}}"
VerticalAlignment="Center" />
</StackPanel>
</Grid>
<Panel Grid.Row="1" x:Name="PagesHost">
<!-- Library page. Covers use a horizontal virtualized rail so the
number of realized images stays bounded for large libraries. -->
<Grid x:Name="LibraryPage" Margin="0,46,0,0" RowDefinitions="188,*">
<Panel x:Name="CarouselHost"
Grid.Row="0"
Classes="carouselHost"
RenderTransformOrigin="50%,50%">
<Panel.Transitions>
<Transitions>
<TransformOperationsTransition Property="RenderTransform"
Duration="0:0:0.32"
Easing="CubicEaseOut" />
<DoubleTransition Property="Opacity"
Duration="0:0:0.18"
Easing="CubicEaseOut" />
</Transitions>
</Panel.Transitions>
<ListBox x:Name="GameList" Classes="tileGrid" Background="Transparent"
SelectionMode="Single">
<ListBox.ContextMenu>
<ContextMenu x:Name="GameContextMenu" Placement="Pointer">
<MenuItem x:Name="CtxLaunch"
Header="{Binding [Library.Context.Launch], Source={x:Static local:Localization.Instance}}"
FontWeight="SemiBold">
<MenuItem.Icon>
<TextBlock Text="▶" FontSize="11" Foreground="{StaticResource AccentHoverBrush}"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</MenuItem.Icon>
</MenuItem>
<MenuItem x:Name="CtxOpenFolder"
Header="{Binding [Library.Context.OpenFolder], Source={x:Static local:Localization.Instance}}">
<MenuItem.Icon>
<TextBlock Text="📂" FontSize="12" HorizontalAlignment="Center" VerticalAlignment="Center" />
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem x:Name="CtxCopyPath"
Header="{Binding [Library.Context.CopyPath], Source={x:Static local:Localization.Instance}}">
<MenuItem.Icon>
<TextBlock Text="⧉" FontSize="13" Foreground="{StaticResource MutedBrush}"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</MenuItem.Icon>
</MenuItem>
<MenuItem x:Name="CtxCopyTitleId"
Header="{Binding [Library.Context.CopyTitleId], Source={x:Static local:Localization.Instance}}">
<MenuItem.Icon>
<TextBlock Text="⧉" FontSize="13" Foreground="{StaticResource MutedBrush}"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem x:Name="CtxGameSettings"
Header="{Binding [Library.Context.GameSettings], Source={x:Static local:Localization.Instance}}">
<MenuItem.Icon>
<TextBlock Text="⚙" FontSize="13" Foreground="{StaticResource MutedBrush}"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem x:Name="CtxRemove"
Header="{Binding [Library.Context.Remove], Source={x:Static local:Localization.Instance}}"
Foreground="{StaticResource DangerHoverBrush}">
<MenuItem.Icon>
<TextBlock Text="✕" FontSize="12" Foreground="{StaticResource DangerHoverBrush}"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</ListBox.ContextMenu>
<ListBox.DataTemplates>
<DataTemplate x:DataType="local:GameEntry" x:CompileBindings="True">
<StackPanel Spacing="7">
<Border Classes="coverShadow libraryGameCard"
Width="148"
Height="148"
ToolTip.Tip="{Binding Name}"
AutomationProperties.Name="{Binding Name}">
<Border Classes="coverClip">
<Panel>
<Border Background="{Binding PlaceholderBrush}" IsVisible="{Binding !HasCover}">
<TextBlock Text="{Binding Initials}" FontSize="38" FontWeight="Light"
Foreground="#C4E8ECF4"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<Image Source="{Binding Cover}"
Stretch="UniformToFill"
RenderOptions.BitmapInterpolationMode="LowQuality"
IsVisible="{Binding HasCover}" />
</Panel>
</Border>
</Border>
<TextBlock Classes="libraryTileName"
Text="{Binding Name}"
TextWrapping="Wrap"
MaxLines="2"
TextTrimming="CharacterEllipsis"
TextAlignment="Center" />
</StackPanel>
</DataTemplate>
<DataTemplate x:DataType="local:AddFolderTile">
<Border Classes="addFolderTile"
Width="148"
Height="148"
ToolTip.Tip="{Binding [Library.AddFolder],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}"
AutomationProperties.Name="{Binding [Library.AddFolder],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<StackPanel HorizontalAlignment="Center"
VerticalAlignment="Center"
Spacing="12">
<Border Classes="addFolderTileIcon">
<TextBlock Classes="addFolderGlyph addFolderIconGlyph"
Text="+"
FontSize="34"
FontWeight="Light"
LineHeight="34"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<TextBlock Classes="addFolderGlyph"
Text="{Binding [Library.AddFolder],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}"
FontSize="12"
FontWeight="SemiBold"
HorizontalAlignment="Center" />
</StackPanel>
</Border>
</DataTemplate>
</ListBox.DataTemplates>
</ListBox>
</Panel>
<!-- Selected-game identity and actions share one detail surface so
the selected title and metadata are never rendered twice. -->
<StackPanel x:Name="LibrarySelectedDetails"
Grid.Row="1"
Classes="selectedDetailsHost"
x:DataType="local:GameEntry"
x:CompileBindings="True"
IsVisible="False"
MaxWidth="980"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="4,8,0,0">
<StackPanel.Transitions>
<Transitions>
<DoubleTransition Property="Opacity"
Duration="0:0:0.16" />
<TransformOperationsTransition Property="RenderTransform"
Duration="0:0:0.18" />
</Transitions>
</StackPanel.Transitions>
<TextBlock Classes="selectedGameTitle"
Text="{Binding Name}"
FontWeight="SemiBold"
TextWrapping="Wrap"
TextTrimming="CharacterEllipsis"
MaxLines="2" />
<StackPanel Orientation="Horizontal" Spacing="8">
<Border Classes="pill" IsVisible="{Binding HasTitleId}">
<TextBlock Text="{Binding TitleId}" FontSize="11" FontWeight="SemiBold"
Foreground="{StaticResource MutedBrush}" />
</Border>
<Border Classes="pill" IsVisible="{Binding HasVersion}">
<TextBlock Text="{Binding VersionText}" FontSize="11" FontWeight="SemiBold"
Foreground="{StaticResource MutedBrush}" />
</Border>
<Border Classes="pill">
<TextBlock Text="{Binding SizeText}" FontSize="11" FontWeight="SemiBold"
Foreground="{StaticResource MutedBrush}" />
</Border>
</StackPanel>
<StackPanel Orientation="Horizontal"
Spacing="12"
HorizontalAlignment="Left">
<Button x:Name="LaunchButton"
Classes="playButton"
Content="Launch"
IsEnabled="False" />
<Button x:Name="GameSettingsButton"
Classes="optionsCircle"
ToolTip.Tip="{Binding [Library.Context.GameSettings],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}"
AutomationProperties.Name="{Binding [Library.Context.GameSettings],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<TextBlock Classes="materialSymbol"
Text="more_horiz" />
</Button>
<ToggleButton x:Name="ConsoleToggle"
Classes="optionsCircle"
ToolTip.Tip="{Binding [Launch.Console],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}"
AutomationProperties.Name="{Binding [Launch.Console],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<TextBlock Classes="materialSymbol"
Text="terminal" />
</ToggleButton>
</StackPanel>
</StackPanel>
<!-- Empty state -->
<StackPanel x:Name="EmptyState" Grid.RowSpan="2"
Spacing="10" HorizontalAlignment="Center" VerticalAlignment="Center"
IsVisible="False">
<TextBlock Text="🎮" FontSize="44" HorizontalAlignment="Center" Opacity="0.7" />
<TextBlock x:Name="EmptyStateTitle" Text="Your library is empty" FontSize="18" FontWeight="SemiBold"
HorizontalAlignment="Center" />
<TextBlock x:Name="EmptyStateHint" Text="Add a folder containing your games to get started."
FontSize="13" Foreground="{StaticResource MutedBrush}" HorizontalAlignment="Center" />
</StackPanel>
<!-- Loading state: covers the grid while a scan (initial load,
rescan, or a just-added folder) is in flight, so the screen
never looks blank mid-scan. -->
<StackPanel x:Name="LoadingState" Grid.RowSpan="2"
Spacing="14" HorizontalAlignment="Center" VerticalAlignment="Center"
IsVisible="False">
<ProgressBar IsIndeterminate="True" Width="180" Height="3" />
<TextBlock x:Name="LoadingStateText"
Text="{Binding [Library.Loading], Source={x:Static local:Localization.Instance}}"
FontSize="13"
Foreground="{StaticResource MutedBrush}" HorizontalAlignment="Center" />
</StackPanel>
</Grid>
<!-- Contextual per-game settings use the same layered reveal as the
original UI branch while keeping the current launch settings. -->
<Grid x:Name="GameOptionsOverlay"
Classes="gameOptionsOverlay"
x:DataType="local:GameEntry"
x:CompileBindings="True"
RowDefinitions="1*,3*"
IsHitTestVisible="False">
<Grid.Transitions>
<Transitions>
<DoubleTransition Property="Opacity"
Duration="0:0:0.2"
Easing="CubicEaseOut" />
<TransformOperationsTransition Property="RenderTransform"
Duration="0:0:0.38"
Easing="CubicEaseOut" />
</Transitions>
</Grid.Transitions>
<Border Grid.Row="1"
Background="Transparent">
<Grid RowDefinitions="Auto,*">
<Border Grid.Row="1"
Margin="-32,0,-32,-20"
Background="{StaticResource GameOptionsMenuBrush}" />
<Border Grid.Row="1"
Height="1"
Margin="-32,0,-32,0"
ZIndex="1"
IsHitTestVisible="False"
VerticalAlignment="Top"
BoxShadow="0 18 42 0 #A6000000" />
<!-- Anchor the cover to the actual menu-surface boundary so it
overlaps both the key art and the settings surface -->
<Border Grid.Row="1"
Width="180"
Height="180"
Margin="52,-152,0,0"
ZIndex="2"
HorizontalAlignment="Left"
VerticalAlignment="Top"
BoxShadow="0 26 54 0 #D1000000">
<Border Classes="coverClip"
Background="{Binding PlaceholderBrush}">
<Panel>
<TextBlock Text="{Binding Initials}"
FontSize="28"
FontWeight="Medium"
Foreground="#A6FFFFFF"
HorizontalAlignment="Center"
VerticalAlignment="Center"
IsVisible="{Binding !HasCover}" />
<Image Source="{Binding Cover}"
Stretch="UniformToFill"
IsVisible="{Binding HasCover}" />
</Panel>
</Border>
</Border>
<Border Padding="260,18,32,24">
<Grid ColumnDefinitions="*,Auto"
ColumnSpacing="34">
<StackPanel Spacing="3"
VerticalAlignment="Center">
<TextBlock Text="{Binding Name}"
FontSize="42"
FontWeight="SemiBold"
TextTrimming="CharacterEllipsis" />
<TextBlock Text="{Binding Path}"
MaxWidth="620"
HorizontalAlignment="Left"
FontSize="11"
Foreground="{StaticResource SecondaryTextBrush}"
Opacity="0.8"
TextTrimming="CharacterEllipsis" />
</StackPanel>
<StackPanel Grid.Column="1"
Orientation="Horizontal"
Spacing="34"
VerticalAlignment="Center">
<StackPanel Spacing="4"
IsVisible="{Binding HasVersion}">
<TextBlock Classes="gameStatLabel"
Text="{Binding [Library.Stat.Version],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}" />
<TextBlock Classes="gameStatValue"
FontSize="15"
Text="{Binding VersionText}" />
</StackPanel>
<StackPanel Spacing="4">
<TextBlock Classes="gameStatLabel"
Text="{Binding [Library.Stat.Installed],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}" />
<TextBlock Classes="gameStatValue"
FontSize="15"
Text="{Binding SizeText}" />
</StackPanel>
<StackPanel Spacing="4"
IsVisible="{Binding HasTitleId}">
<TextBlock Classes="gameStatLabel"
Text="{Binding [Library.Stat.TitleId],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}" />
<TextBlock Classes="gameStatValue"
FontSize="15"
Text="{Binding TitleId}" />
</StackPanel>
</StackPanel>
</Grid>
</Border>
<Grid Grid.Row="1"
Margin="32,12,32,8"
ColumnDefinitions="220,*"
ColumnSpacing="54">
<Grid Margin="0,62,0,0"
RowDefinitions="Auto,*">
<Button x:Name="GameOptionsLaunchButton"
Classes="gameOptionsLaunch">
<TextBlock VerticalAlignment="Center"
Text="{Binding [Library.Context.Launch],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}" />
</Button>
<ScrollViewer x:Name="GameOptionsNavScroll"
Grid.Row="1"
Margin="0,12,0,0"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Hidden"
BringIntoViewOnFocusChange="True">
<ScrollViewer.Styles>
<Style Selector="ScrollBar">
<Setter Property="IsHitTestVisible" Value="False" />
<Setter Property="Opacity" Value="0" />
</Style>
</ScrollViewer.Styles>
<Grid x:Name="GameOptionsNavHost"
Background="Transparent"
VerticalAlignment="Top">
<Border x:Name="GameOptionsNavIndicator"
Classes="optionsNavIndicator"
IsHitTestVisible="False"
VerticalAlignment="Top" />
<StackPanel>
<Button x:Name="GameOptionsGeneralNav"
Classes="optionsNav active"
AutomationProperties.Name="{Binding [Options.General],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<Grid ColumnDefinitions="36,*">
<TextBlock Grid.Column="0"
Classes="materialSymbol optionsNavIcon"
Text="tune" />
<TextBlock Grid.Column="1"
Classes="optionsNavLabel"
Text="{Binding [Options.General],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}" />
</Grid>
</Button>
<Button x:Name="GameOptionsLoggingNav"
Classes="optionsNav"
AutomationProperties.Name="{Binding [Options.Logging],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<Grid ColumnDefinitions="36,*">
<TextBlock Grid.Column="0"
Classes="materialSymbol optionsNavIcon"
Text="terminal" />
<TextBlock Grid.Column="1"
Classes="optionsNavLabel"
Text="{Binding [Options.Logging],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}" />
</Grid>
</Button>
<Button x:Name="GameOptionsRenderingNav"
Classes="optionsNav"
AutomationProperties.Name="{Binding [Options.Graphics],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<Grid ColumnDefinitions="36,*">
<TextBlock Grid.Column="0"
Classes="materialSymbol optionsNavIcon"
Text="monitor" />
<TextBlock Grid.Column="1"
Classes="optionsNavLabel"
Text="{Binding [Options.Graphics],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}" />
</Grid>
</Button>
<Button x:Name="GameOptionsEnvironmentNav"
Classes="optionsNav"
AutomationProperties.Name="{Binding [Options.Env.Tab],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<Grid ColumnDefinitions="36,*">
<TextBlock Grid.Column="0"
Classes="materialSymbol optionsNavIcon"
Text="deployed_code" />
<TextBlock Grid.Column="1"
Classes="optionsNavLabel"
Text="{Binding [Options.Env.Tab],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}" />
</Grid>
</Button>
<Button x:Name="GameOptionsBackNav"
Classes="optionsNav"
AutomationProperties.Name="{Binding [Common.Back],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<Grid ColumnDefinitions="36,*">
<TextBlock Grid.Column="0"
Classes="materialSymbol optionsNavIcon"
Text="arrow_back" />
<TextBlock Grid.Column="1"
Classes="optionsNavLabel"
Text="{Binding [Common.Back],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}" />
</Grid>
</Button>
</StackPanel>
</Grid>
</ScrollViewer>
</Grid>
<Grid Grid.Column="1"
Margin="0,36,0,0">
<ScrollViewer x:Name="GameOptionsGeneralPanel"
Classes="optionsSectionPanel active">
<StackPanel Spacing="12">
<Border Classes="optionsGroup">
<StackPanel Spacing="8">
<local:SettingRow x:Name="GameStrictRow"
Classes="optionRow"
Label="{Binding [Options.Strict.Label],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}"
Description="{Binding [Options.Strict.Desc],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<ToggleSwitch x:Name="GameStrictToggle"
Classes="optionToggle" />
</local:SettingRow>
</StackPanel>
</Border>
<WrapPanel Margin="0,12,0,0"
ItemWidth="260"
ItemHeight="54"
Orientation="Horizontal">
<Button x:Name="GameOptionsOpenFolderButton"
Classes="gameAction"
Margin="0,0,10,10">
<StackPanel Orientation="Horizontal"
Spacing="11">
<TextBlock Classes="materialSymbol"
Text="folder_open" />
<TextBlock Text="{Binding [Library.Context.OpenFolder],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}"
VerticalAlignment="Center" />
</StackPanel>
</Button>
<Button x:Name="GameOptionsCopyPathButton"
Classes="gameAction"
Margin="0,0,10,10">
<StackPanel Orientation="Horizontal"
Spacing="11">
<TextBlock Classes="materialSymbol"
Text="content_copy" />
<TextBlock Text="{Binding [Library.Context.CopyPath],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}"
VerticalAlignment="Center" />
</StackPanel>
</Button>
<Button x:Name="GameOptionsCopyTitleIdButton"
Classes="gameAction"
Margin="0,0,10,10">
<StackPanel Orientation="Horizontal"
Spacing="11">
<TextBlock Classes="materialSymbol"
Text="tag" />
<TextBlock Text="{Binding [Library.Context.CopyTitleId],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}"
VerticalAlignment="Center" />
</StackPanel>
</Button>
<Button x:Name="GameOptionsRemoveButton"
Classes="gameAction dangerAction"
Margin="0,0,10,10">
<StackPanel Orientation="Horizontal"
Spacing="11">
<TextBlock Classes="materialSymbol"
Text="delete" />
<TextBlock Text="{Binding [Library.Context.Remove],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}"
VerticalAlignment="Center" />
</StackPanel>
</Button>
</WrapPanel>
</StackPanel>
</ScrollViewer>
<ScrollViewer x:Name="GameOptionsLoggingPanel"
Classes="optionsSectionPanel">
<StackPanel>
<Border Classes="optionsGroup">
<StackPanel Spacing="8">
<local:SettingRow x:Name="GameLogLevelRow"
Classes="optionRow"
Label="{Binding [Options.LogLevel.Label],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}"
Description="{Binding [Options.LogLevel.Desc],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<ComboBox x:Name="GameLogLevelBox"
Classes="optionValue"
ItemTemplate="{StaticResource LocalizedChoiceTemplate}"
HorizontalContentAlignment="Left"
VerticalAlignment="Center" />
</local:SettingRow>
<local:SettingRow x:Name="GameTraceImportsRow"
Classes="optionRow"
Label="{Binding [Options.TraceImports.Label],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}"
Description="{Binding [Options.TraceImports.Desc],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<settingsControls:SplitNumericUpDown x:Name="GameTraceImportsBox"
Classes="optionValue"
Minimum="0"
Maximum="4096"
Increment="16"
Value="0"
FormatString="0"
VerticalAlignment="Center" />
</local:SettingRow>
<local:SettingRow x:Name="GameLogToFileRow"
Classes="optionRow"
Label="{Binding [Options.LogToFile.Label],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}"
Description="{Binding [Options.LogToFile.Desc],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<ToggleSwitch x:Name="GameLogToFileToggle"
Classes="optionToggle" />
</local:SettingRow>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
<ScrollViewer x:Name="GameOptionsRenderingPanel"
Classes="optionsSectionPanel">
<StackPanel>
<Border Classes="optionsGroup">
<StackPanel Spacing="8">
<local:SettingRow x:Name="GameWindowModeRow"
Classes="optionRow"
Label="{Binding [Options.WindowMode.Label],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}"
Description="{Binding [Options.WindowMode.Desc],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<ComboBox x:Name="GameWindowModeBox"
Classes="optionValue"
ItemTemplate="{StaticResource LocalizedChoiceTemplate}"
HorizontalContentAlignment="Left"
VerticalAlignment="Center" />
</local:SettingRow>
<local:SettingRow x:Name="GameResolutionRow"
Classes="optionRow"
Label="{Binding [Options.Resolution.Label],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}"
Description="{Binding [Options.Resolution.Desc],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<ComboBox x:Name="GameResolutionBox"
Classes="optionValue"
VerticalAlignment="Center" />
</local:SettingRow>
<local:SettingRow x:Name="GameDisplayRow"
Classes="optionRow"
Label="{Binding [Options.Display.Label],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}"
Description="{Binding [Options.Display.Desc],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<ComboBox x:Name="GameDisplayBox"
Classes="optionValue"
Width="260"
VerticalAlignment="Center" />
</local:SettingRow>
<local:SettingRow x:Name="GameRefreshRateRow"
Classes="optionRow"
Label="{Binding [Options.RefreshRate.Label],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}"
Description="{Binding [Options.RefreshRate.Desc],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<ComboBox x:Name="GameRefreshRateBox"
Classes="optionValue"
VerticalAlignment="Center" />
</local:SettingRow>
<local:SettingRow x:Name="GameScalingModeRow"
Classes="optionRow"
Label="{Binding [Options.Scaling.Label],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}"
Description="{Binding [Options.Scaling.Desc],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<ComboBox x:Name="GameScalingModeBox"
Classes="optionValue"
ItemTemplate="{StaticResource LocalizedChoiceTemplate}"
HorizontalContentAlignment="Left"
VerticalAlignment="Center" />
</local:SettingRow>
<local:SettingRow x:Name="GameVSyncRow"
Classes="optionRow"
Label="{Binding [Options.VSync.Label],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}"
Description="{Binding [Options.VSync.Desc],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<ToggleSwitch x:Name="GameVSyncToggle"
Classes="optionToggle" />
</local:SettingRow>
<local:SettingRow x:Name="GameHdrModeRow"
Classes="optionRow"
Label="{Binding [Options.Hdr.Label],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}"
Description="{Binding [Options.Hdr.Desc],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<ComboBox x:Name="GameHdrModeBox"
Classes="optionValue"
ItemTemplate="{StaticResource LocalizedChoiceTemplate}"
HorizontalContentAlignment="Left"
VerticalAlignment="Center" />
</local:SettingRow>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
<ScrollViewer x:Name="GameOptionsEnvironmentPanel"
Classes="optionsSectionPanel">
<StackPanel>
<Border Classes="optionsGroup">
<StackPanel Spacing="8">
<local:SettingRow Classes="optionRow"
Label="SHARPEMU_BTHID_UNAVAILABLE"
Description="{Binding [Options.Env.Bthid.Desc],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<ToggleSwitch x:Name="GameEnvBthidToggle"
Classes="optionToggle" />
</local:SettingRow>
<local:SettingRow Classes="optionRow"
Label="SHARPEMU_DISABLE_IMPORT_LOOP_GUARD"
Description="{Binding [Options.Env.LoopGuard.Desc],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<ToggleSwitch x:Name="GameEnvLoopGuardToggle"
Classes="optionToggle" />
</local:SettingRow>
<local:SettingRow Classes="optionRow"
Label="SHARPEMU_WRITABLE_APP0"
Description="{Binding [Options.Env.WritableApp0.Desc],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<ToggleSwitch x:Name="GameEnvWritableApp0Toggle"
Classes="optionToggle" />
</local:SettingRow>
<local:SettingRow Classes="optionRow"
Label="SHARPEMU_VK_VALIDATION"
Description="{Binding [Options.Env.VkValidation.Desc],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<ToggleSwitch x:Name="GameEnvVkValidationToggle"
Classes="optionToggle" />
</local:SettingRow>
<local:SettingRow Classes="optionRow"
Label="SHARPEMU_DUMP_SPIRV"
Description="{Binding [Options.Env.DumpSpirv.Desc],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<ToggleSwitch x:Name="GameEnvDumpSpirvToggle"
Classes="optionToggle" />
</local:SettingRow>
<local:SettingRow Classes="optionRow"
Label="SHARPEMU_LOG_DIRECT_MEMORY"
Description="{Binding [Options.Env.LogDirectMemory.Desc],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<ToggleSwitch x:Name="GameEnvLogDirectMemoryToggle"
Classes="optionToggle" />
</local:SettingRow>
<local:SettingRow Classes="optionRow"
Label="SHARPEMU_LOG_IO"
Description="{Binding [Options.Env.LogIo.Desc],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<ToggleSwitch x:Name="GameEnvLogIoToggle"
Classes="optionToggle" />
</local:SettingRow>
<local:SettingRow Classes="optionRow"
Label="SHARPEMU_LOG_NP"
Description="{Binding [Options.Env.LogNp.Desc],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<ToggleSwitch x:Name="GameEnvLogNpToggle"
Classes="optionToggle" />
</local:SettingRow>
<local:SettingRow Classes="optionRow"
Label="SHARPEMU_GUEST_IMAGE_CPU_SYNC"
Description="{Binding [Options.Env.GuestImageCpuSync.Desc],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}">
<ToggleSwitch x:Name="GameEnvGuestImageCpuSyncToggle"
Classes="optionToggle" />
</local:SettingRow>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</Grid>
</Grid>
</Grid>
</Border>
</Grid>
<!-- Options page: stable local navigation keeps each settings group
focused while preserving every setting from the current launcher -->
<Grid x:Name="OptionsPage"
IsVisible="False"
ColumnDefinitions="244,*"
ColumnSpacing="42"
Margin="32,14,32,16">
<Border Grid.Column="0" Classes="optionsNavSurface">
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Hidden">
<Grid x:Name="OptionsNavHost">
<Border x:Name="OptionsNavIndicator"
Classes="optionsNavIndicator"
Height="54"
VerticalAlignment="Top"
IsHitTestVisible="False" />
<StackPanel>
<Button x:Name="OptionsGeneralNav" Classes="optionsNav active">
<Grid ColumnDefinitions="36,*">
<TextBlock Grid.Column="0"
Classes="materialSymbol optionsNavIcon"
Text="tune" />
<TextBlock x:Name="OptionsGeneralNavLabel"
Grid.Column="1"
Classes="optionsNavLabel"
Text="General" />
</Grid>
</Button>
<Button x:Name="OptionsLoggingNav" Classes="optionsNav">
<Grid ColumnDefinitions="36,*">
<TextBlock Grid.Column="0"
Classes="materialSymbol optionsNavIcon"
Text="terminal" />
<TextBlock x:Name="OptionsLoggingNavLabel"
Grid.Column="1"
Classes="optionsNavLabel"
Text="Logging" />
</Grid>
</Button>
<Button x:Name="OptionsLauncherNav" Classes="optionsNav">
<Grid ColumnDefinitions="36,*">
<TextBlock Grid.Column="0"
Classes="materialSymbol optionsNavIcon"
Text="rocket_launch" />
<TextBlock x:Name="OptionsLauncherNavLabel"
Grid.Column="1"
Classes="optionsNavLabel"
Text="Launcher" />
</Grid>
</Button>
<Button x:Name="OptionsRenderingNav" Classes="optionsNav">
<Grid ColumnDefinitions="36,*">
<TextBlock Grid.Column="0"
Classes="materialSymbol optionsNavIcon"
Text="monitor" />
<TextBlock x:Name="OptionsRenderingNavLabel"
Grid.Column="1"
Classes="optionsNavLabel"
Text="Rendering" />
</Grid>
</Button>
<Button x:Name="OptionsEnvironmentNav" Classes="optionsNav">
<Grid ColumnDefinitions="36,*">
<TextBlock Grid.Column="0"
Classes="materialSymbol optionsNavIcon"
Text="deployed_code" />
<TextBlock x:Name="OptionsEnvironmentNavLabel"
Grid.Column="1"
Classes="optionsNavLabel"
Text="Environment" />
</Grid>
</Button>
<Button x:Name="OptionsAboutNav" Classes="optionsNav">
<Grid ColumnDefinitions="36,*">
<TextBlock Grid.Column="0"
Classes="materialSymbol optionsNavIcon"
Text="info" />
<TextBlock x:Name="OptionsAboutNavLabel"
Grid.Column="1"
Classes="optionsNavLabel"
Text="About" />
</Grid>
</Button>
</StackPanel>
</Grid>
</ScrollViewer>
</Border>
<Border Grid.Column="1" Classes="optionsContentSurface">
<Panel>
<ScrollViewer x:Name="OptionsGeneralPanel"
Classes="optionsSectionPanel active">
<StackPanel>
<Border Classes="optionsGroup">
<StackPanel Spacing="8">
<local:SettingRow x:Name="CpuEngineRow"
Classes="optionRow"
Label="{Binding [Options.CpuEngine.Label], Source={x:Static local:Localization.Instance}}"
Description="{Binding [Options.CpuEngine.Desc], Source={x:Static local:Localization.Instance}}">
<ComboBox x:Name="CpuEngineBox"
Classes="optionValue"
ItemTemplate="{StaticResource LocalizedChoiceTemplate}"
HorizontalContentAlignment="Left"
VerticalAlignment="Center" />
</local:SettingRow>
<local:SettingRow x:Name="StrictRow"
Classes="optionRow"
Label="{Binding [Options.Strict.Label], Source={x:Static local:Localization.Instance}}"
Description="{Binding [Options.Strict.Desc], Source={x:Static local:Localization.Instance}}">
<ToggleSwitch x:Name="StrictToggle"
Classes="optionToggle" />
</local:SettingRow>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
<ScrollViewer x:Name="OptionsLoggingPanel"
Classes="optionsSectionPanel">
<StackPanel>
<Border Classes="optionsGroup">
<StackPanel Spacing="8">
<local:SettingRow x:Name="LogLevelRow"
Classes="optionRow"
Label="{Binding [Options.LogLevel.Label], Source={x:Static local:Localization.Instance}}"
Description="{Binding [Options.LogLevel.Desc], Source={x:Static local:Localization.Instance}}">
<ComboBox x:Name="LogLevelBox"
Classes="optionValue"
ItemTemplate="{StaticResource LocalizedChoiceTemplate}"
HorizontalContentAlignment="Left"
VerticalAlignment="Center" />
</local:SettingRow>
<local:SettingRow x:Name="TraceImportsRow"
Classes="optionRow"
Label="{Binding [Options.TraceImports.Label], Source={x:Static local:Localization.Instance}}"
Description="{Binding [Options.TraceImports.Desc], Source={x:Static local:Localization.Instance}}">
<settingsControls:SplitNumericUpDown x:Name="TraceImportsBox"
Classes="optionValue"
Minimum="0"
Maximum="4096" Increment="16" Value="0" FormatString="0"
VerticalAlignment="Center" />
</local:SettingRow>
<local:SettingRow x:Name="LogToFileRow"
Classes="optionRow"
Label="{Binding [Options.LogToFile.Label], Source={x:Static local:Localization.Instance}}"
Description="{Binding [Options.LogToFile.Desc], Source={x:Static local:Localization.Instance}}">
<ToggleSwitch x:Name="LogToFileToggle"
Classes="optionToggle" />
</local:SettingRow>
<local:SettingRow x:Name="LogFilePathRow"
Classes="optionRow"
Label="{Binding [Options.LogFilePath.Label], Source={x:Static local:Localization.Instance}}"
Description="No custom path">
<Button x:Name="SelectLogFilePathButton"
Classes="optionAction">
<TextBlock x:Name="SelectLogFilePathButtonLabel"
Text="{Binding [Options.LogFilePath.Select], Source={x:Static local:Localization.Instance}}"
VerticalAlignment="Center" />
</Button>
</local:SettingRow>
<local:SettingRow x:Name="OverrideLogFileRow"
Classes="optionRow"
Label="{Binding [Options.OverrideLogFile.Label], Source={x:Static local:Localization.Instance}}"
Description="{Binding [Options.OverrideLogFile.Desc], Source={x:Static local:Localization.Instance}}">
<ToggleSwitch x:Name="OverrideLogFileToggle"
Classes="optionToggle" />
</local:SettingRow>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
<ScrollViewer x:Name="OptionsLauncherPanel"
Classes="optionsSectionPanel">
<StackPanel>
<Border Classes="optionsGroup">
<StackPanel Spacing="8">
<local:SettingRow x:Name="LanguageRow"
Classes="optionRow"
Label="{Binding [Options.Language.Label], Source={x:Static local:Localization.Instance}}"
Description="{Binding [Options.Language.Desc], Source={x:Static local:Localization.Instance}}">
<ComboBox x:Name="LanguageBox"
Classes="optionValue"
Width="210"
VerticalAlignment="Center">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="local:LanguageInfo">
<TextBlock Text="{Binding NativeName}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</local:SettingRow>
<local:SettingRow x:Name="DefaultProfileRow"
Classes="optionRow"
Label="{Binding [Options.DefaultProfile.Label], Source={x:Static local:Localization.Instance}}"
Description="{Binding [Options.DefaultProfile.Desc], Source={x:Static local:Localization.Instance}}">
<TextBox x:Name="DefaultProfileBox"
Classes="optionValue"
MaxLength="16"
VerticalAlignment="Center" />
</local:SettingRow>
<local:SettingRow x:Name="TitleMusicRow"
Classes="optionRow"
Label="{Binding [Options.TitleMusic.Label], Source={x:Static local:Localization.Instance}}"
Description="{Binding [Options.TitleMusic.Desc], Source={x:Static local:Localization.Instance}}">
<ToggleSwitch x:Name="TitleMusicToggle"
Classes="optionToggle"
IsChecked="True" />
</local:SettingRow>
<local:SettingRow x:Name="DiscordRow"
Classes="optionRow"
Label="{Binding [Options.Discord.Label], Source={x:Static local:Localization.Instance}}"
Description="{Binding [Options.Discord.Desc], Source={x:Static local:Localization.Instance}}">
<ToggleSwitch x:Name="DiscordToggle"
Classes="optionToggle" />
</local:SettingRow>
<local:SettingRow x:Name="AutoUpdateRow"
Classes="optionRow"
Label="{Binding [Updater.Auto.Label], Source={x:Static local:Localization.Instance}}"
Description="{Binding [Updater.Auto.Desc], Source={x:Static local:Localization.Instance}}">
<ToggleSwitch x:Name="AutoUpdateToggle"
Classes="optionToggle"
IsChecked="True" />
</local:SettingRow>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
<ScrollViewer x:Name="OptionsAboutPanel"
Classes="optionsSectionPanel">
<StackPanel>
<Border Classes="optionsGroup">
<StackPanel Spacing="8">
<!--Latest commit info-->
<Border Classes="optionsInfoRow">
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="18">
<StackPanel VerticalAlignment="Center">
<TextBlock x:Name="LatestCommitLabel"
Text="{Binding [About.Github.LatestCommitLabel], Source={x:Static local:Localization.Instance}}"
FontSize="14"
FontWeight="Medium" />
<TextBlock x:Name="LatestCommitDescription"
Text="{Binding [About.Github.LatestCommitDescription], Source={x:Static local:Localization.Instance}}"
FontSize="11"
Foreground="{StaticResource SettingsDescriptionBrush}"
TextWrapping="Wrap" />
</StackPanel>
<Button Grid.Column="1"
x:Name="LatestCommitHashText"
Classes="optionAction"
Content="Loading…"
FontSize="12"
FontFamily="Consolas,monospace"
VerticalAlignment="Center"
IsEnabled="False" />
</Grid>
</Border>
<!--Update-->
<Border Classes="optionsInfoRow">
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="18">
<StackPanel VerticalAlignment="Center">
<TextBlock x:Name="UpdateLabel"
Text="{Binding [Updater.Label], Source={x:Static local:Localization.Instance}}"
FontSize="14"
FontWeight="Medium" />
<TextBlock x:Name="UpdateStatusText"
Text="Current build: dev"
FontSize="11"
Foreground="{StaticResource SettingsDescriptionBrush}"
TextWrapping="Wrap" />
</StackPanel>
<Button Grid.Column="1"
x:Name="UpdateButton"
Classes="optionAction"
Content="Check for updates"
VerticalAlignment="Center" />
</Grid>
</Border>
<!--Github-->
<Border Classes="optionsInfoRow">
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="18">
<StackPanel VerticalAlignment="Center">
<TextBlock x:Name="GithubLabel"
Text="{Binding [About.Github.Label], Source={x:Static local:Localization.Instance}}"
FontSize="14"
FontWeight="Medium" />
<TextBlock x:Name="GithubDesc"
Text="{Binding [About.Github.Desc], Source={x:Static local:Localization.Instance}}"
FontSize="11"
Foreground="{StaticResource SettingsDescriptionBrush}"
TextWrapping="Wrap" />
</StackPanel>
<Button Grid.Column="1"
x:Name="GithubButton"
Classes="optionAction"
Content="{Binding [About.GithubButton], Source={x:Static local:Localization.Instance}}"
VerticalAlignment="Center" />
</Grid>
</Border>
<!--Discord-->
<Border Classes="optionsInfoRow">
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="18">
<StackPanel VerticalAlignment="Center">
<TextBlock x:Name="DiscordServerLabel"
Text="{Binding [About.Discord.Label], Source={x:Static local:Localization.Instance}}"
FontSize="14"
FontWeight="Medium" />
<TextBlock x:Name="DiscordServerDesc"
Text="{Binding [About.Discord.Desc], Source={x:Static local:Localization.Instance}}"
FontSize="11"
Foreground="{StaticResource SettingsDescriptionBrush}"
TextWrapping="Wrap" />
</StackPanel>
<TextBlock Grid.Column="1"
x:Name="DiscordComingSoonText"
Text="{Binding [About.DiscordComingSoon], Source={x:Static local:Localization.Instance}}"
FontSize="12"
Foreground="{StaticResource MutedBrush}"
VerticalAlignment="Center" />
</Grid>
</Border>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
<ScrollViewer x:Name="OptionsRenderingPanel"
Classes="optionsSectionPanel">
<StackPanel Spacing="16">
<Border Classes="optionsGroup">
<StackPanel Spacing="8">
<local:SettingRow x:Name="RenderResolutionRow"
Classes="optionRow"
Label="{Binding [Options.RenderResolution.Label], Source={x:Static local:Localization.Instance}}"
Description="{Binding [Options.RenderResolution.Desc], Source={x:Static local:Localization.Instance}}">
<ComboBox x:Name="RenderResolutionBox"
Classes="optionValue"
ItemTemplate="{StaticResource LocalizedChoiceTemplate}"
HorizontalContentAlignment="Left"
VerticalAlignment="Center" />
</local:SettingRow>
</StackPanel>
</Border>
<Border Classes="optionsGroup">
<StackPanel Spacing="8">
<local:SettingRow x:Name="WindowModeRow"
Classes="optionRow"
Label="{Binding [Options.WindowMode.Label], Source={x:Static local:Localization.Instance}}"
Description="{Binding [Options.WindowMode.Desc], Source={x:Static local:Localization.Instance}}">
<ComboBox x:Name="WindowModeBox"
Classes="optionValue"
ItemTemplate="{StaticResource LocalizedChoiceTemplate}"
HorizontalContentAlignment="Left"
VerticalAlignment="Center" />
</local:SettingRow>
<local:SettingRow x:Name="ResolutionRow"
Classes="optionRow"
Label="{Binding [Options.Resolution.Label], Source={x:Static local:Localization.Instance}}"
Description="{Binding [Options.Resolution.Desc], Source={x:Static local:Localization.Instance}}">
<ComboBox x:Name="ResolutionBox"
Classes="optionValue"
VerticalAlignment="Center" />
</local:SettingRow>
<local:SettingRow x:Name="DisplayRow"
Classes="optionRow"
Label="{Binding [Options.Display.Label], Source={x:Static local:Localization.Instance}}"
Description="{Binding [Options.Display.Desc], Source={x:Static local:Localization.Instance}}">
<ComboBox x:Name="DisplayBox"
Classes="optionValue"
Width="260"
VerticalAlignment="Center" />
</local:SettingRow>
<local:SettingRow x:Name="RefreshRateRow"
Classes="optionRow"
Label="{Binding [Options.RefreshRate.Label], Source={x:Static local:Localization.Instance}}"
Description="{Binding [Options.RefreshRate.Desc], Source={x:Static local:Localization.Instance}}">
<ComboBox x:Name="RefreshRateBox"
Classes="optionValue"
VerticalAlignment="Center" />
</local:SettingRow>
<local:SettingRow x:Name="ScalingRow"
Classes="optionRow"
Label="{Binding [Options.Scaling.Label], Source={x:Static local:Localization.Instance}}"
Description="{Binding [Options.Scaling.Desc], Source={x:Static local:Localization.Instance}}">
<ComboBox x:Name="ScalingModeBox"
Classes="optionValue"
ItemTemplate="{StaticResource LocalizedChoiceTemplate}"
HorizontalContentAlignment="Left"
VerticalAlignment="Center" />
</local:SettingRow>
<local:SettingRow x:Name="VSyncRow"
Classes="optionRow"
Label="{Binding [Options.VSync.Label], Source={x:Static local:Localization.Instance}}"
Description="{Binding [Options.VSync.Desc], Source={x:Static local:Localization.Instance}}">
<ToggleSwitch x:Name="VSyncToggle"
Classes="optionToggle"
IsChecked="True" />
</local:SettingRow>
<local:SettingRow x:Name="HdrRow"
Classes="optionRow"
Label="{Binding [Options.Hdr.Label], Source={x:Static local:Localization.Instance}}"
Description="{Binding [Options.Hdr.Desc], Source={x:Static local:Localization.Instance}}">
<ComboBox x:Name="HdrModeBox"
Classes="optionValue"
ItemTemplate="{StaticResource LocalizedChoiceTemplate}"
HorizontalContentAlignment="Left"
VerticalAlignment="Center" />
</local:SettingRow>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
<ScrollViewer x:Name="OptionsEnvironmentPanel"
Classes="optionsSectionPanel">
<StackPanel>
<Border Classes="optionsGroup">
<StackPanel Spacing="8">
<local:SettingRow x:Name="EnvBthidRow" Classes="optionRow" LabelFontFamily="Consolas,monospace" Label="SHARPEMU_BTHID_UNAVAILABLE"
Description="{Binding [Options.Env.Bthid.Desc], Source={x:Static local:Localization.Instance}}">
<ToggleSwitch x:Name="EnvBthidToggle" Classes="optionToggle" />
</local:SettingRow>
<local:SettingRow x:Name="EnvLoopGuardRow" Classes="optionRow" LabelFontFamily="Consolas,monospace" Label="SHARPEMU_DISABLE_IMPORT_LOOP_GUARD"
Description="{Binding [Options.Env.LoopGuard.Desc], Source={x:Static local:Localization.Instance}}">
<ToggleSwitch x:Name="EnvLoopGuardToggle" Classes="optionToggle" />
</local:SettingRow>
<local:SettingRow x:Name="EnvWritableApp0Row" Classes="optionRow" LabelFontFamily="Consolas,monospace" Label="SHARPEMU_WRITABLE_APP0"
Description="{Binding [Options.Env.WritableApp0.Desc], Source={x:Static local:Localization.Instance}}">
<ToggleSwitch x:Name="EnvWritableApp0Toggle" Classes="optionToggle" />
</local:SettingRow>
<local:SettingRow x:Name="EnvVkValidationRow" Classes="optionRow" LabelFontFamily="Consolas,monospace" Label="SHARPEMU_VK_VALIDATION"
Description="{Binding [Options.Env.VkValidation.Desc], Source={x:Static local:Localization.Instance}}">
<ToggleSwitch x:Name="EnvVkValidationToggle" Classes="optionToggle" />
</local:SettingRow>
<local:SettingRow x:Name="EnvDumpSpirvRow" Classes="optionRow" LabelFontFamily="Consolas,monospace" Label="SHARPEMU_DUMP_SPIRV"
Description="{Binding [Options.Env.DumpSpirv.Desc], Source={x:Static local:Localization.Instance}}">
<ToggleSwitch x:Name="EnvDumpSpirvToggle" Classes="optionToggle" />
</local:SettingRow>
<local:SettingRow x:Name="EnvLogDirectMemoryRow" Classes="optionRow" LabelFontFamily="Consolas,monospace" Label="SHARPEMU_LOG_DIRECT_MEMORY"
Description="{Binding [Options.Env.LogDirectMemory.Desc], Source={x:Static local:Localization.Instance}}">
<ToggleSwitch x:Name="EnvLogDirectMemoryToggle" Classes="optionToggle" />
</local:SettingRow>
<local:SettingRow x:Name="EnvLogIoRow" Classes="optionRow" LabelFontFamily="Consolas,monospace" Label="SHARPEMU_LOG_IO"
Description="{Binding [Options.Env.LogIo.Desc], Source={x:Static local:Localization.Instance}}">
<ToggleSwitch x:Name="EnvLogIoToggle" Classes="optionToggle" />
</local:SettingRow>
<local:SettingRow x:Name="EnvLogNpRow" Classes="optionRow" LabelFontFamily="Consolas,monospace" Label="SHARPEMU_LOG_NP"
Description="{Binding [Options.Env.LogNp.Desc], Source={x:Static local:Localization.Instance}}">
<ToggleSwitch x:Name="EnvLogNpToggle" Classes="optionToggle" />
</local:SettingRow>
<local:SettingRow x:Name="EnvGuestImageCpuSyncRow" Classes="optionRow" LabelFontFamily="Consolas,monospace" Label="SHARPEMU_GUEST_IMAGE_CPU_SYNC"
Description="{Binding [Options.Env.GuestImageCpuSync.Desc], Source={x:Static local:Localization.Instance}}">
<ToggleSwitch x:Name="EnvGuestImageCpuSyncToggle" Classes="optionToggle" />
</local:SettingRow>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</Panel>
</Border>
</Grid>
</Panel>
<!-- Console (collapsible) -->
<Border Grid.Row="2" x:Name="ConsolePanel" Classes="card" Padding="0" Height="240"
Margin="0,12,0,0" IsVisible="False">
<Grid RowDefinitions="Auto,*">
<Grid Grid.Row="0" ColumnDefinitions="*,Auto,Auto,Auto,Auto,Auto,Auto" Margin="16,12,16,8">
<TextBlock x:Name="ConsoleSectionTitle" Classes="sectionTitle"
Text="{Binding [Console.Title], Source={x:Static local:Localization.Instance}}"
VerticalAlignment="Center" />
<TextBox Grid.Column="1" FontSize="12" Margin="0,0,12,0" x:Name="ConsoleSearchBox"
PlaceholderText="{Binding [Console.SearchWatermark], Source={x:Static local:Localization.Instance}}"
Width="320" />
<CheckBox Grid.Column="2" x:Name="AutoScrollCheck"
Content="{Binding [Console.AutoScroll], Source={x:Static local:Localization.Instance}}"
IsChecked="True"
FontSize="12" Margin="0,0,12,0" />
<Button Grid.Column="3" x:Name="DetachConsoleButton" Classes="ghost"
Content="{Binding [Console.Split], Source={x:Static local:Localization.Instance}}"
FontSize="12"
Padding="10,4" Margin="0,0,8,0" />
<Button Grid.Column="4" x:Name="CopyLogButton" Classes="ghost"
Content="{Binding [Console.Copy], Source={x:Static local:Localization.Instance}}"
FontSize="12"
Padding="10,4" Margin="0,0,8,0" />
<Button Grid.Column="5" x:Name="ClearLogButton" Classes="ghost"
Content="{Binding [Console.Clear], Source={x:Static local:Localization.Instance}}"
FontSize="12"
Padding="10,4" Margin="0,0,8,0" />
<Button Grid.Column="6"
x:Name="CloseConsoleButton"
Classes="ghost"
Content="×"
AutomationProperties.Name="{Binding [Launch.Console],
Source={x:Static local:Localization.Instance}}"
FontSize="16"
Padding="10,2" />
</Grid>
<ListBox Grid.Row="1" x:Name="ConsoleList" Classes="console" BorderThickness="0,1,0,0"
BorderBrush="{StaticResource CardBorderBrush}" CornerRadius="0,0,12,12">
<ListBox.ItemTemplate>
<DataTemplate x:DataType="local:LogLine" x:CompileBindings="True">
<TextBlock Text="{Binding Text}" Foreground="{Binding Brush}" TextWrapping="NoWrap" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Border>
</Grid>
<!-- Portable resize hit targets for the frameless desktop window. They
are disabled while maximized or fullscreen in code-behind. -->
<Panel x:Name="ResizeHandles"
Grid.RowSpan="2"
ZIndex="1000"
IsVisible="False">
<Border Tag="North"
Height="6"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Background="#01000000"
Cursor="TopSide"
PointerPressed="OnResizeHandlePointerPressed" />
<Border Tag="South"
Height="6"
HorizontalAlignment="Stretch"
VerticalAlignment="Bottom"
Background="#01000000"
Cursor="BottomSide"
PointerPressed="OnResizeHandlePointerPressed" />
<Border Tag="West"
Width="6"
HorizontalAlignment="Left"
VerticalAlignment="Stretch"
Background="#01000000"
Cursor="LeftSide"
PointerPressed="OnResizeHandlePointerPressed" />
<Border Tag="East"
Width="6"
HorizontalAlignment="Right"
VerticalAlignment="Stretch"
Background="#01000000"
Cursor="RightSide"
PointerPressed="OnResizeHandlePointerPressed" />
<Border Tag="NorthWest"
Width="12"
Height="12"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Background="#01000000"
Cursor="TopLeftCorner"
PointerPressed="OnResizeHandlePointerPressed" />
<Border Tag="NorthEast"
Width="12"
Height="12"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Background="#01000000"
Cursor="TopRightCorner"
PointerPressed="OnResizeHandlePointerPressed" />
<Border Tag="SouthWest"
Width="12"
Height="12"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Background="#01000000"
Cursor="BottomLeftCorner"
PointerPressed="OnResizeHandlePointerPressed" />
<Border Tag="SouthEast"
Width="12"
Height="12"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Background="#01000000"
Cursor="BottomRightCorner"
PointerPressed="OnResizeHandlePointerPressed" />
</Panel>
</Grid>
</Window>