[GUI] Add grid settings to GUI and implement grid snapping

This commit is contained in:
ParantezTech
2026-07-31 13:20:14 +03:00
parent 544f588cfd
commit e28069c7e3
10 changed files with 249 additions and 46 deletions
+107 -4
View File
@@ -123,6 +123,7 @@ public partial class MainWindow : Window
private bool _isClosing;
private bool _restoringGameSelection;
private bool _addFolderInProgress;
private bool _isLibraryGridLayout;
private GameEntry? _lastSelectedGame;
// Bundled key art shown whenever no game-specific backdrop applies; the
@@ -134,6 +135,8 @@ public partial class MainWindow : Window
private HostGamepadButtons _previousPadButtons;
private long _navLeftNextAt;
private long _navRightNextAt;
private long _navUpNextAt;
private long _navDownNextAt;
//Github http client for latest commit
private static readonly HttpClient GithubHttpClient = CreateGithubHttpClient();
@@ -219,6 +222,9 @@ public partial class MainWindow : Window
CloseConsoleButton.Click += (_, _) => ConsoleToggle.IsChecked = false;
LibraryTabButton.Click += (_, _) => SetActivePage(0);
OptionsTabButton.Click += (_, _) => SetActivePage(1);
LibraryLayoutButton.Click += (_, _) => ToggleLibraryLayout();
LibraryPage.SizeChanged += (_, _) => UpdateLibraryGridHeight();
LibrarySelectedDetails.SizeChanged += (_, _) => UpdateLibraryGridHeight();
ConsoleToggle.IsCheckedChanged += (_, _) => ConsolePanel.IsVisible = ConsoleToggle.IsChecked == true && _consoleWindow is null;
WireOptionsNavigation();
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 (!button.Classes.Contains("active"))
if (!control.Classes.Contains(className))
{
button.Classes.Add("active");
control.Classes.Add(className);
}
}
else
{
button.Classes.Remove("active");
control.Classes.Remove(className);
}
}
@@ -676,6 +737,23 @@ public partial class MainWindow : Window
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;
if ((pressed & HostGamepadButtons.Cross) != 0)
{
@@ -712,6 +790,29 @@ public partial class MainWindow : Window
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)
{
var index = GameList.SelectedIndex < 0
@@ -783,6 +884,7 @@ public partial class MainWindow : Window
RefreshHostRefreshRates(_settings.RefreshRate);
RefreshUpdateText();
UpdateEmptyStateTexts();
UpdateLibraryLayoutButton();
UpdateRunButtons();
}
@@ -1067,6 +1169,7 @@ public partial class MainWindow : Window
LogToFileToggle.IsChecked = _settings.LogToFile;
OverrideLogFileToggle.IsChecked = _settings.OverrideLogFile;
TitleMusicToggle.IsChecked = _settings.PlayTitleMusic;
SetLibraryLayout(string.Equals(_settings.LibraryLayout, "Grid", StringComparison.OrdinalIgnoreCase));
DiscordToggle.IsChecked = _settings.DiscordRichPresence;
AutoUpdateToggle.IsChecked = _settings.CheckForUpdatesOnStartup;
EnvBthidToggle.IsChecked = _settings.EnvironmentToggles.Contains("SHARPEMU_BTHID_UNAVAILABLE");