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(); } } } } }