[GUI] Add inline per-game settings and unify options styling (#728)

* [GUI] Add inline per-game settings and unify options styling

* [GUI] Update options styling & add scrollable area

* [GUI] Remove focus and pointover styles for options
This commit is contained in:
Daniel Freak
2026-07-31 12:14:21 +03:00
committed by GitHub
parent 97bd8c422e
commit a7ec3d5a77
28 changed files with 1782 additions and 772 deletions
+646 -54
View File
@@ -26,11 +26,22 @@ SPDX-License-Identifier: GPL-2.0-or-later
</DataTemplate>
</Window.Resources>
<Grid x:Name="RootLayout" RowDefinitions="Auto,*,Auto">
<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 Grid.Row="1" ClipToBounds="True">
<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>
@@ -42,16 +53,15 @@ SPDX-License-Identifier: GPL-2.0-or-later
<Border>
<Border.Background>
<LinearGradientBrush StartPoint="0%,0%" EndPoint="0%,100%">
<GradientStop Offset="0" Color="#730D1017" />
<GradientStop Offset="0.55" Color="#BF0D1017" />
<GradientStop Offset="1" Color="#EB0D1017" />
<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) along with the status bar, so
the game gets the whole screen. -->
<!-- Title bar; hidden in fullscreen (F11) so the game gets the whole screen. -->
<Grid x:Name="TitleBar"
Grid.Row="0"
Height="44"
@@ -96,6 +106,13 @@ SPDX-License-Identifier: GPL-2.0-or-later
<!-- 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
@@ -135,9 +152,22 @@ SPDX-License-Identifier: GPL-2.0-or-later
<!-- 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,*">
<ListBox x:Name="GameList" Classes="tileGrid" Background="Transparent"
Grid.Row="0"
SelectionMode="Single" Padding="4,0,28,0">
<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" Padding="4,0,28,0">
<ListBox.ContextMenu>
<ContextMenu x:Name="GameContextMenu" Placement="Pointer">
<MenuItem x:Name="CtxLaunch"
@@ -248,12 +278,14 @@ SPDX-License-Identifier: GPL-2.0-or-later
</Border>
</DataTemplate>
</ListBox.DataTemplates>
</ListBox>
</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"
@@ -262,6 +294,14 @@ SPDX-License-Identifier: GPL-2.0-or-later
VerticalAlignment="Top"
Margin="4,8,0,0"
Spacing="18">
<StackPanel.Transitions>
<Transitions>
<DoubleTransition Property="Opacity"
Duration="0:0:0.16" />
<TransformOperationsTransition Property="RenderTransform"
Duration="0:0:0.18" />
</Transitions>
</StackPanel.Transitions>
<TextBlock Text="{Binding Name}"
FontSize="42"
FontWeight="SemiBold"
@@ -282,25 +322,36 @@ SPDX-License-Identifier: GPL-2.0-or-later
Foreground="{StaticResource MutedBrush}" />
</Border>
</StackPanel>
<Grid Width="360"
ColumnDefinitions="*,*"
ColumnSpacing="8"
HorizontalAlignment="Left">
<StackPanel Orientation="Horizontal"
Spacing="12"
HorizontalAlignment="Left">
<Button x:Name="LaunchButton"
Grid.Column="0"
Classes="accent"
Classes="playButton"
Content="Launch"
HorizontalAlignment="Stretch"
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"
Grid.Column="1"
Classes="ghost"
Padding="22,10"
HorizontalAlignment="Stretch"
Content="{Binding [Launch.Console],
Source={x:Static local:Localization.Instance},
x:CompileBindings=False}" />
</Grid>
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 -->
@@ -328,6 +379,569 @@ SPDX-License-Identifier: GPL-2.0-or-later
</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"
@@ -343,19 +957,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
Classes="optionsNavIndicator"
Height="54"
VerticalAlignment="Top"
IsHitTestVisible="False">
<Border.RenderTransform>
<TranslateTransform>
<TranslateTransform.Transitions>
<Transitions>
<DoubleTransition Property="Y"
Duration="0:0:0.16"
Easing="CubicEaseOut" />
</Transitions>
</TranslateTransform.Transitions>
</TranslateTransform>
</Border.RenderTransform>
</Border>
IsHitTestVisible="False" />
<StackPanel>
<Button x:Name="OptionsGeneralNav" Classes="optionsNav active">
@@ -595,7 +1197,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
<TextBlock x:Name="LatestCommitDescription"
Text="{Binding [About.Github.LatestCommitDescription], Source={x:Static local:Localization.Instance}}"
FontSize="11"
Foreground="{StaticResource MutedBrush}"
Foreground="{StaticResource SettingsDescriptionBrush}"
TextWrapping="Wrap" />
</StackPanel>
<Button Grid.Column="1"
@@ -620,7 +1222,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
<TextBlock x:Name="UpdateStatusText"
Text="Current build: dev"
FontSize="11"
Foreground="{StaticResource MutedBrush}"
Foreground="{StaticResource SettingsDescriptionBrush}"
TextWrapping="Wrap" />
</StackPanel>
<Button Grid.Column="1"
@@ -642,7 +1244,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
<TextBlock x:Name="GithubDesc"
Text="{Binding [About.Github.Desc], Source={x:Static local:Localization.Instance}}"
FontSize="11"
Foreground="{StaticResource MutedBrush}"
Foreground="{StaticResource SettingsDescriptionBrush}"
TextWrapping="Wrap" />
</StackPanel>
<Button Grid.Column="1"
@@ -664,7 +1266,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
<TextBlock x:Name="DiscordServerDesc"
Text="{Binding [About.Discord.Desc], Source={x:Static local:Localization.Instance}}"
FontSize="11"
Foreground="{StaticResource MutedBrush}"
Foreground="{StaticResource SettingsDescriptionBrush}"
TextWrapping="Wrap" />
</StackPanel>
<TextBlock Grid.Column="1"
@@ -877,20 +1479,10 @@ SPDX-License-Identifier: GPL-2.0-or-later
</Grid>
<!-- Status bar -->
<Grid x:Name="StatusBar" Grid.Row="2" Height="32" Background="{StaticResource ChromeBrush}"
ColumnDefinitions="*,Auto">
<TextBlock x:Name="EmulatorPathText" Grid.Column="0" Text="Emulator: locating…" FontSize="11"
Foreground="{StaticResource FaintBrush}" VerticalAlignment="Center" Margin="16,0"
TextTrimming="CharacterEllipsis" />
<TextBlock x:Name="StatusBarRight" Grid.Column="1" Text="" FontSize="11"
Foreground="{StaticResource FaintBrush}" VerticalAlignment="Center" Margin="16,0" />
</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="3"
Grid.RowSpan="2"
ZIndex="1000"
IsVisible="False">
<Border Tag="North"