using System;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Platform;
using JetBrains.Annotations;
namespace Avalonia.Controls
{
///
/// Base class for top-level windows.
///
///
/// This class acts as a base for top level windows such as and
/// . It handles scheduling layout, styling and rendering as well as
/// tracking the window and state.
///
public class WindowBase : TopLevel
{
///
/// Defines the property.
///
public static readonly DirectProperty IsActiveProperty =
AvaloniaProperty.RegisterDirect(nameof(IsActive), o => o.IsActive);
///
/// Defines the property.
///
public static readonly DirectProperty OwnerProperty =
AvaloniaProperty.RegisterDirect(
nameof(Owner),
o => o.Owner,
(o, v) => o.Owner = v);
public static readonly StyledProperty TopmostProperty =
AvaloniaProperty.Register(nameof(Topmost));
private bool _hasExecutedInitialLayoutPass;
private bool _isActive;
private bool _ignoreVisibilityChange;
private WindowBase _owner;
static WindowBase()
{
IsVisibleProperty.OverrideDefaultValue(false);
IsVisibleProperty.Changed.AddClassHandler((x,e) => x.IsVisibleChanged(e));
TopmostProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.SetTopmost((bool)e.NewValue));
}
public WindowBase(IWindowBaseImpl impl) : this(impl, AvaloniaLocator.Current)
{
}
public WindowBase(IWindowBaseImpl impl, IAvaloniaDependencyResolver dependencyResolver) : base(impl, dependencyResolver)
{
Screens = new Screens(PlatformImpl?.Screen);
impl.Activated = HandleActivated;
impl.Deactivated = HandleDeactivated;
impl.PositionChanged = HandlePositionChanged;
}
///
/// Fired when the window is activated.
///
public event EventHandler Activated;
///
/// Fired when the window is deactivated.
///
public event EventHandler Deactivated;
///
/// Fired when the window position is changed.
///
public event EventHandler PositionChanged;
[CanBeNull]
public new IWindowBaseImpl PlatformImpl => (IWindowBaseImpl) base.PlatformImpl;
///
/// Gets a value that indicates whether the window is active.
///
public bool IsActive
{
get { return _isActive; }
private set { SetAndRaise(IsActiveProperty, ref _isActive, value); }
}
public Screens Screens { get; private set; }
///
/// Whether an auto-size operation is in progress.
///
protected bool AutoSizing
{
get;
private set;
}
///
/// Gets or sets the owner of the window.
///
public WindowBase Owner
{
get { return _owner; }
set { SetAndRaise(OwnerProperty, ref _owner, value); }
}
///
/// Gets or sets whether this window appears on top of all other windows
///
public bool Topmost
{
get { return GetValue(TopmostProperty); }
set { SetValue(TopmostProperty, value); }
}
///
/// Activates the window.
///
public void Activate()
{
PlatformImpl?.Activate();
}
///
/// Hides the popup.
///
public virtual void Hide()
{
_ignoreVisibilityChange = true;
try
{
Renderer?.Stop();
PlatformImpl?.Hide();
IsVisible = false;
}
finally
{
_ignoreVisibilityChange = false;
}
}
///
/// Shows the window.
///
public virtual void Show()
{
_ignoreVisibilityChange = true;
try
{
EnsureInitialized();
IsVisible = true;
if (!_hasExecutedInitialLayoutPass)
{
LayoutManager.ExecuteInitialLayoutPass(this);
_hasExecutedInitialLayoutPass = true;
}
PlatformImpl?.Show();
Renderer?.Start();
OnOpened(EventArgs.Empty);
}
finally
{
_ignoreVisibilityChange = false;
}
}
///
/// Begins an auto-resize operation.
///
/// A disposable used to finish the operation.
///
/// When an auto-resize operation is in progress any resize events received will not be
/// cause the new size to be written to the and
/// properties.
///
protected IDisposable BeginAutoSizing()
{
AutoSizing = true;
return Disposable.Create(() => AutoSizing = false);
}
///
/// Ensures that the window is initialized.
///
protected void EnsureInitialized()
{
if (!IsInitialized)
{
var init = (ISupportInitialize)this;
init.BeginInit();
init.EndInit();
}
}
protected override void HandleClosed()
{
_ignoreVisibilityChange = true;
try
{
IsVisible = false;
base.HandleClosed();
}
finally
{
_ignoreVisibilityChange = false;
}
}
///
/// Handles a resize notification from .
///
/// The new client size.
protected override void HandleResized(Size clientSize)
{
if (!AutoSizing)
{
Width = clientSize.Width;
Height = clientSize.Height;
}
ClientSize = clientSize;
LayoutManager.ExecuteLayoutPass();
Renderer?.Resized(clientSize);
}
///
/// Handles a window position change notification from
/// .
///
/// The window position.
private void HandlePositionChanged(PixelPoint pos)
{
PositionChanged?.Invoke(this, new PixelPointEventArgs(pos));
}
///
/// Handles an activated notification from .
///
private void HandleActivated()
{
Activated?.Invoke(this, EventArgs.Empty);
var scope = this as IFocusScope;
if (scope != null)
{
FocusManager.Instance.SetFocusScope(scope);
}
IsActive = true;
}
///
/// Handles a deactivated notification from .
///
private void HandleDeactivated()
{
IsActive = false;
Deactivated?.Invoke(this, EventArgs.Empty);
}
private void IsVisibleChanged(AvaloniaPropertyChangedEventArgs e)
{
if (!_ignoreVisibilityChange)
{
if ((bool)e.NewValue)
{
Show();
}
else
{
Hide();
}
}
}
}
}