Skip to content

Commit

Permalink
Merge pull request #6191 from pr8x/feature-devtools-inspect-popup
Browse files Browse the repository at this point in the history
DevTools: Support for inspecting Popup visual tree
  • Loading branch information
MarchingCube authored and danwalmsley committed Aug 17, 2021
1 parent 86e81f6 commit c69ab45
Show file tree
Hide file tree
Showing 13 changed files with 406 additions and 113 deletions.
17 changes: 15 additions & 2 deletions src/Avalonia.Controls/ContextMenu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;

using Avalonia.Controls.Diagnostics;
using Avalonia.Controls.Generators;
using Avalonia.Controls.Platform;
using Avalonia.Controls.Primitives;
Expand All @@ -21,7 +21,7 @@ namespace Avalonia.Controls
/// <summary>
/// A control context menu.
/// </summary>
public class ContextMenu : MenuBase, ISetterValue
public class ContextMenu : MenuBase, ISetterValue, IPopupHostProvider
{
/// <summary>
/// Defines the <see cref="HorizontalOffset"/> property.
Expand Down Expand Up @@ -82,6 +82,7 @@ public class ContextMenu : MenuBase, ISetterValue
private Popup? _popup;
private List<Control>? _attachedControls;
private IInputElement? _previousFocus;
private Action<IPopupHost?>? _popupHostChangedHandler;

/// <summary>
/// Initializes a new instance of the <see cref="ContextMenu"/> class.
Expand Down Expand Up @@ -304,6 +305,14 @@ void ISetterValue.Initialize(ISetter setter)
}
}

IPopupHost? IPopupHostProvider.PopupHost => _popup?.Host;

event Action<IPopupHost?>? IPopupHostProvider.PopupHostChanged
{
add => _popupHostChangedHandler += value;
remove => _popupHostChangedHandler -= value;
}

protected override IItemContainerGenerator CreateItemContainerGenerator()
{
return new MenuItemContainerGenerator(this);
Expand Down Expand Up @@ -364,6 +373,8 @@ private void PopupOpened(object sender, EventArgs e)
{
_previousFocus = FocusManager.Instance?.Current;
Focus();

_popupHostChangedHandler?.Invoke(_popup!.Host);
}

private void PopupClosing(object sender, CancelEventArgs e)
Expand Down Expand Up @@ -397,6 +408,8 @@ private void PopupClosed(object sender, EventArgs e)
RoutedEvent = MenuClosedEvent,
Source = this,
});

_popupHostChangedHandler?.Invoke(null);
}

private void PopupKeyUp(object sender, KeyEventArgs e)
Expand Down
23 changes: 23 additions & 0 deletions src/Avalonia.Controls/Diagnostics/IPopupHostProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using Avalonia.Controls.Primitives;

#nullable enable

namespace Avalonia.Controls.Diagnostics
{
/// <summary>
/// Diagnostics interface to retrieve an associated <see cref="IPopupHost"/>.
/// </summary>
public interface IPopupHostProvider
{
/// <summary>
/// The popup host.
/// </summary>
IPopupHost? PopupHost { get; }

/// <summary>
/// Raised when the popup host changes.
/// </summary>
event Action<IPopupHost?>? PopupHostChanged;
}
}
15 changes: 15 additions & 0 deletions src/Avalonia.Controls/Diagnostics/ToolTipDiagnostics.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#nullable enable

namespace Avalonia.Controls.Diagnostics
{
/// <summary>
/// Helper class to provide diagnostics information for <see cref="ToolTip"/>.
/// </summary>
public static class ToolTipDiagnostics
{
/// <summary>
/// Provides access to the internal <see cref="ToolTip.ToolTipProperty"/> for use in DevTools.
/// </summary>
public static AvaloniaProperty<ToolTip?> ToolTipProperty = ToolTip.ToolTipProperty;
}
}
18 changes: 15 additions & 3 deletions src/Avalonia.Controls/Flyouts/FlyoutBase.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
using System;
using System.ComponentModel;
using Avalonia.Controls.Diagnostics;
using System.Linq;

using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Input.Raw;
using Avalonia.Layout;
using Avalonia.Logging;
using Avalonia.Rendering;

#nullable enable

namespace Avalonia.Controls.Primitives
{
public abstract class FlyoutBase : AvaloniaObject
public abstract class FlyoutBase : AvaloniaObject, IPopupHostProvider
{
static FlyoutBase()
{
Expand Down Expand Up @@ -59,6 +58,7 @@ static FlyoutBase()
private Rect? _enlargedPopupRect;
private PixelRect? _enlargePopupRectScreenPixelRect;
private IDisposable? _transientDisposable;
private Action<IPopupHost?>? _popupHostChangedHandler;

public FlyoutBase()
{
Expand Down Expand Up @@ -103,6 +103,14 @@ public Control? Target
private set => SetAndRaise(TargetProperty, ref _target, value);
}

IPopupHost? IPopupHostProvider.PopupHost => Popup?.Host;

event Action<IPopupHost?>? IPopupHostProvider.PopupHostChanged
{
add => _popupHostChangedHandler += value;
remove => _popupHostChangedHandler -= value;
}

public event EventHandler? Closed;
public event EventHandler<CancelEventArgs>? Closing;
public event EventHandler? Opened;
Expand Down Expand Up @@ -363,6 +371,8 @@ private Popup CreatePopup()
private void OnPopupOpened(object sender, EventArgs e)
{
IsOpen = true;

_popupHostChangedHandler?.Invoke(Popup!.Host);
}

private void OnPopupClosing(object sender, CancelEventArgs e)
Expand All @@ -376,6 +386,8 @@ private void OnPopupClosing(object sender, CancelEventArgs e)
private void OnPopupClosed(object sender, EventArgs e)
{
HideCore(false);

_popupHostChangedHandler?.Invoke(null);
}

// This method is handling both popup logical tree and target logical tree.
Expand Down
16 changes: 15 additions & 1 deletion src/Avalonia.Controls/Primitives/Popup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.ComponentModel;
using System.Linq;
using System.Reactive.Disposables;
using Avalonia.Controls.Diagnostics;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives.PopupPositioning;
using Avalonia.Input;
Expand All @@ -18,7 +19,7 @@ namespace Avalonia.Controls.Primitives
/// <summary>
/// Displays a popup window.
/// </summary>
public class Popup : Control, IVisualTreeHost
public class Popup : Control, IVisualTreeHost, IPopupHostProvider
{
public static readonly StyledProperty<bool> WindowManagerAddShadowHintProperty =
AvaloniaProperty.Register<PopupRoot, bool>(nameof(WindowManagerAddShadowHint), true);
Expand Down Expand Up @@ -134,6 +135,7 @@ public class Popup : Control, IVisualTreeHost
private bool _ignoreIsOpenChanged;
private PopupOpenState? _openState;
private IInputElement _overlayInputPassThroughElement;
private Action<IPopupHost?>? _popupHostChangedHandler;

/// <summary>
/// Initializes static members of the <see cref="Popup"/> class.
Expand Down Expand Up @@ -351,6 +353,14 @@ public bool Topmost
/// </summary>
IVisual? IVisualTreeHost.Root => _openState?.PopupHost.HostedVisualTreeRoot;

IPopupHost? IPopupHostProvider.PopupHost => Host;

event Action<IPopupHost?>? IPopupHostProvider.PopupHostChanged
{
add => _popupHostChangedHandler += value;
remove => _popupHostChangedHandler -= value;
}

/// <summary>
/// Opens the popup.
/// </summary>
Expand Down Expand Up @@ -482,6 +492,8 @@ void DeferCleanup(IDisposable? disposable)
}

Opened?.Invoke(this, EventArgs.Empty);

_popupHostChangedHandler?.Invoke(Host);
}

/// <summary>
Expand Down Expand Up @@ -591,6 +603,8 @@ private void CloseCore()
_openState.Dispose();
_openState = null;

_popupHostChangedHandler?.Invoke(null);

using (BeginIgnoringIsOpen())
{
IsOpen = false;
Expand Down
40 changes: 25 additions & 15 deletions src/Avalonia.Controls/ToolTip.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
#nullable enable
using System;
using System.Reactive.Linq;
using Avalonia.Controls.Diagnostics;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.VisualTree;

namespace Avalonia.Controls
{
Expand All @@ -17,7 +16,7 @@ namespace Avalonia.Controls
/// assigning the content that you want displayed.
/// </remarks>
[PseudoClasses(":open")]
public class ToolTip : ContentControl
public class ToolTip : ContentControl, IPopupHostProvider
{
/// <summary>
/// Defines the ToolTip.Tip attached property.
Expand Down Expand Up @@ -61,7 +60,8 @@ public class ToolTip : ContentControl
internal static readonly AttachedProperty<ToolTip?> ToolTipProperty =
AvaloniaProperty.RegisterAttached<ToolTip, Control, ToolTip?>("ToolTip");

private IPopupHost? _popup;
private IPopupHost? _popupHost;
private Action<IPopupHost?>? _popupHostChangedHandler;

/// <summary>
/// Initializes static members of the <see cref="ToolTip"/> class.
Expand Down Expand Up @@ -251,35 +251,45 @@ private static void RecalculatePositionOnPropertyChanged(AvaloniaPropertyChanged

tooltip.RecalculatePosition(control);
}

IPopupHost? IPopupHostProvider.PopupHost => _popupHost;

event Action<IPopupHost?>? IPopupHostProvider.PopupHostChanged
{
add => _popupHostChangedHandler += value;
remove => _popupHostChangedHandler -= value;
}

internal void RecalculatePosition(Control control)
{
_popup?.ConfigurePosition(control, GetPlacement(control), new Point(GetHorizontalOffset(control), GetVerticalOffset(control)));
_popupHost?.ConfigurePosition(control, GetPlacement(control), new Point(GetHorizontalOffset(control), GetVerticalOffset(control)));
}

private void Open(Control control)
{
Close();

_popup = OverlayPopupHost.CreatePopupHost(control, null);
_popup.SetChild(this);
((ISetLogicalParent)_popup).SetParent(control);
_popupHost = OverlayPopupHost.CreatePopupHost(control, null);
_popupHost.SetChild(this);
((ISetLogicalParent)_popupHost).SetParent(control);

_popup.ConfigurePosition(control, GetPlacement(control),
_popupHost.ConfigurePosition(control, GetPlacement(control),
new Point(GetHorizontalOffset(control), GetVerticalOffset(control)));

WindowManagerAddShadowHintChanged(_popup, false);
WindowManagerAddShadowHintChanged(_popupHost, false);

_popup.Show();
_popupHost.Show();
_popupHostChangedHandler?.Invoke(_popupHost);
}

private void Close()
{
if (_popup != null)
if (_popupHost != null)
{
_popup.SetChild(null);
_popup.Dispose();
_popup = null;
_popupHost.SetChild(null);
_popupHost.Dispose();
_popupHost = null;
_popupHostChangedHandler?.Invoke(null);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.ComponentModel;

using Avalonia.Controls;
using Avalonia.Diagnostics.Models;
using Avalonia.Input;
Expand All @@ -22,6 +21,7 @@ internal class MainViewModel : ViewModelBase, IDisposable
private bool _shouldVisualizeMarginPadding = true;
private bool _shouldVisualizeDirtyRects;
private bool _showFpsOverlay;
private bool _freezePopups;

#nullable disable
// Remove "nullable disable" after MemberNotNull will work on our CI.
Expand All @@ -41,6 +41,12 @@ public MainViewModel(TopLevel root)
Console = new ConsoleViewModel(UpdateConsoleContext);
}

public bool FreezePopups
{
get => _freezePopups;
set => RaiseAndSetIfChanged(ref _freezePopups, value);
}

public bool ShouldVisualizeMarginPadding
{
get => _shouldVisualizeMarginPadding;
Expand Down
Loading

0 comments on commit c69ab45

Please sign in to comment.