// 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.Collections.Generic;
using System.Linq;
using System.Reactive.Disposables;
using System.Text;
using Avalonia.Controls.Platform;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives.PopupPositioning;
using Avalonia.Data;
using Avalonia.Diagnostics;
using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Styling;
using Avalonia.VisualTree;
using JetBrains.Annotations;
namespace Avalonia.Controls.Primitives
{
///
/// The root window of a .
///
public class PopupRoot : WindowBase, IInteractive, IHostedVisualTreeRoot, IDisposable, IStyleHost, IPopupHost
{
private readonly TopLevel _parent;
private IDisposable _presenterSubscription;
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 dependency resolver to use. If null the default dependency resolver will be used.
///
public PopupRoot(TopLevel parent, IPopupImpl impl, IAvaloniaDependencyResolver dependencyResolver)
: base(impl, dependencyResolver)
{
_parent = parent;
}
///
/// Gets the platform-specific window implementation.
///
[CanBeNull]
public new IPopupImpl PlatformImpl => (IPopupImpl)base.PlatformImpl;
///
/// 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 void Dispose() => PlatformImpl?.Dispose();
///
protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
{
base.OnTemplateApplied(e);
if (Parent?.TemplatedParent != null)
{
if (_presenterSubscription != null)
{
_presenterSubscription.Dispose();
_presenterSubscription = null;
}
Presenter?.ApplyTemplate();
Presenter?.GetObservable(ContentPresenter.ChildProperty)
.Subscribe(SetTemplatedParentAndApplyChildTemplates);
}
}
private void SetTemplatedParentAndApplyChildTemplates(IControl control)
{
if (control != null)
{
var templatedParent = Parent.TemplatedParent;
if (control.TemplatedParent == null)
{
control.SetValue(TemplatedParentProperty, templatedParent);
}
control.ApplyTemplate();
if (!(control is IPresenter) && control.TemplatedParent == templatedParent)
{
foreach (IControl child in control.GetVisualChildren())
{
SetTemplatedParentAndApplyChildTemplates(child);
}
}
}
}
void UpdatePosition()
{
PlatformImpl?.PopupPositioner.Update(_positionerParameters);
}
public void ConfigurePosition(IVisual target, PlacementMode placement, Point offset,
PopupPositioningEdge anchor = PopupPositioningEdge.None,
PopupPositioningEdge gravity = PopupPositioningEdge.None)
{
_positionerParameters.ConfigurePosition(_parent, target,
placement, offset, anchor, gravity);
if (_positionerParameters.Size != default)
UpdatePosition();
}
public void SetContent(IControl control) => Content = control;
IVisual IPopupHost.VisualRoot => this;
public IDisposable BindConstraints(AvaloniaObject popup, StyledProperty widthProperty, StyledProperty minWidthProperty,
StyledProperty maxWidthProperty, StyledProperty heightProperty, StyledProperty minHeightProperty,
StyledProperty maxHeightProperty, StyledProperty topmostProperty)
{
var bindings = new List();
void Bind(AvaloniaProperty what, AvaloniaProperty to) => bindings.Add(this.Bind(what, popup[~to]));
Bind(WidthProperty, widthProperty);
Bind(MinWidthProperty, minWidthProperty);
Bind(MaxWidthProperty, maxWidthProperty);
Bind(HeightProperty, heightProperty);
Bind(MinHeightProperty, minHeightProperty);
Bind(MaxHeightProperty, maxHeightProperty);
Bind(TopmostProperty, topmostProperty);
return Disposable.Create(() =>
{
foreach (var x in bindings)
x.Dispose();
});
}
///
/// Carries out the arrange pass of the window.
///
/// The final window size.
/// The parameter unchanged.
protected override Size ArrangeOverride(Size finalSize)
{
using (BeginAutoSizing())
{
_positionerParameters.Size = finalSize;
UpdatePosition();
}
return base.ArrangeOverride(PlatformImpl?.ClientSize ?? default(Size));
}
}
}