mirror of
https://github.com/par274/sharpemu.git
synced 2026-08-01 15:39:47 +08:00
[GUI] Add grid settings to GUI and implement grid snapping
This commit is contained in:
@@ -40,6 +40,8 @@ public sealed class GuiSettings
|
|||||||
/// <summary>Loop the selected game's sce_sys/snd0.at9 preview music.</summary>
|
/// <summary>Loop the selected game's sce_sys/snd0.at9 preview music.</summary>
|
||||||
public bool PlayTitleMusic { get; set; } = true;
|
public bool PlayTitleMusic { get; set; } = true;
|
||||||
|
|
||||||
|
public string LibraryLayout { get; set; } = "Carousel";
|
||||||
|
|
||||||
public string? EmulatorPath { get; set; }
|
public string? EmulatorPath { get; set; }
|
||||||
|
|
||||||
/// <summary>UI language, matching a file code under Languages/ (e.g. "en", "tr").</summary>
|
/// <summary>UI language, matching a file code under Languages/ (e.g. "en", "tr").</summary>
|
||||||
@@ -132,6 +134,7 @@ public sealed class GuiSettings
|
|||||||
{
|
{
|
||||||
settings.RenderResolutionScale = 1.0;
|
settings.RenderResolutionScale = 1.0;
|
||||||
}
|
}
|
||||||
|
settings.LibraryLayout = NormalizeChoice(settings.LibraryLayout, "Carousel", "Grid");
|
||||||
settings.WindowMode = NormalizeChoice(settings.WindowMode, "Windowed", "Borderless", "Exclusive");
|
settings.WindowMode = NormalizeChoice(settings.WindowMode, "Windowed", "Borderless", "Exclusive");
|
||||||
settings.Resolution = NormalizeResolution(settings.Resolution);
|
settings.Resolution = NormalizeResolution(settings.Resolution);
|
||||||
settings.ScalingMode = NormalizeChoice(settings.ScalingMode, "Fit", "Cover", "Stretch", "Integer");
|
settings.ScalingMode = NormalizeChoice(settings.ScalingMode, "Fit", "Cover", "Stretch", "Integer");
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
"Library.SearchWatermark": "Search library…",
|
"Library.SearchWatermark": "Search library…",
|
||||||
"Library.AddFolder": "Add folder",
|
"Library.AddFolder": "Add folder",
|
||||||
"Library.OpenFile": "Open file…",
|
"Library.OpenFile": "Open file…",
|
||||||
|
"Library.View.Grid": "Stacked view",
|
||||||
|
"Library.View.Carousel": "Row view",
|
||||||
|
|
||||||
"Library.Context.Launch": "Launch",
|
"Library.Context.Launch": "Launch",
|
||||||
"Library.Context.OpenFolder": "Open game folder",
|
"Library.Context.OpenFolder": "Open game folder",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
"Library.SearchWatermark": "Kütüphanede ara…",
|
"Library.SearchWatermark": "Kütüphanede ara…",
|
||||||
"Library.AddFolder": "Klasör ekle",
|
"Library.AddFolder": "Klasör ekle",
|
||||||
"Library.OpenFile": "Dosya aç…",
|
"Library.OpenFile": "Dosya aç…",
|
||||||
|
"Library.View.Grid": "Alt alta görünüm",
|
||||||
|
"Library.View.Carousel": "Tek sıra görünüm",
|
||||||
|
|
||||||
"Library.Context.Launch": "Başlat",
|
"Library.Context.Launch": "Başlat",
|
||||||
"Library.Context.OpenFolder": "Oyun klasörünü aç",
|
"Library.Context.OpenFolder": "Oyun klasörünü aç",
|
||||||
|
|||||||
@@ -476,18 +476,6 @@ public partial class MainWindow
|
|||||||
("SHARPEMU_GUEST_IMAGE_CPU_SYNC", GameEnvGuestImageCpuSyncToggle),
|
("SHARPEMU_GUEST_IMAGE_CPU_SYNC", GameEnvGuestImageCpuSyncToggle),
|
||||||
];
|
];
|
||||||
|
|
||||||
private static void SetGameOptionsOpenClass(Control control, bool active)
|
private static void SetGameOptionsOpenClass(Control control, bool active) =>
|
||||||
{
|
SetClass(control, "gameOptionsOpen", active);
|
||||||
if (active)
|
|
||||||
{
|
|
||||||
if (!control.Classes.Contains("gameOptionsOpen"))
|
|
||||||
{
|
|
||||||
control.Classes.Add("gameOptionsOpen");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
control.Classes.Remove("gameOptionsOpen");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,6 +136,13 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
|
|
||||||
<StackPanel Grid.Column="2" x:Name="LibraryToolbar" Orientation="Horizontal" Spacing="8"
|
<StackPanel Grid.Column="2" x:Name="LibraryToolbar" Orientation="Horizontal" Spacing="8"
|
||||||
VerticalAlignment="Center">
|
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"
|
<TextBox x:Name="SearchBox"
|
||||||
PlaceholderText="{Binding [Library.SearchWatermark], Source={x:Static local:Localization.Instance}}"
|
PlaceholderText="{Binding [Library.SearchWatermark], Source={x:Static local:Localization.Instance}}"
|
||||||
Width="240"
|
Width="240"
|
||||||
@@ -167,7 +174,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
</Transitions>
|
</Transitions>
|
||||||
</Panel.Transitions>
|
</Panel.Transitions>
|
||||||
<ListBox x:Name="GameList" Classes="tileGrid" Background="Transparent"
|
<ListBox x:Name="GameList" Classes="tileGrid" Background="Transparent"
|
||||||
SelectionMode="Single" Padding="4,0,28,0">
|
SelectionMode="Single">
|
||||||
<ListBox.ContextMenu>
|
<ListBox.ContextMenu>
|
||||||
<ContextMenu x:Name="GameContextMenu" Placement="Pointer">
|
<ContextMenu x:Name="GameContextMenu" Placement="Pointer">
|
||||||
<MenuItem x:Name="CtxLaunch"
|
<MenuItem x:Name="CtxLaunch"
|
||||||
@@ -218,32 +225,35 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
</ListBox.ContextMenu>
|
</ListBox.ContextMenu>
|
||||||
<ListBox.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<VirtualizingStackPanel Orientation="Horizontal" />
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</ListBox.ItemsPanel>
|
|
||||||
<ListBox.DataTemplates>
|
<ListBox.DataTemplates>
|
||||||
<DataTemplate x:DataType="local:GameEntry" x:CompileBindings="True">
|
<DataTemplate x:DataType="local:GameEntry" x:CompileBindings="True">
|
||||||
<Border Classes="coverShadow libraryGameCard"
|
<StackPanel Spacing="7">
|
||||||
Width="148"
|
<Border Classes="coverShadow libraryGameCard"
|
||||||
Height="148"
|
Width="148"
|
||||||
ToolTip.Tip="{Binding Name}"
|
Height="148"
|
||||||
AutomationProperties.Name="{Binding Name}">
|
ToolTip.Tip="{Binding Name}"
|
||||||
<Border Classes="coverClip">
|
AutomationProperties.Name="{Binding Name}">
|
||||||
<Panel>
|
<Border Classes="coverClip">
|
||||||
<Border Background="{Binding PlaceholderBrush}" IsVisible="{Binding !HasCover}">
|
<Panel>
|
||||||
<TextBlock Text="{Binding Initials}" FontSize="38" FontWeight="Light"
|
<Border Background="{Binding PlaceholderBrush}" IsVisible="{Binding !HasCover}">
|
||||||
Foreground="#C4E8ECF4"
|
<TextBlock Text="{Binding Initials}" FontSize="38" FontWeight="Light"
|
||||||
HorizontalAlignment="Center" VerticalAlignment="Center" />
|
Foreground="#C4E8ECF4"
|
||||||
</Border>
|
HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||||
<Image Source="{Binding Cover}"
|
</Border>
|
||||||
Stretch="UniformToFill"
|
<Image Source="{Binding Cover}"
|
||||||
RenderOptions.BitmapInterpolationMode="LowQuality"
|
Stretch="UniformToFill"
|
||||||
IsVisible="{Binding HasCover}" />
|
RenderOptions.BitmapInterpolationMode="LowQuality"
|
||||||
</Panel>
|
IsVisible="{Binding HasCover}" />
|
||||||
|
</Panel>
|
||||||
|
</Border>
|
||||||
</Border>
|
</Border>
|
||||||
</Border>
|
<TextBlock Classes="libraryTileName"
|
||||||
|
Text="{Binding Name}"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
MaxLines="2"
|
||||||
|
TextTrimming="CharacterEllipsis"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
</StackPanel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
<DataTemplate x:DataType="local:AddFolderTile">
|
<DataTemplate x:DataType="local:AddFolderTile">
|
||||||
<Border Classes="addFolderTile"
|
<Border Classes="addFolderTile"
|
||||||
@@ -292,8 +302,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
MaxWidth="980"
|
MaxWidth="980"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
Margin="4,8,0,0"
|
Margin="4,8,0,0">
|
||||||
Spacing="18">
|
|
||||||
<StackPanel.Transitions>
|
<StackPanel.Transitions>
|
||||||
<Transitions>
|
<Transitions>
|
||||||
<DoubleTransition Property="Opacity"
|
<DoubleTransition Property="Opacity"
|
||||||
@@ -302,8 +311,8 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
Duration="0:0:0.18" />
|
Duration="0:0:0.18" />
|
||||||
</Transitions>
|
</Transitions>
|
||||||
</StackPanel.Transitions>
|
</StackPanel.Transitions>
|
||||||
<TextBlock Text="{Binding Name}"
|
<TextBlock Classes="selectedGameTitle"
|
||||||
FontSize="42"
|
Text="{Binding Name}"
|
||||||
FontWeight="SemiBold"
|
FontWeight="SemiBold"
|
||||||
TextWrapping="Wrap"
|
TextWrapping="Wrap"
|
||||||
TextTrimming="CharacterEllipsis"
|
TextTrimming="CharacterEllipsis"
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ public partial class MainWindow : Window
|
|||||||
private bool _isClosing;
|
private bool _isClosing;
|
||||||
private bool _restoringGameSelection;
|
private bool _restoringGameSelection;
|
||||||
private bool _addFolderInProgress;
|
private bool _addFolderInProgress;
|
||||||
|
private bool _isLibraryGridLayout;
|
||||||
private GameEntry? _lastSelectedGame;
|
private GameEntry? _lastSelectedGame;
|
||||||
|
|
||||||
// Bundled key art shown whenever no game-specific backdrop applies; the
|
// Bundled key art shown whenever no game-specific backdrop applies; the
|
||||||
@@ -134,6 +135,8 @@ public partial class MainWindow : Window
|
|||||||
private HostGamepadButtons _previousPadButtons;
|
private HostGamepadButtons _previousPadButtons;
|
||||||
private long _navLeftNextAt;
|
private long _navLeftNextAt;
|
||||||
private long _navRightNextAt;
|
private long _navRightNextAt;
|
||||||
|
private long _navUpNextAt;
|
||||||
|
private long _navDownNextAt;
|
||||||
|
|
||||||
//Github http client for latest commit
|
//Github http client for latest commit
|
||||||
private static readonly HttpClient GithubHttpClient = CreateGithubHttpClient();
|
private static readonly HttpClient GithubHttpClient = CreateGithubHttpClient();
|
||||||
@@ -219,6 +222,9 @@ public partial class MainWindow : Window
|
|||||||
CloseConsoleButton.Click += (_, _) => ConsoleToggle.IsChecked = false;
|
CloseConsoleButton.Click += (_, _) => ConsoleToggle.IsChecked = false;
|
||||||
LibraryTabButton.Click += (_, _) => SetActivePage(0);
|
LibraryTabButton.Click += (_, _) => SetActivePage(0);
|
||||||
OptionsTabButton.Click += (_, _) => SetActivePage(1);
|
OptionsTabButton.Click += (_, _) => SetActivePage(1);
|
||||||
|
LibraryLayoutButton.Click += (_, _) => ToggleLibraryLayout();
|
||||||
|
LibraryPage.SizeChanged += (_, _) => UpdateLibraryGridHeight();
|
||||||
|
LibrarySelectedDetails.SizeChanged += (_, _) => UpdateLibraryGridHeight();
|
||||||
ConsoleToggle.IsCheckedChanged += (_, _) => ConsolePanel.IsVisible = ConsoleToggle.IsChecked == true && _consoleWindow is null;
|
ConsoleToggle.IsCheckedChanged += (_, _) => ConsolePanel.IsVisible = ConsoleToggle.IsChecked == true && _consoleWindow is null;
|
||||||
WireOptionsNavigation();
|
WireOptionsNavigation();
|
||||||
WireGameOptions();
|
WireGameOptions();
|
||||||
@@ -379,18 +385,73 @@ public partial class MainWindow : Window
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetActiveClass(Button button, bool active)
|
private void SetLibraryLayout(bool grid)
|
||||||
|
{
|
||||||
|
_isLibraryGridLayout = grid;
|
||||||
|
SetClass(GameList, "gridLayout", grid);
|
||||||
|
SetClass(LibrarySelectedDetails, "gridLayout", grid);
|
||||||
|
LibraryPage.RowDefinitions[0].Height = grid
|
||||||
|
? GridLength.Auto
|
||||||
|
: new GridLength(188);
|
||||||
|
LibraryPage.Margin = grid
|
||||||
|
? new Thickness(0, 6, 0, 0)
|
||||||
|
: new Thickness(0, 46, 0, 0);
|
||||||
|
UpdateLibraryGridHeight();
|
||||||
|
UpdateLibraryLayoutButton();
|
||||||
|
|
||||||
|
if (GameList.SelectedItem is { } selected)
|
||||||
|
{
|
||||||
|
Dispatcher.UIThread.Post(
|
||||||
|
() => GameList.ScrollIntoView(selected),
|
||||||
|
DispatcherPriority.Loaded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateLibraryGridHeight()
|
||||||
|
{
|
||||||
|
var pageHeight = LibraryPage.Bounds.Height;
|
||||||
|
if (!_isLibraryGridLayout || pageHeight <= 0)
|
||||||
|
{
|
||||||
|
GameList.MaxHeight = double.PositiveInfinity;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GameList.MaxHeight = Math.Max(
|
||||||
|
0,
|
||||||
|
pageHeight - LibrarySelectedDetails.DesiredSize.Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ToggleLibraryLayout()
|
||||||
|
{
|
||||||
|
SetLibraryLayout(!_isLibraryGridLayout);
|
||||||
|
_settings.LibraryLayout = _isLibraryGridLayout ? "Grid" : "Carousel";
|
||||||
|
_settings.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateLibraryLayoutButton()
|
||||||
|
{
|
||||||
|
LibraryLayoutGlyph.Text = _isLibraryGridLayout ? "view_carousel" : "grid_view";
|
||||||
|
var label = Localization.Instance.Get(
|
||||||
|
_isLibraryGridLayout ? "Library.View.Carousel" : "Library.View.Grid");
|
||||||
|
ToolTip.SetTip(LibraryLayoutButton, label);
|
||||||
|
AutomationProperties.SetName(LibraryLayoutButton, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetActiveClass(Button button, bool active) =>
|
||||||
|
SetClass(button, "active", active);
|
||||||
|
|
||||||
|
private static void SetClass(Control control, string className, bool active)
|
||||||
{
|
{
|
||||||
if (active)
|
if (active)
|
||||||
{
|
{
|
||||||
if (!button.Classes.Contains("active"))
|
if (!control.Classes.Contains(className))
|
||||||
{
|
{
|
||||||
button.Classes.Add("active");
|
control.Classes.Add(className);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
button.Classes.Remove("active");
|
control.Classes.Remove(className);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -676,6 +737,23 @@ public partial class MainWindow : Window
|
|||||||
MoveSelection(1);
|
MoveSelection(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_isLibraryGridLayout)
|
||||||
|
{
|
||||||
|
var up = (pad.Buttons & HostGamepadButtons.Up) != 0 || pad.LeftY < 64;
|
||||||
|
var down = (pad.Buttons & HostGamepadButtons.Down) != 0 || pad.LeftY > 192;
|
||||||
|
var rowStep = LibraryRowStep();
|
||||||
|
|
||||||
|
if (ShouldNavigate(up, ref _navUpNextAt, now))
|
||||||
|
{
|
||||||
|
MoveSelection(-rowStep);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ShouldNavigate(down, ref _navDownNextAt, now))
|
||||||
|
{
|
||||||
|
MoveSelection(rowStep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var pressed = pad.Buttons & ~_previousPadButtons;
|
var pressed = pad.Buttons & ~_previousPadButtons;
|
||||||
if ((pressed & HostGamepadButtons.Cross) != 0)
|
if ((pressed & HostGamepadButtons.Cross) != 0)
|
||||||
{
|
{
|
||||||
@@ -712,6 +790,29 @@ public partial class MainWindow : Window
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int LibraryRowStep()
|
||||||
|
{
|
||||||
|
if (GameList.ContainerFromIndex(0) is not { } first)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var top = first.Bounds.Top;
|
||||||
|
var columns = 1;
|
||||||
|
for (var index = 1; index < _libraryTiles.Count; index++)
|
||||||
|
{
|
||||||
|
if (GameList.ContainerFromIndex(index) is not { } container ||
|
||||||
|
Math.Abs(container.Bounds.Top - top) > 0.5)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
columns++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return columns;
|
||||||
|
}
|
||||||
|
|
||||||
private void MoveSelection(int delta)
|
private void MoveSelection(int delta)
|
||||||
{
|
{
|
||||||
var index = GameList.SelectedIndex < 0
|
var index = GameList.SelectedIndex < 0
|
||||||
@@ -783,6 +884,7 @@ public partial class MainWindow : Window
|
|||||||
RefreshHostRefreshRates(_settings.RefreshRate);
|
RefreshHostRefreshRates(_settings.RefreshRate);
|
||||||
RefreshUpdateText();
|
RefreshUpdateText();
|
||||||
UpdateEmptyStateTexts();
|
UpdateEmptyStateTexts();
|
||||||
|
UpdateLibraryLayoutButton();
|
||||||
UpdateRunButtons();
|
UpdateRunButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1067,6 +1169,7 @@ public partial class MainWindow : Window
|
|||||||
LogToFileToggle.IsChecked = _settings.LogToFile;
|
LogToFileToggle.IsChecked = _settings.LogToFile;
|
||||||
OverrideLogFileToggle.IsChecked = _settings.OverrideLogFile;
|
OverrideLogFileToggle.IsChecked = _settings.OverrideLogFile;
|
||||||
TitleMusicToggle.IsChecked = _settings.PlayTitleMusic;
|
TitleMusicToggle.IsChecked = _settings.PlayTitleMusic;
|
||||||
|
SetLibraryLayout(string.Equals(_settings.LibraryLayout, "Grid", StringComparison.OrdinalIgnoreCase));
|
||||||
DiscordToggle.IsChecked = _settings.DiscordRichPresence;
|
DiscordToggle.IsChecked = _settings.DiscordRichPresence;
|
||||||
AutoUpdateToggle.IsChecked = _settings.CheckForUpdatesOnStartup;
|
AutoUpdateToggle.IsChecked = _settings.CheckForUpdatesOnStartup;
|
||||||
EnvBthidToggle.IsChecked = _settings.EnvironmentToggles.Contains("SHARPEMU_BTHID_UNAVAILABLE");
|
EnvBthidToggle.IsChecked = _settings.EnvironmentToggles.Contains("SHARPEMU_BTHID_UNAVAILABLE");
|
||||||
|
|||||||
@@ -43,6 +43,23 @@ Shared launcher button variants and page switcher styles.
|
|||||||
<Setter Property="Foreground" Value="{StaticResource TextBrush}" />
|
<Setter Property="Foreground" Value="{StaticResource TextBrush}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="Button.iconGhost">
|
||||||
|
<Setter Property="Width" Value="32" />
|
||||||
|
<Setter Property="Height" Value="32" />
|
||||||
|
<Setter Property="Padding" Value="0" />
|
||||||
|
<Setter Property="Background" Value="Transparent" />
|
||||||
|
<Setter Property="BorderBrush" Value="{StaticResource CardBorderBrush}" />
|
||||||
|
<Setter Property="BorderThickness" Value="1" />
|
||||||
|
<Setter Property="Foreground" Value="{StaticResource TextBrush}" />
|
||||||
|
<Setter Property="CornerRadius" Value="8" />
|
||||||
|
<Setter Property="HorizontalContentAlignment" Value="Center" />
|
||||||
|
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="Button.iconGhost:pointerover /template/ ContentPresenter#PART_ContentPresenter">
|
||||||
|
<Setter Property="Background" Value="{StaticResource ElevatedBrush}" />
|
||||||
|
<Setter Property="Foreground" Value="{StaticResource TextBrush}" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
<Style Selector="ToggleButton.ghost">
|
<Style Selector="ToggleButton.ghost">
|
||||||
<Setter Property="Background" Value="Transparent" />
|
<Setter Property="Background" Value="Transparent" />
|
||||||
<Setter Property="BorderBrush" Value="{StaticResource CardBorderBrush}" />
|
<Setter Property="BorderBrush" Value="{StaticResource CardBorderBrush}" />
|
||||||
|
|||||||
@@ -103,6 +103,36 @@ Contextual per-game options reveal, actions, and selected-game motion.
|
|||||||
<Setter Property="Foreground" Value="White" />
|
<Setter Property="Foreground" Value="White" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="StackPanel.selectedDetailsHost">
|
||||||
|
<Setter Property="Spacing" Value="18" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="TextBlock.selectedGameTitle">
|
||||||
|
<Setter Property="FontSize" Value="42" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="StackPanel.selectedDetailsHost.gridLayout">
|
||||||
|
<Setter Property="Spacing" Value="12" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="StackPanel.selectedDetailsHost.gridLayout TextBlock.selectedGameTitle">
|
||||||
|
<Setter Property="FontSize" Value="26" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="StackPanel.selectedDetailsHost.gridLayout Button.playButton">
|
||||||
|
<Setter Property="MinHeight" Value="44" />
|
||||||
|
<Setter Property="MinWidth" Value="168" />
|
||||||
|
<Setter Property="Padding" Value="28,10" />
|
||||||
|
<Setter Property="FontSize" Value="15" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="StackPanel.selectedDetailsHost.gridLayout Button.optionsCircle,
|
||||||
|
StackPanel.selectedDetailsHost.gridLayout ToggleButton.optionsCircle">
|
||||||
|
<Setter Property="Width" Value="44" />
|
||||||
|
<Setter Property="Height" Value="44" />
|
||||||
|
<Setter Property="CornerRadius" Value="22" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
<Style Selector="Button.gameOptionsLaunch">
|
<Style Selector="Button.gameOptionsLaunch">
|
||||||
<Setter Property="Width" Value="220" />
|
<Setter Property="Width" Value="220" />
|
||||||
<Setter Property="Height" Value="46" />
|
<Setter Property="Height" Value="46" />
|
||||||
|
|||||||
@@ -9,8 +9,25 @@ Cover-art library item states and motion.
|
|||||||
<Style Selector="ListBox.tileGrid">
|
<Style Selector="ListBox.tileGrid">
|
||||||
<Setter Property="Background" Value="Transparent" />
|
<Setter Property="Background" Value="Transparent" />
|
||||||
<Setter Property="BorderThickness" Value="0" />
|
<Setter Property="BorderThickness" Value="0" />
|
||||||
|
<Setter Property="Padding" Value="4,0,28,0" />
|
||||||
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden" />
|
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden" />
|
||||||
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Disabled" />
|
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Disabled" />
|
||||||
|
<Setter Property="ItemsPanel">
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<VirtualizingStackPanel Orientation="Horizontal" />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="ListBox.tileGrid.gridLayout">
|
||||||
|
<Setter Property="Padding" Value="4,0,14,0" />
|
||||||
|
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
|
||||||
|
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
|
||||||
|
<Setter Property="ItemsPanel">
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<WrapPanel />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="ListBox.tileGrid ListBoxItem">
|
<Style Selector="ListBox.tileGrid ListBoxItem">
|
||||||
<Setter Property="Width" Value="160" />
|
<Setter Property="Width" Value="160" />
|
||||||
@@ -35,6 +52,25 @@ Cover-art library item states and motion.
|
|||||||
</Transitions>
|
</Transitions>
|
||||||
</Setter>
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
|
<!-- The title rides along in the item template so both layouts share one
|
||||||
|
template. The rail hides it because the selected game already names
|
||||||
|
itself in the details below the covers. -->
|
||||||
|
<Style Selector="TextBlock.libraryTileName">
|
||||||
|
<Setter Property="IsVisible" Value="False" />
|
||||||
|
<Setter Property="FontSize" Value="12" />
|
||||||
|
<Setter Property="FontWeight" Value="SemiBold" />
|
||||||
|
<Setter Property="LineHeight" Value="16" />
|
||||||
|
<Setter Property="Foreground" Value="{StaticResource TextBrush}" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ListBox.tileGrid.gridLayout TextBlock.libraryTileName">
|
||||||
|
<Setter Property="IsVisible" Value="True" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ListBox.tileGrid.gridLayout ListBoxItem">
|
||||||
|
<Setter Property="Height" Value="200" />
|
||||||
|
<Setter Property="Margin" Value="0,6,12,10" />
|
||||||
|
<Setter Property="VerticalContentAlignment" Value="Top" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
<Style Selector="ListBox.tileGrid ListBoxItem:pointerover,
|
<Style Selector="ListBox.tileGrid ListBoxItem:pointerover,
|
||||||
ListBox.tileGrid ListBoxItem:selected">
|
ListBox.tileGrid ListBoxItem:selected">
|
||||||
<Setter Property="Opacity" Value="1" />
|
<Setter Property="Opacity" Value="1" />
|
||||||
|
|||||||
@@ -61,6 +61,19 @@ public sealed class GuiSettingsTests
|
|||||||
Assert.Equal(1000, settings.RefreshRate);
|
Assert.Equal(1000, settings.RefreshRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("""{ }""", "Carousel")]
|
||||||
|
[InlineData("""{ "LibraryLayout": null }""", "Carousel")]
|
||||||
|
[InlineData("""{ "LibraryLayout": "sideways" }""", "Carousel")]
|
||||||
|
[InlineData("""{ "LibraryLayout": "grid" }""", "Grid")]
|
||||||
|
[InlineData("""{ "LibraryLayout": "Grid" }""", "Grid")]
|
||||||
|
public void NormalizeFromJson_LibraryLayout_FallsBackToCarousel(string json, string expected)
|
||||||
|
{
|
||||||
|
var settings = GuiSettings.NormalizeFromJson(json);
|
||||||
|
|
||||||
|
Assert.Equal(expected, settings.LibraryLayout);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void NormalizeFromJson_CustomResolution_IsPreserved()
|
public void NormalizeFromJson_CustomResolution_IsPreserved()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user