127 lines
3.6 KiB
C#
127 lines
3.6 KiB
C#
using System.ComponentModel;
|
|
using System.Windows;
|
|
|
|
namespace CursorLang.Services;
|
|
|
|
/// <summary>
|
|
/// Keeps the settings window between the screen and the tray.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The application works in the background, and the settings window is a guest on
|
|
/// the screen rather than the application itself. Both buttons in its title bar
|
|
/// therefore mean the same thing — put the window away — and neither ends the
|
|
/// application: that is what the tray menu is for.
|
|
///
|
|
/// The window is hidden rather than closed. Closing it would take its handle with
|
|
/// it, and everything hung on the window — the theme, the place it was left in, the
|
|
/// computed layout — would have to be built anew on every show.
|
|
/// </remarks>
|
|
public sealed class MainWindowPresenter
|
|
{
|
|
private readonly MainWindowPlacement _placement;
|
|
|
|
private Window? _window;
|
|
|
|
// The application is quitting: the window may close for real now
|
|
private bool _isExiting;
|
|
|
|
public MainWindowPresenter(MainWindowPlacement placement) => _placement = placement;
|
|
|
|
/// <summary>Whether the window is on the screen right now.</summary>
|
|
public bool IsShown => _window is { IsVisible: true };
|
|
|
|
/// <summary>Takes over the fate of the window: the close button and the minimise one.</summary>
|
|
public void Attach(Window window)
|
|
{
|
|
_window = window;
|
|
|
|
window.Closing += OnClosing;
|
|
window.StateChanged += OnStateChanged;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Shows the window and brings it forward — from the tray as well as from a
|
|
/// second launch of the application.
|
|
/// </summary>
|
|
public void Show()
|
|
{
|
|
if (_window is null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_window.Show();
|
|
|
|
// A window put away while minimised is restored first: only then does it
|
|
// have bounds to be placed by
|
|
if (_window.WindowState == WindowState.Minimized)
|
|
{
|
|
_window.WindowState = WindowState.Normal;
|
|
}
|
|
|
|
_placement.Apply(_window);
|
|
_window.Activate();
|
|
}
|
|
|
|
/// <summary>Puts the window away into the tray.</summary>
|
|
public void Hide()
|
|
{
|
|
if (_window is null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_window.Hide();
|
|
|
|
// The state is straightened out after the window is out of sight: the next
|
|
// show is to bring back a window, not an icon on the taskbar
|
|
_window.WindowState = WindowState.Normal;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Lets the window close. Called on the way out through the tray menu — up to
|
|
/// that moment closing means hiding.
|
|
/// </summary>
|
|
public void AllowClose() => _isExiting = true;
|
|
|
|
/// <summary>
|
|
/// Gives the window back its usual behaviour: the close button closes, and the
|
|
/// minimise button minimises.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The last resort for a session with no notification area in it. Without the
|
|
/// icon there is no way back to a hidden window and no way out of the
|
|
/// application — the window has to take both duties back.
|
|
/// </remarks>
|
|
public void Detach()
|
|
{
|
|
if (_window is null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_window.Closing -= OnClosing;
|
|
_window.StateChanged -= OnStateChanged;
|
|
_window = null;
|
|
}
|
|
|
|
private void OnClosing(object? sender, CancelEventArgs e)
|
|
{
|
|
if (_isExiting)
|
|
{
|
|
return;
|
|
}
|
|
|
|
e.Cancel = true;
|
|
Hide();
|
|
}
|
|
|
|
private void OnStateChanged(object? sender, EventArgs e)
|
|
{
|
|
if (_window is { WindowState: WindowState.Minimized })
|
|
{
|
|
Hide();
|
|
}
|
|
}
|
|
}
|