mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-31 06:59:45 +08:00
[GUI] Update library page layout (#690)
* [GUI] Add horizontal game tiles * [GUI] Update launching elements layout * [GUI] Change cards format to squares
This commit is contained in:
@@ -33,8 +33,6 @@ public partial class MainWindow : Window
|
||||
{
|
||||
private const int MaxConsoleLines = 4000;
|
||||
private const int MaxConsoleLinesPerFlush = 500;
|
||||
private const double LaunchBlurRadius = 12;
|
||||
private const double BlurTransitionSeconds = 0.24;
|
||||
|
||||
private static readonly IBrush DefaultLineBrush = new SolidColorBrush(Color.Parse("#C7CFDE"));
|
||||
private static readonly IBrush DimLineBrush = new SolidColorBrush(Color.Parse("#6B7488"));
|
||||
@@ -83,17 +81,12 @@ public partial class MainWindow : Window
|
||||
];
|
||||
private readonly List<GameEntry> _allGames = new();
|
||||
private readonly ObservableCollection<GameEntry> _visibleGames = new();
|
||||
private readonly LibraryTileCollection _libraryTiles;
|
||||
private readonly GameLibraryWatcher _libraryWatcher = new();
|
||||
private readonly AvaloniaList<LogLine> _consoleLines = new();
|
||||
private readonly List<LogLine> _allConsoleLines = new();
|
||||
private readonly ConcurrentQueue<(string Line, bool IsError)> _pendingLines = new();
|
||||
private readonly DispatcherTimer _consoleFlushTimer;
|
||||
private readonly DispatcherTimer _libraryBlurTimer;
|
||||
private BlurEffect? _libraryBlur;
|
||||
private double _libraryBlurStartRadius;
|
||||
private double _libraryBlurTargetRadius;
|
||||
private long _libraryBlurStartedAt;
|
||||
private bool _clearLibraryBlurWhenComplete;
|
||||
|
||||
private GuiSettings _settings = new();
|
||||
private IReadOnlyList<HostDisplayOption> _hostDisplays = [];
|
||||
@@ -123,23 +116,19 @@ public partial class MainWindow : Window
|
||||
private int _detailLoadGeneration;
|
||||
private int _backdropGeneration;
|
||||
private bool _isClosing;
|
||||
private bool _restoringGameSelection;
|
||||
private bool _addFolderInProgress;
|
||||
private GameEntry? _lastSelectedGame;
|
||||
|
||||
// Bundled key art shown whenever no game-specific backdrop applies; the
|
||||
// plain window color remains the fallback when the asset fails to load.
|
||||
private Bitmap? _defaultBackdrop;
|
||||
|
||||
// Whether the native loading/closing popup should be showing; it is a
|
||||
// desktop-topmost popup, so it closes while the launcher is in the
|
||||
// background or minimized and reopens from this flag on activation.
|
||||
private bool _sessionLoadingActive;
|
||||
|
||||
// Controller navigation state.
|
||||
private readonly DispatcherTimer _gamepadTimer;
|
||||
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();
|
||||
@@ -156,6 +145,7 @@ public partial class MainWindow : Window
|
||||
{
|
||||
InitializeComponent();
|
||||
InitializeLocalizedChoiceBoxes();
|
||||
_libraryTiles = new LibraryTileCollection(_visibleGames);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -169,7 +159,7 @@ public partial class MainWindow : Window
|
||||
_defaultBackdrop = null; // color background remains the fallback
|
||||
}
|
||||
|
||||
GameList.ItemsSource = _visibleGames;
|
||||
GameList.ItemsSource = _libraryTiles;
|
||||
_libraryWatcher.RefreshRequested += OnLibraryRefreshRequested;
|
||||
ConsoleList.ItemsSource = _consoleLines;
|
||||
_consoleMirror = GuiConsoleMirror.Install((line, isError) =>
|
||||
@@ -187,23 +177,6 @@ public partial class MainWindow : Window
|
||||
};
|
||||
_consoleFlushTimer.Start();
|
||||
|
||||
_libraryBlurTimer = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromMilliseconds(16),
|
||||
};
|
||||
_libraryBlurTimer.Tick += (_, _) => AdvanceLibraryBlur();
|
||||
|
||||
// Native popups float above every window on the desktop; they must
|
||||
// follow the launcher into the background or a minimized state.
|
||||
Activated += (_, _) =>
|
||||
{
|
||||
SessionLoadingPopup.IsOpen = _sessionLoadingActive;
|
||||
};
|
||||
Deactivated += (_, _) =>
|
||||
{
|
||||
SessionLoadingPopup.IsOpen = false;
|
||||
};
|
||||
|
||||
TitleBar.PointerPressed += OnTitleBarPointerPressed;
|
||||
TitleBar.DoubleTapped += OnTitleBarDoubleTapped;
|
||||
MinimizeButton.Click += (_, _) => WindowState = WindowState.Minimized;
|
||||
@@ -221,18 +194,26 @@ public partial class MainWindow : Window
|
||||
UpdateWindowChromeState();
|
||||
};
|
||||
UpdateWindowChromeState();
|
||||
GameList.SelectionChanged += (_, _) => UpdateSelectedGame();
|
||||
GameList.DoubleTapped += (_, _) => LaunchSelected();
|
||||
GameList.SelectionChanged += (_, _) => OnGameListSelectionChanged();
|
||||
GameList.DoubleTapped += OnGameListDoubleTapped;
|
||||
SearchBox.TextChanged += (_, _) => RefreshVisibleGames();
|
||||
ConsoleSearchBox.TextChanged += (_, _) => RefreshVisibleConsoleLines();
|
||||
AddFolderButton.Click += async (_, _) => await AddFolderAsync();
|
||||
EmptyAddFolderButton.Click += async (_, _) => await AddFolderAsync();
|
||||
OpenFileButton.Click += async (_, _) => await OpenFileAsync();
|
||||
LaunchButton.Click += (_, _) => LaunchSelected();
|
||||
LaunchButton.Click += (_, _) =>
|
||||
{
|
||||
if (_isRunning)
|
||||
{
|
||||
StopEmulator();
|
||||
}
|
||||
else
|
||||
{
|
||||
LaunchSelected();
|
||||
}
|
||||
};
|
||||
ClearLogButton.Click += (_, _) => { _consoleLines.Clear(); _allConsoleLines.Clear(); };
|
||||
StopButton.Click += (_, _) => StopEmulator();
|
||||
CopyLogButton.Click += async (_, _) => await CopyConsoleAsync();
|
||||
DetachConsoleButton.Click += (_, _) => ShowConsoleWindow();
|
||||
CloseConsoleButton.Click += (_, _) => ConsoleToggle.IsChecked = false;
|
||||
LibraryTabButton.Click += (_, _) => SetActivePage(0);
|
||||
OptionsTabButton.Click += (_, _) => SetActivePage(1);
|
||||
ConsoleToggle.IsCheckedChanged += (_, _) => ConsolePanel.IsVisible = ConsoleToggle.IsChecked == true && _consoleWindow is null;
|
||||
@@ -520,8 +501,6 @@ public partial class MainWindow : Window
|
||||
var now = Environment.TickCount64;
|
||||
var left = (pad.Buttons & HostGamepadButtons.Left) != 0 || pad.LeftX < 64;
|
||||
var right = (pad.Buttons & HostGamepadButtons.Right) != 0 || pad.LeftX > 192;
|
||||
var up = (pad.Buttons & HostGamepadButtons.Up) != 0 || pad.LeftY < 64;
|
||||
var down = (pad.Buttons & HostGamepadButtons.Down) != 0 || pad.LeftY > 192;
|
||||
|
||||
if (ShouldNavigate(left, ref _navLeftNextAt, now))
|
||||
{
|
||||
@@ -533,16 +512,6 @@ public partial class MainWindow : Window
|
||||
MoveSelection(1);
|
||||
}
|
||||
|
||||
if (ShouldNavigate(up, ref _navUpNextAt, now))
|
||||
{
|
||||
MoveSelection(-TilesPerRow());
|
||||
}
|
||||
|
||||
if (ShouldNavigate(down, ref _navDownNextAt, now))
|
||||
{
|
||||
MoveSelection(TilesPerRow());
|
||||
}
|
||||
|
||||
var pressed = pad.Buttons & ~_previousPadButtons;
|
||||
if ((pressed & HostGamepadButtons.Cross) != 0)
|
||||
{
|
||||
@@ -581,26 +550,13 @@ public partial class MainWindow : Window
|
||||
|
||||
private void MoveSelection(int delta)
|
||||
{
|
||||
if (_visibleGames.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var index = GameList.SelectedIndex < 0
|
||||
? 0
|
||||
: Math.Clamp(GameList.SelectedIndex + delta, 0, _visibleGames.Count - 1);
|
||||
: Math.Clamp(GameList.SelectedIndex + delta, 0, _libraryTiles.Count - 1);
|
||||
GameList.SelectedIndex = index;
|
||||
GameList.ScrollIntoView(index);
|
||||
}
|
||||
|
||||
private int TilesPerRow()
|
||||
{
|
||||
// Tile footprint: 128 content + 20 item padding + 10 item margin.
|
||||
const double TileOuterWidth = 158;
|
||||
var width = GameList.Bounds.Width;
|
||||
return width > TileOuterWidth ? (int)(width / TileOuterWidth) : 1;
|
||||
}
|
||||
|
||||
private async Task OnOpenedAsync()
|
||||
{
|
||||
var version = Assembly.GetExecutingAssembly().GetName().Version;
|
||||
@@ -662,7 +618,7 @@ public partial class MainWindow : Window
|
||||
RefreshHostRefreshRates(_settings.RefreshRate);
|
||||
RefreshUpdateText();
|
||||
UpdateEmptyStateTexts();
|
||||
UpdateSelectedGameTexts();
|
||||
UpdateRunButtons();
|
||||
}
|
||||
|
||||
// ---- Discord Rich Presence ----
|
||||
@@ -730,7 +686,6 @@ public partial class MainWindow : Window
|
||||
_libraryWatcher.Dispose();
|
||||
_settings.Save();
|
||||
_consoleFlushTimer.Stop();
|
||||
_libraryBlurTimer.Stop();
|
||||
_gamepadTimer.Stop();
|
||||
SdlLauncherGamepad.Shutdown();
|
||||
_sndPreview.Stop();
|
||||
@@ -1605,6 +1560,71 @@ public partial class MainWindow : Window
|
||||
|
||||
// ---- Game context menu ----
|
||||
|
||||
private void OnGameListSelectionChanged()
|
||||
{
|
||||
if (_restoringGameSelection)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (GameList.SelectedItem is AddFolderTile)
|
||||
{
|
||||
_restoringGameSelection = true;
|
||||
try
|
||||
{
|
||||
GameList.SelectedItem = _lastSelectedGame;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_restoringGameSelection = false;
|
||||
}
|
||||
|
||||
// A held direction must not reopen the picker after it closes.
|
||||
_navLeftNextAt = long.MaxValue;
|
||||
_navRightNextAt = long.MaxValue;
|
||||
StartAddFolderFromTile();
|
||||
return;
|
||||
}
|
||||
|
||||
_lastSelectedGame = GameList.SelectedItem as GameEntry;
|
||||
UpdateSelectedGame();
|
||||
}
|
||||
|
||||
private void OnGameListDoubleTapped(object? sender, TappedEventArgs e)
|
||||
{
|
||||
var item = (e.Source as Visual)?.FindAncestorOfType<ListBoxItem>(includeSelf: true);
|
||||
if (item?.DataContext is AddFolderTile)
|
||||
{
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
LaunchSelected();
|
||||
}
|
||||
|
||||
private void StartAddFolderFromTile()
|
||||
{
|
||||
if (_addFolderInProgress)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_addFolderInProgress = true;
|
||||
_ = AddFolderFromTileAsync();
|
||||
}
|
||||
|
||||
private async Task AddFolderFromTileAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await AddFolderAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_addFolderInProgress = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects the tile under the pointer before its context menu opens, and
|
||||
/// suppresses the menu on empty grid space.
|
||||
@@ -1746,7 +1766,6 @@ public partial class MainWindow : Window
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateSelectedGameTexts();
|
||||
UpdateRunButtons();
|
||||
if (selectedAfter is not null && backgroundsChanged?.Contains(selectedAfter) == true)
|
||||
{
|
||||
@@ -1774,26 +1793,21 @@ public partial class MainWindow : Window
|
||||
EmptyStateHint.Text = hasFilter
|
||||
? Localization.Instance.Format("Library.Empty.SearchHint", query)
|
||||
: Localization.Instance.Get("Library.Empty.Hint");
|
||||
EmptyAddFolderButton.IsVisible = !hasFilter;
|
||||
}
|
||||
|
||||
private void UpdateSelectedGame()
|
||||
{
|
||||
if (GameList.SelectedItem is GameEntry game)
|
||||
{
|
||||
UpdateSelectedGameTexts();
|
||||
SelectedCoverPanel.DataContext = game;
|
||||
SelectedBadgesRow.DataContext = game;
|
||||
SelectedBadgesRow.IsVisible = true;
|
||||
LibrarySelectedDetails.DataContext = game;
|
||||
LibrarySelectedDetails.IsVisible = true;
|
||||
_ = UpdateBackdropAsync(game);
|
||||
PlaySelectedGamePreview(game);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateSelectedGameTexts();
|
||||
SelectedCoverPanel.DataContext = null;
|
||||
SelectedBadgesRow.DataContext = null;
|
||||
SelectedBadgesRow.IsVisible = false;
|
||||
LibrarySelectedDetails.DataContext = null;
|
||||
LibrarySelectedDetails.IsVisible = false;
|
||||
_ = UpdateBackdropAsync(null);
|
||||
_sndPreview.Stop();
|
||||
}
|
||||
@@ -1801,25 +1815,6 @@ public partial class MainWindow : Window
|
||||
UpdateRunButtons();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Text-only refresh of the launch bar's title/path, split out of
|
||||
/// <see cref="UpdateSelectedGame"/> so a language change can re-apply it
|
||||
/// without restarting the backdrop fade or preview music.
|
||||
/// </summary>
|
||||
private void UpdateSelectedGameTexts()
|
||||
{
|
||||
if (GameList.SelectedItem is GameEntry game)
|
||||
{
|
||||
SelectedGameTitle.Text = game.Name;
|
||||
SelectedGamePath.Text = game.Path;
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedGameTitle.Text = Localization.Instance.Get("Launch.NoGameSelected");
|
||||
SelectedGamePath.Text = Localization.Instance.Get("Launch.NoGameHint");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loops the selected game's sce_sys/snd0.at9 preview music, console
|
||||
/// home screen style. Silent while a game is running or when disabled
|
||||
@@ -1869,18 +1864,10 @@ public partial class MainWindow : Window
|
||||
if (WindowState == WindowState.Minimized)
|
||||
{
|
||||
_sndPreview.Pause();
|
||||
if (SessionLoadingPopup is { } popup)
|
||||
{
|
||||
popup.IsOpen = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_sndPreview.Resume();
|
||||
if (SessionLoadingPopup is { } popup)
|
||||
{
|
||||
popup.IsOpen = _sessionLoadingActive;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2044,16 +2031,14 @@ public partial class MainWindow : Window
|
||||
};
|
||||
|
||||
_isRunning = true;
|
||||
_isStopping = false;
|
||||
_runningGameName = displayName;
|
||||
_runningGameTitleId = resolvedTitleId;
|
||||
_runningSinceUnixSeconds = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
StatusDot.Fill = SuccessLineBrush;
|
||||
StatusText.Text = Localization.Instance.Format("Launch.Running", displayName);
|
||||
StatusBarRight.Text = Localization.Instance.Format("Status.Running", displayName);
|
||||
UpdateRunButtons();
|
||||
UpdateDiscordPresence();
|
||||
|
||||
BeginSessionUi();
|
||||
_pendingLaunch = new PendingLaunch(
|
||||
Path.GetFullPath(ebootPath),
|
||||
displayName,
|
||||
@@ -2099,15 +2084,14 @@ public partial class MainWindow : Window
|
||||
}
|
||||
|
||||
_isStopping = true;
|
||||
StopButton.IsEnabled = false;
|
||||
ShowSessionLoading("Closing game", "Waiting for the emulation session to exit...");
|
||||
UpdateRunButtons();
|
||||
_emulator.Stop();
|
||||
_runningGameName = null;
|
||||
_runningGameTitleId = null;
|
||||
StatusText.Text = Localization.Instance.Get("Launch.Stopping");
|
||||
StatusBarRight.Text = Localization.Instance.Get("Status.Stopping");
|
||||
UpdateDiscordPresence();
|
||||
ReturnToLibraryWhileStopping();
|
||||
ConsolePanel.IsVisible = ConsoleToggle.IsChecked == true && _consoleWindow is null;
|
||||
Console.Error.WriteLine("[GUI][INFO] Waiting for the SDL game process to exit.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -2149,7 +2133,7 @@ public partial class MainWindow : Window
|
||||
_emulator?.Dispose();
|
||||
_emulator = null;
|
||||
_pendingLaunch = null;
|
||||
EndSessionUi();
|
||||
ConsolePanel.IsVisible = ConsoleToggle.IsChecked == true && _consoleWindow is null;
|
||||
|
||||
var meaningKey = exitCode switch
|
||||
{
|
||||
@@ -2171,10 +2155,6 @@ public partial class MainWindow : Window
|
||||
brush);
|
||||
CloseFileLogSoon();
|
||||
|
||||
StatusDot.Fill = exitCode == 0 || stoppedByUser ? (IBrush)SuccessLineBrush : ErrorLineBrush;
|
||||
StatusText.Text = stoppedByUser
|
||||
? "Game closed by the user."
|
||||
: Localization.Instance.Format("Launch.Exited", exitCode, meaning);
|
||||
StatusBarRight.Text = Localization.Instance.Get("Status.Idle");
|
||||
_runningGameName = null;
|
||||
_runningGameTitleId = null;
|
||||
@@ -2255,137 +2235,6 @@ public partial class MainWindow : Window
|
||||
private void OnEmulatorOutput(string line, bool isError)
|
||||
{
|
||||
_pendingLines.Enqueue((line, isError));
|
||||
if (!line.Contains("Vulkan VideoOut presented first frame:", StringComparison.Ordinal) &&
|
||||
!line.Contains("Vulkan VideoOut ready:", StringComparison.Ordinal))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
if (_isRunning && !_isStopping)
|
||||
{
|
||||
ShowSessionStatus("Game is running");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void BeginSessionUi()
|
||||
{
|
||||
_isStopping = false;
|
||||
AnimateLibraryBlur(LaunchBlurRadius);
|
||||
ShowSessionLoading("Loading game", "Preparing the emulation session...");
|
||||
LaunchBar.IsVisible = true;
|
||||
}
|
||||
|
||||
private void EndSessionUi()
|
||||
{
|
||||
HideSessionLoading();
|
||||
AnimateLibraryBlur(0, clearWhenComplete: true);
|
||||
LaunchBar.IsVisible = true;
|
||||
ConsolePanel.IsVisible = ConsoleToggle.IsChecked == true && _consoleWindow is null;
|
||||
}
|
||||
|
||||
private void AnimateLibraryBlur(double targetRadius, bool clearWhenComplete = false)
|
||||
{
|
||||
_libraryBlur ??= new BlurEffect();
|
||||
PagesHost.Effect = _libraryBlur;
|
||||
|
||||
_libraryBlurStartRadius = _libraryBlur.Radius;
|
||||
_libraryBlurTargetRadius = Math.Max(0, targetRadius);
|
||||
_libraryBlurStartedAt = Stopwatch.GetTimestamp();
|
||||
_clearLibraryBlurWhenComplete = clearWhenComplete && _libraryBlurTargetRadius == 0;
|
||||
|
||||
if (Math.Abs(_libraryBlurStartRadius - _libraryBlurTargetRadius) < 0.01)
|
||||
{
|
||||
CompleteLibraryBlur();
|
||||
return;
|
||||
}
|
||||
|
||||
_libraryBlurTimer.Start();
|
||||
}
|
||||
|
||||
private void AdvanceLibraryBlur()
|
||||
{
|
||||
if (_libraryBlur is null)
|
||||
{
|
||||
_libraryBlurTimer.Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
var elapsed = (Stopwatch.GetTimestamp() - _libraryBlurStartedAt) /
|
||||
(double)Stopwatch.Frequency;
|
||||
var progress = Math.Clamp(elapsed / BlurTransitionSeconds, 0, 1);
|
||||
// Cubic ease-out gives the loading transition a quick response while
|
||||
// keeping the final change of sharpness unobtrusive.
|
||||
var easedProgress = 1 - Math.Pow(1 - progress, 3);
|
||||
_libraryBlur.Radius = _libraryBlurStartRadius +
|
||||
((_libraryBlurTargetRadius - _libraryBlurStartRadius) * easedProgress);
|
||||
|
||||
if (progress >= 1)
|
||||
{
|
||||
CompleteLibraryBlur();
|
||||
}
|
||||
}
|
||||
|
||||
private void CompleteLibraryBlur()
|
||||
{
|
||||
_libraryBlurTimer.Stop();
|
||||
if (_libraryBlur is not null)
|
||||
{
|
||||
_libraryBlur.Radius = _libraryBlurTargetRadius;
|
||||
}
|
||||
|
||||
if (_clearLibraryBlurWhenComplete)
|
||||
{
|
||||
PagesHost.Effect = null;
|
||||
_libraryBlur = null;
|
||||
_clearLibraryBlurWhenComplete = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearLibraryBlur()
|
||||
{
|
||||
_libraryBlurTimer.Stop();
|
||||
_libraryBlur = null;
|
||||
_clearLibraryBlurWhenComplete = false;
|
||||
PagesHost.Effect = null;
|
||||
}
|
||||
|
||||
private void ShowSessionLoading(string title, string detail)
|
||||
{
|
||||
SessionLoadingTitle.Text = title;
|
||||
SessionLoadingTitle.IsVisible = true;
|
||||
SessionLoadingDetail.Text = detail;
|
||||
SessionLoadingDetail.IsVisible = true;
|
||||
SessionLoadingProgress.IsVisible = true;
|
||||
_sessionLoadingActive = true;
|
||||
SessionLoadingPopup.IsOpen = IsActive && WindowState != WindowState.Minimized;
|
||||
}
|
||||
|
||||
private void ShowSessionStatus(string message)
|
||||
{
|
||||
SessionLoadingTitle.Text = message;
|
||||
SessionLoadingTitle.IsVisible = true;
|
||||
SessionLoadingDetail.IsVisible = false;
|
||||
SessionLoadingProgress.IsVisible = false;
|
||||
_sessionLoadingActive = true;
|
||||
SessionLoadingPopup.IsOpen = IsActive && WindowState != WindowState.Minimized;
|
||||
}
|
||||
|
||||
private void HideSessionLoading()
|
||||
{
|
||||
_sessionLoadingActive = false;
|
||||
SessionLoadingPopup.IsOpen = false;
|
||||
}
|
||||
|
||||
private void ReturnToLibraryWhileStopping()
|
||||
{
|
||||
AnimateLibraryBlur(LaunchBlurRadius);
|
||||
ConsolePanel.IsVisible = ConsoleToggle.IsChecked == true && _consoleWindow is null;
|
||||
LaunchBar.IsVisible = true;
|
||||
UpdateRunButtons();
|
||||
Console.Error.WriteLine("[GUI][INFO] Waiting for the SDL game process to exit.");
|
||||
}
|
||||
|
||||
private void OpenFileLog(string? titleId)
|
||||
@@ -2442,8 +2291,23 @@ public partial class MainWindow : Window
|
||||
|
||||
private void UpdateRunButtons()
|
||||
{
|
||||
LaunchButton.IsEnabled = !_isRunning && GameList.SelectedItem is GameEntry;
|
||||
StopButton.IsEnabled = _isRunning && !_isStopping;
|
||||
LaunchButton.Classes.Remove("accent");
|
||||
LaunchButton.Classes.Remove("danger");
|
||||
|
||||
if (_isRunning)
|
||||
{
|
||||
LaunchButton.Classes.Add("danger");
|
||||
LaunchButton.Content = Localization.Instance.Get(
|
||||
_isStopping ? "Launch.Stopping" : "Launch.Stop");
|
||||
LaunchButton.IsEnabled = !_isStopping;
|
||||
}
|
||||
else
|
||||
{
|
||||
LaunchButton.Classes.Add("accent");
|
||||
LaunchButton.Content = Localization.Instance.Get("Launch.Launch");
|
||||
LaunchButton.IsEnabled = GameList.SelectedItem is GameEntry;
|
||||
}
|
||||
|
||||
OpenFileButton.IsEnabled = !_isRunning;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user