You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
3.7 KiB
114 lines
3.7 KiB
12 months ago
|
using System.Linq;
|
||
|
using Avalonia;
|
||
|
using Avalonia.Controls;
|
||
|
using Avalonia.Input;
|
||
|
using Avalonia.Interactivity;
|
||
|
using Avalonia.VisualTree;
|
||
|
using JetBrains.Annotations;
|
||
|
|
||
12 months ago
|
namespace StabilityMatrix.Avalonia.MarkupExtensions;
|
||
12 months ago
|
|
||
|
/// <summary>
|
||
|
/// Show tooltip on Controls with IsEffectivelyEnabled = false
|
||
|
/// https://github.com/AvaloniaUI/Avalonia/issues/3847#issuecomment-1618790059
|
||
|
/// </summary>
|
||
|
[PublicAPI]
|
||
|
public static class ShowDisabledTooltipExtension
|
||
|
{
|
||
|
static ShowDisabledTooltipExtension()
|
||
|
{
|
||
|
ShowOnDisabledProperty.Changed.AddClassHandler<Control>(HandleShowOnDisabledChanged);
|
||
|
}
|
||
|
|
||
|
public static bool GetShowOnDisabled(AvaloniaObject obj)
|
||
|
{
|
||
|
return obj.GetValue(ShowOnDisabledProperty);
|
||
|
}
|
||
|
|
||
|
public static void SetShowOnDisabled(AvaloniaObject obj, bool value)
|
||
|
{
|
||
|
obj.SetValue(ShowOnDisabledProperty, value);
|
||
|
}
|
||
|
|
||
12 months ago
|
public static readonly AttachedProperty<bool> ShowOnDisabledProperty = AvaloniaProperty.RegisterAttached<
|
||
|
object,
|
||
|
Control,
|
||
|
bool
|
||
|
>("ShowOnDisabled");
|
||
12 months ago
|
|
||
12 months ago
|
private static void HandleShowOnDisabledChanged(Control control, AvaloniaPropertyChangedEventArgs e)
|
||
12 months ago
|
{
|
||
12 months ago
|
if (e.GetNewValue<bool>())
|
||
12 months ago
|
{
|
||
|
control.DetachedFromVisualTree += AttachedControl_DetachedFromVisualOrExtension;
|
||
|
control.AttachedToVisualTree += AttachedControl_AttachedToVisualTree;
|
||
|
if (control.IsInitialized)
|
||
|
{
|
||
|
// enabled after visual attached
|
||
|
AttachedControl_AttachedToVisualTree(control, null!);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
AttachedControl_DetachedFromVisualOrExtension(control, null!);
|
||
|
}
|
||
|
}
|
||
|
|
||
12 months ago
|
private static void AttachedControl_AttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
|
||
12 months ago
|
{
|
||
|
if (sender is not Control control || TopLevel.GetTopLevel(control) is not { } tl)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
// NOTE pointermove needed to be tunneled for me but you may not need to...
|
||
12 months ago
|
tl.AddHandler(InputElement.PointerMovedEvent, TopLevel_PointerMoved, RoutingStrategies.Tunnel);
|
||
12 months ago
|
}
|
||
|
|
||
12 months ago
|
private static void AttachedControl_DetachedFromVisualOrExtension(object? s, VisualTreeAttachmentEventArgs e)
|
||
12 months ago
|
{
|
||
|
if (s is not Control control)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
control.DetachedFromVisualTree -= AttachedControl_DetachedFromVisualOrExtension;
|
||
|
control.AttachedToVisualTree -= AttachedControl_AttachedToVisualTree;
|
||
|
if (TopLevel.GetTopLevel(control) is not { } tl)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
tl.RemoveHandler(InputElement.PointerMovedEvent, TopLevel_PointerMoved);
|
||
|
}
|
||
|
|
||
|
private static void TopLevel_PointerMoved(object? sender, PointerEventArgs e)
|
||
|
{
|
||
|
if (sender is not Control tl)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
12 months ago
|
var attachedControls = tl.GetVisualDescendants().Where(GetShowOnDisabled).Cast<Control>().ToList();
|
||
12 months ago
|
|
||
|
// find disabled children under pointer w/ this extension enabled
|
||
|
var disabledChildUnderPointer = attachedControls.FirstOrDefault(
|
||
|
x =>
|
||
|
x.Bounds.Contains(e.GetPosition(x.Parent as Visual))
|
||
|
&& x is { IsEffectivelyVisible: true, IsEffectivelyEnabled: false }
|
||
|
);
|
||
|
|
||
|
if (disabledChildUnderPointer != null)
|
||
|
{
|
||
|
// manually show tooltip
|
||
|
ToolTip.SetIsOpen(disabledChildUnderPointer, true);
|
||
|
}
|
||
|
|
||
|
var disabledTooltipsToHide = attachedControls.Where(
|
||
|
x => ToolTip.GetIsOpen(x) && x != disabledChildUnderPointer && !x.IsEffectivelyEnabled
|
||
|
);
|
||
|
|
||
|
foreach (var control in disabledTooltipsToHide)
|
||
|
{
|
||
|
ToolTip.SetIsOpen(control, false);
|
||
|
}
|
||
|
}
|
||
|
}
|