Browse Source

Make toplevels responsible of creating popups

pull/2778/head
Nikita Tsukanov 7 years ago
parent
commit
35f64af761
  1. 5
      src/Android/Avalonia.Android/AndroidPlatform.cs
  2. 2
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
  3. 1
      src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs
  4. 2
      src/Avalonia.Controls/Platform/ITopLevelImpl.cs
  5. 1
      src/Avalonia.Controls/Platform/IWindowingPlatform.cs
  6. 5
      src/Avalonia.Controls/Platform/PlatformManager.cs
  7. 37
      src/Avalonia.Controls/Primitives/Popup.cs
  8. 8
      src/Avalonia.Controls/Primitives/PopupRoot.cs
  9. 3
      src/Avalonia.Controls/ToolTip.cs
  10. 2
      src/Avalonia.DesignerSupport/Remote/Stubs.cs
  11. 5
      src/Avalonia.Native/AvaloniaNativePlatform.cs
  12. 6
      src/Avalonia.Native/PopupImpl.cs
  13. 5
      src/Avalonia.Native/WindowImpl.cs
  14. 3
      src/Avalonia.Native/WindowImplBase.cs
  15. 7
      src/Avalonia.X11/X11Platform.cs
  16. 10
      src/Avalonia.X11/X11Window.cs
  17. 2
      src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs
  18. 2
      src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs
  19. 5
      src/Windows/Avalonia.Win32/Win32Platform.cs
  20. 2
      src/iOS/Avalonia.iOS/TopLevelImpl.cs
  21. 12
      tests/Avalonia.Controls.UnitTests/Primitives/PopupRootTests.cs

5
src/Android/Avalonia.Android/AndroidPlatform.cs

@ -71,10 +71,5 @@ namespace Avalonia.Android
{
throw new NotSupportedException();
}
public IPopupImpl CreatePopup()
{
return new PopupImpl();
}
}
}

2
src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

@ -191,6 +191,8 @@ namespace Avalonia.Android.Platform.SkiaPlatform
}
}
public IPopupImpl CreatePopup() => null;
ILockedFramebuffer IFramebufferPlatformSurface.Lock()=>new AndroidFramebuffer(_view.Holder.Surface);
}
}

1
src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs

@ -61,5 +61,6 @@ namespace Avalonia.Controls.Embedding.Offscreen
public Action Closed { get; set; }
public abstract IMouseDevice MouseDevice { get; }
public IPopupImpl CreatePopup() => null;
}
}

2
src/Avalonia.Controls/Platform/ITopLevelImpl.cs

@ -107,5 +107,7 @@ namespace Avalonia.Platform
/// </summary>
[CanBeNull]
IMouseDevice MouseDevice { get; }
IPopupImpl CreatePopup();
}
}

1
src/Avalonia.Controls/Platform/IWindowingPlatform.cs

@ -4,6 +4,5 @@ namespace Avalonia.Platform
{
IWindowImpl CreateWindow();
IEmbeddableWindowImpl CreateEmbeddableWindow();
IPopupImpl CreatePopup();
}
}

5
src/Avalonia.Controls/Platform/PlatformManager.cs

@ -41,10 +41,5 @@ namespace Avalonia.Controls.Platform
throw new Exception("Could not CreateEmbeddableWindow(): IWindowingPlatform is not registered.");
return platform.CreateEmbeddableWindow();
}
public static IPopupImpl CreatePopup()
{
return AvaloniaLocator.Current.GetService<IWindowingPlatform>().CreatePopup();
}
}
}

37
src/Avalonia.Controls/Primitives/Popup.cs

@ -218,9 +218,16 @@ namespace Avalonia.Controls.Primitives
/// </summary>
public void Open()
{
if (PlacementTarget == null)
throw new InvalidOperationException("It's not valid to show a popup without a PlacementTarget");
if (_topLevel == null && PlacementTarget != null)
_topLevel = PlacementTarget.GetSelfAndLogicalAncestors().First(x => x is TopLevel) as TopLevel;
if (_popupRoot == null)
{
_popupRoot = new PopupRoot(DependencyResolver)
_popupRoot = new PopupRoot(_topLevel, DependencyResolver)
{
[~ContentControl.ContentProperty] = this[~ChildProperty],
[~WidthProperty] = this[~WidthProperty],
@ -236,30 +243,22 @@ namespace Avalonia.Controls.Primitives
_popupRoot.Position = GetPosition();
if (_topLevel == null && PlacementTarget != null)
var window = _topLevel as Window;
if (window != null)
{
_topLevel = PlacementTarget.GetSelfAndLogicalAncestors().First(x => x is TopLevel) as TopLevel;
window.Deactivated += WindowDeactivated;
}
if (_topLevel != null)
else
{
var window = _topLevel as Window;
if (window != null)
var parentPopuproot = _topLevel as PopupRoot;
if (parentPopuproot?.Parent is Popup popup)
{
window.Deactivated += WindowDeactivated;
popup.Closed += ParentClosed;
}
else
{
var parentPopuproot = _topLevel as PopupRoot;
if (parentPopuproot?.Parent is Popup popup)
{
popup.Closed += ParentClosed;
}
}
_topLevel.AddHandler(PointerPressedEvent, PointerPressedOutside, RoutingStrategies.Tunnel);
_nonClientListener = InputManager.Instance.Process.Subscribe(ListenForNonClientClick);
}
_topLevel.AddHandler(PointerPressedEvent, PointerPressedOutside, RoutingStrategies.Tunnel);
_nonClientListener = InputManager.Instance.Process.Subscribe(ListenForNonClientClick);
PopupRootCreated?.Invoke(this, EventArgs.Empty);
_popupRoot.Show();

8
src/Avalonia.Controls/Primitives/PopupRoot.cs

@ -31,8 +31,8 @@ namespace Avalonia.Controls.Primitives
/// <summary>
/// Initializes a new instance of the <see cref="PopupRoot"/> class.
/// </summary>
public PopupRoot()
: this(null)
public PopupRoot(TopLevel parent)
: this(parent, null)
{
}
@ -42,8 +42,8 @@ namespace Avalonia.Controls.Primitives
/// <param name="dependencyResolver">
/// The dependency resolver to use. If null the default dependency resolver will be used.
/// </param>
public PopupRoot(IAvaloniaDependencyResolver dependencyResolver)
: base(PlatformManager.CreatePopup(), dependencyResolver)
public PopupRoot(TopLevel parent, IAvaloniaDependencyResolver dependencyResolver)
: base(parent.PlatformImpl.CreatePopup(), dependencyResolver)
{
}

3
src/Avalonia.Controls/ToolTip.cs

@ -4,6 +4,7 @@
using System;
using System.Reactive.Linq;
using Avalonia.Controls.Primitives;
using Avalonia.VisualTree;
namespace Avalonia.Controls
{
@ -234,7 +235,7 @@ namespace Avalonia.Controls
{
Close();
_popup = new PopupRoot { Content = this, };
_popup = new PopupRoot((TopLevel)control.GetVisualRoot()) {Content = this};
((ISetLogicalParent)_popup).SetParent(control);
_popup.Position = Popup.GetPosition(control, GetPlacement(control), _popup,
GetHorizontalOffset(control), GetVerticalOffset(control));

2
src/Avalonia.DesignerSupport/Remote/Stubs.cs

@ -29,6 +29,8 @@ namespace Avalonia.DesignerSupport.Remote
public Func<bool> Closing { get; set; }
public Action Closed { get; set; }
public IMouseDevice MouseDevice { get; } = new MouseDevice();
public IPopupImpl CreatePopup() => null;
public PixelPoint Position { get; set; }
public Action<PixelPoint> PositionChanged { get; set; }
public WindowState WindowState { get; set; }

5
src/Avalonia.Native/AvaloniaNativePlatform.cs

@ -97,11 +97,6 @@ namespace Avalonia.Native
{
throw new NotImplementedException();
}
public IPopupImpl CreatePopup()
{
return new PopupImpl(_factory, _options);
}
}
public class AvaloniaNativeMacOptions

6
src/Avalonia.Native/PopupImpl.cs

@ -9,8 +9,12 @@ namespace Avalonia.Native
{
public class PopupImpl : WindowBaseImpl, IPopupImpl
{
private readonly IAvaloniaNativeFactory _factory;
private readonly AvaloniaNativePlatformOptions _opts;
public PopupImpl(IAvaloniaNativeFactory factory, AvaloniaNativePlatformOptions opts) : base(opts)
{
_factory = factory;
_opts = opts;
using (var e = new PopupEvents(this))
{
Init(factory.CreatePopup(e), factory.CreateScreens());
@ -35,5 +39,7 @@ namespace Avalonia.Native
{
}
}
public override IPopupImpl CreatePopup() => new PopupImpl(_factory, _opts);
}
}

5
src/Avalonia.Native/WindowImpl.cs

@ -11,9 +11,13 @@ namespace Avalonia.Native
{
public class WindowImpl : WindowBaseImpl, IWindowImpl
{
private readonly IAvaloniaNativeFactory _factory;
private readonly AvaloniaNativePlatformOptions _opts;
IAvnWindow _native;
public WindowImpl(IAvaloniaNativeFactory factory, AvaloniaNativePlatformOptions opts) : base(opts)
{
_factory = factory;
_opts = opts;
using (var e = new WindowEvents(this))
{
Init(_native = factory.CreateWindow(e), factory.CreateScreens());
@ -100,5 +104,6 @@ namespace Avalonia.Native
}
public Func<bool> Closing { get; set; }
public override IPopupImpl CreatePopup() => new PopupImpl(_factory, _opts);
}
}

3
src/Avalonia.Native/WindowImplBase.cs

@ -15,7 +15,7 @@ using Avalonia.Threading;
namespace Avalonia.Native
{
public class WindowBaseImpl : IWindowBaseImpl,
public abstract class WindowBaseImpl : IWindowBaseImpl,
IFramebufferPlatformSurface
{
IInputRoot _inputRoot;
@ -91,6 +91,7 @@ namespace Avalonia.Native
public Action<Size> Resized { get; set; }
public Action Closed { get; set; }
public IMouseDevice MouseDevice => AvaloniaNativePlatform.MouseDevice;
public abstract IPopupImpl CreatePopup();
class FramebufferWrapper : ILockedFramebuffer

7
src/Avalonia.X11/X11Platform.cs

@ -74,18 +74,13 @@ namespace Avalonia.X11
public IntPtr Display { get; set; }
public IWindowImpl CreateWindow()
{
return new X11Window(this, false);
return new X11Window(this, null);
}
public IEmbeddableWindowImpl CreateEmbeddableWindow()
{
throw new NotSupportedException();
}
public IPopupImpl CreatePopup()
{
return new X11Window(this, true);
}
}
}

10
src/Avalonia.X11/X11Window.cs

@ -21,6 +21,7 @@ namespace Avalonia.X11
unsafe class X11Window : IWindowImpl, IPopupImpl, IXI2Client
{
private readonly AvaloniaX11Platform _platform;
private readonly IWindowImpl _popupParent;
private readonly bool _popup;
private readonly X11Info _x11;
private bool _invalidated;
@ -47,10 +48,10 @@ namespace Avalonia.X11
private readonly Queue<InputEventContainer> _inputQueue = new Queue<InputEventContainer>();
private InputEventContainer _lastEvent;
private bool _useRenderWindow = false;
public X11Window(AvaloniaX11Platform platform, bool popup)
public X11Window(AvaloniaX11Platform platform, IWindowImpl popupParent)
{
_platform = platform;
_popup = popup;
_popup = popupParent != null;
_x11 = platform.Info;
_mouse = platform.MouseDevice;
_keyboard = platform.KeyboardDevice;
@ -66,7 +67,7 @@ namespace Avalonia.X11
| SetWindowValuemask.BackPixmap | SetWindowValuemask.BackingStore
| SetWindowValuemask.BitGravity | SetWindowValuemask.WinGravity;
if (popup)
if (_popup)
{
attr.override_redirect = true;
valueMask |= SetWindowValuemask.OverrideRedirect;
@ -793,7 +794,8 @@ namespace Avalonia.X11
}
public IMouseDevice MouseDevice => _mouse;
public IPopupImpl CreatePopup() => new X11Window(_platform, this);
public void Activate()
{
if (_x11.Atoms._NET_ACTIVE_WINDOW != IntPtr.Zero)

2
src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs

@ -59,6 +59,8 @@ namespace Avalonia.LinuxFramebuffer
public Size ClientSize => ScaledSize;
public IMouseDevice MouseDevice => new MouseDevice();
public IPopupImpl CreatePopup() => null;
public double Scaling => 1;
public IEnumerable<object> Surfaces => new object[] {_outputBackend};
public Action<RawInputEventArgs> Input { get; set; }

2
src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs

@ -240,5 +240,7 @@ namespace Avalonia.Win32.Interop.Wpf
return new Vector(1, 1);
return new Vector(src.TransformToDevice.M11, src.TransformToDevice.M22);
}
IPopupImpl CreatePopup() => null;
}
}

5
src/Windows/Avalonia.Win32/Win32Platform.cs

@ -210,11 +210,6 @@ namespace Avalonia.Win32
return embedded;
}
public IPopupImpl CreatePopup()
{
return new PopupImpl();
}
public IWindowIconImpl LoadIcon(string fileName)
{
using (var stream = File.OpenRead(fileName))

2
src/iOS/Avalonia.iOS/TopLevelImpl.cs

@ -134,5 +134,7 @@ namespace Avalonia.iOS
}
public ILockedFramebuffer Lock() => new EmulatedFramebuffer(this);
public IPopupImpl CreatePopup() => null;
}
}

12
tests/Avalonia.Controls.UnitTests/Primitives/PopupRootTests.cs

@ -21,7 +21,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var target = CreateTarget();
var target = CreateTarget(new Window());
Assert.True(((ILogical)target).IsAttachedToLogicalTree);
}
@ -32,7 +32,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var target = CreateTarget();
var target = CreateTarget(new Window());
Assert.True(target.Presenter.IsAttachedToLogicalTree);
}
@ -63,8 +63,8 @@ namespace Avalonia.Controls.UnitTests.Primitives
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var child = new Decorator();
var target = CreateTarget();
var window = new Window();
var target = CreateTarget(window);
var detachedCount = 0;
var attachedCount = 0;
@ -88,8 +88,8 @@ namespace Avalonia.Controls.UnitTests.Primitives
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var child = new Decorator();
var target = CreateTarget();
var window = new Window();
var target = CreateTarget(window);
var detachedCount = 0;
var attachedCount = 0;
@ -130,9 +130,9 @@ namespace Avalonia.Controls.UnitTests.Primitives
}
}
private PopupRoot CreateTarget()
private PopupRoot CreateTarget(TopLevel popupParent)
{
var result = new PopupRoot
var result = new PopupRoot(popupParent)
{
Template = new FuncControlTemplate<PopupRoot>((parent, scope) =>
new ContentPresenter

Loading…
Cancel
Save