// Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; using System.Reactive.Linq; using System.Threading.Tasks; using Avalonia.Controls.Platform; using Avalonia.Input; using Avalonia.Layout; using Avalonia.Media; using Avalonia.Platform; using Avalonia.Styling; using System.Collections.Generic; namespace Avalonia.Controls { /// /// Determines how a will size itself to fit its content. /// public enum SizeToContent { /// /// The window will not automatically size itself to fit its content. /// Manual, /// /// The window will size itself horizontally to fit its content. /// Width, /// /// The window will size itself vertically to fit its content. /// Height, /// /// The window will size itself horizontally and vertically to fit its content. /// WidthAndHeight, } /// /// A top-level window. /// public class Window : TopLevel, IStyleable, IFocusScope, ILayoutRoot, INameScope { private static IList s_windows = new List(); /// /// Retrieves an enumeration of all Windows in the currently running application. /// public static IList OpenWindows => s_windows; /// /// Defines the property. /// public static readonly StyledProperty SizeToContentProperty = AvaloniaProperty.Register(nameof(SizeToContent)); /// /// Enables of disables system window decorations (title bar, buttons, etc) /// public static readonly StyledProperty HasSystemDecorationsProperty = AvaloniaProperty.Register(nameof(HasSystemDecorations), true); /// /// Defines the property. /// public static readonly StyledProperty TitleProperty = AvaloniaProperty.Register(nameof(Title), "Window"); /// /// Defines the property. /// public static readonly StyledProperty IconProperty = AvaloniaProperty.Register(nameof(Icon)); private readonly NameScope _nameScope = new NameScope(); private object _dialogResult; private readonly Size _maxPlatformClientSize; /// /// Initializes static members of the class. /// static Window() { BackgroundProperty.OverrideDefaultValue(typeof(Window), Brushes.White); TitleProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl.SetTitle((string)e.NewValue)); HasSystemDecorationsProperty.Changed.AddClassHandler( (s, e) => s.PlatformImpl.SetSystemDecorations((bool) e.NewValue)); IconProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl.SetIcon(((WindowIcon)e.NewValue).PlatformImpl)); } /// /// Initializes a new instance of the class. /// public Window() : this(PlatformManager.CreateWindow()) { } /// /// Initializes a new instance of the class. /// /// The window implementation. public Window(IWindowImpl impl) : base(impl) { _maxPlatformClientSize = this.PlatformImpl.MaxClientSize; } /// event EventHandler INameScope.Registered { add { _nameScope.Registered += value; } remove { _nameScope.Registered -= value; } } /// event EventHandler INameScope.Unregistered { add { _nameScope.Unregistered += value; } remove { _nameScope.Unregistered -= value; } } /// /// Gets the platform-specific window implementation. /// public new IWindowImpl PlatformImpl => (IWindowImpl)base.PlatformImpl; /// /// Gets or sets a value indicating how the window will size itself to fit its content. /// public SizeToContent SizeToContent { get { return GetValue(SizeToContentProperty); } set { SetValue(SizeToContentProperty, value); } } /// /// Gets or sets the title of the window. /// public string Title { get { return GetValue(TitleProperty); } set { SetValue(TitleProperty, value); } } /// /// Enables of disables system window decorations (title bar, buttons, etc) /// /// public bool HasSystemDecorations { get { return GetValue(HasSystemDecorationsProperty); } set { SetValue(HasSystemDecorationsProperty, value); } } /// /// Gets or sets the minimized/maximized state of the window. /// public WindowState WindowState { get { return this.PlatformImpl.WindowState; } set { this.PlatformImpl.WindowState = value; } } /// /// Gets or sets the icon of the window. /// public WindowIcon Icon { get { return GetValue(IconProperty); } set { SetValue(IconProperty, value); } } /// Size ILayoutRoot.MaxClientSize => _maxPlatformClientSize; /// Type IStyleable.StyleKey => typeof(Window); /// /// Closes the window. /// public void Close() { s_windows.Remove(this); PlatformImpl.Dispose(); } protected override void HandleApplicationExiting() { base.HandleApplicationExiting(); Close(); } /// /// Closes a dialog window with the specified result. /// /// The dialog result. /// /// When the window is shown with the method, the /// resulting task will produce the value when the window /// is closed. /// public void Close(object dialogResult) { _dialogResult = dialogResult; Close(); } /// /// Hides the window but does not close it. /// public void Hide() { using (BeginAutoSizing()) { PlatformImpl.Hide(); } } /// /// Shows the window. /// public void Show() { s_windows.Add(this); EnsureInitialized(); LayoutManager.Instance.ExecuteInitialLayoutPass(this); using (BeginAutoSizing()) { PlatformImpl.Show(); } } /// /// Shows the window as a dialog. /// /// /// A task that can be used to track the lifetime of the dialog. /// public Task ShowDialog() { return ShowDialog(); } /// /// Shows the window as a dialog. /// /// /// The type of the result produced by the dialog. /// /// . /// A task that can be used to retrive the result of the dialog when it closes. /// public Task ShowDialog() { s_windows.Add(this); EnsureInitialized(); LayoutManager.Instance.ExecuteInitialLayoutPass(this); using (BeginAutoSizing()) { var modal = PlatformImpl.ShowDialog(); var result = new TaskCompletionSource(); Observable.FromEventPattern(this, nameof(Closed)) .Take(1) .Subscribe(_ => { modal.Dispose(); result.SetResult((TResult)_dialogResult); }); return result.Task; } } /// void INameScope.Register(string name, object element) { _nameScope.Register(name, element); } /// object INameScope.Find(string name) { return _nameScope.Find(name); } /// void INameScope.Unregister(string name) { _nameScope.Unregister(name); } /// protected override Size MeasureOverride(Size availableSize) { var sizeToContent = SizeToContent; var size = ClientSize; var desired = base.MeasureOverride(availableSize.Constrain(_maxPlatformClientSize)); switch (sizeToContent) { case SizeToContent.Width: size = new Size(desired.Width, ClientSize.Height); break; case SizeToContent.Height: size = new Size(ClientSize.Width, desired.Height); break; case SizeToContent.WidthAndHeight: size = new Size(desired.Width, desired.Height); break; case SizeToContent.Manual: size = ClientSize; break; default: throw new InvalidOperationException("Invalid value for SizeToContent."); } return size; } /// protected override void HandleResized(Size clientSize) { if (!AutoSizing) { SizeToContent = SizeToContent.Manual; } base.HandleResized(clientSize); } private void EnsureInitialized() { if (!this.IsInitialized) { var init = (ISupportInitialize)this; init.BeginInit(); init.EndInit(); } } } } namespace Avalonia { public static class WindowApplicationExtensions { public static void RunWithMainWindow(this Application app) where TWindow : Avalonia.Controls.Window, new() { var window = new TWindow(); window.Show(); app.Run(window); } } }