using System; using Avalonia.Automation.Peers; using Avalonia.Controls.Primitives.PopupPositioning; using Avalonia.Interactivity; using Avalonia.Media; using Avalonia.Platform; using Avalonia.Styling; using Avalonia.VisualTree; namespace Avalonia.Controls.Primitives { /// /// The root window of a . /// public sealed class PopupRoot : WindowBase, IInteractive, IHostedVisualTreeRoot, IDisposable, IStyleHost, IPopupHost { /// /// Defines the property. /// public static readonly StyledProperty TransformProperty = AvaloniaProperty.Register(nameof(Transform)); private PopupPositionerParameters _positionerParameters; /// /// Initializes static members of the class. /// static PopupRoot() { BackgroundProperty.OverrideDefaultValue(typeof(PopupRoot), Brushes.White); } /// /// Initializes a new instance of the class. /// public PopupRoot(TopLevel parent, IPopupImpl impl) : this(parent, impl,null) { } /// /// Initializes a new instance of the class. /// /// The popup parent. /// The popup implementation. /// /// The dependency resolver to use. If null the default dependency resolver will be used. /// public PopupRoot(TopLevel parent, IPopupImpl impl, IAvaloniaDependencyResolver? dependencyResolver) : base(impl, dependencyResolver) { ParentTopLevel = parent; } /// /// Gets the platform-specific window implementation. /// public new IPopupImpl? PlatformImpl => (IPopupImpl?)base.PlatformImpl; /// /// Gets or sets a transform that will be applied to the popup. /// public Transform? Transform { get => GetValue(TransformProperty); set => SetValue(TransformProperty, value); } /// /// Gets the parent control in the event route. /// /// /// Popup events are passed to their parent window. This facilitates this. /// IInteractive? IInteractive.InteractiveParent => Parent; /// /// Gets the control that is hosting the popup root. /// IVisual? IHostedVisualTreeRoot.Host => Parent; /// /// Gets the styling parent of the popup root. /// IStyleHost? IStyleHost.StylingParent => Parent; public TopLevel ParentTopLevel { get; } /// public void Dispose() { PlatformImpl?.Dispose(); HandleClosed(); } private void UpdatePosition() { PlatformImpl?.PopupPositioner.Update(_positionerParameters); } public void ConfigurePosition(IVisual target, PlacementMode placement, Point offset, PopupAnchor anchor = PopupAnchor.None, PopupGravity gravity = PopupGravity.None, PopupPositionerConstraintAdjustment constraintAdjustment = PopupPositionerConstraintAdjustment.All, Rect? rect = null) { _positionerParameters.ConfigurePosition(ParentTopLevel, target, placement, offset, anchor, gravity, constraintAdjustment, rect, FlowDirection); if (_positionerParameters.Size != default) UpdatePosition(); } public void SetChild(IControl? control) => Content = control; IVisual IPopupHost.HostedVisualTreeRoot => this; protected override Size MeasureOverride(Size availableSize) { var maxAutoSize = PlatformImpl?.MaxAutoSizeHint ?? Size.Infinity; var constraint = availableSize; if (double.IsInfinity(constraint.Width)) { constraint = constraint.WithWidth(maxAutoSize.Width); } if (double.IsInfinity(constraint.Height)) { constraint = constraint.WithHeight(maxAutoSize.Height); } var measured = base.MeasureOverride(constraint); var width = measured.Width; var height = measured.Height; var widthCache = Width; var heightCache = Height; if (!double.IsNaN(widthCache)) { width = widthCache; } width = Math.Min(width, MaxWidth); width = Math.Max(width, MinWidth); if (!double.IsNaN(heightCache)) { height = heightCache; } height = Math.Min(height, MaxHeight); height = Math.Max(height, MinHeight); return new Size(width, height); } protected override sealed Size ArrangeSetBounds(Size size) { _positionerParameters.Size = size; UpdatePosition(); return ClientSize; } protected override AutomationPeer OnCreateAutomationPeer() { return new PopupRootAutomationPeer(this); } } }