From 5403c743441d476f2577c3d3c1b4c91e1e5a0477 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Sun, 3 Jan 2021 03:31:15 -0500 Subject: [PATCH 1/5] Recalculate ToolTip position on Offset/Placement props changed --- src/Avalonia.Controls/ToolTip.cs | 40 +++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/Avalonia.Controls/ToolTip.cs b/src/Avalonia.Controls/ToolTip.cs index 71bd0726d4..ab507d07a2 100644 --- a/src/Avalonia.Controls/ToolTip.cs +++ b/src/Avalonia.Controls/ToolTip.cs @@ -1,3 +1,4 @@ +#nullable enable using System; using System.Reactive.Linq; using Avalonia.Controls.Metadata; @@ -21,8 +22,8 @@ namespace Avalonia.Controls /// /// Defines the ToolTip.Tip attached property. /// - public static readonly AttachedProperty TipProperty = - AvaloniaProperty.RegisterAttached("Tip"); + public static readonly AttachedProperty TipProperty = + AvaloniaProperty.RegisterAttached("Tip"); /// /// Defines the ToolTip.IsOpen attached property. @@ -57,10 +58,10 @@ namespace Avalonia.Controls /// /// Stores the current instance in the control. /// - internal static readonly AttachedProperty ToolTipProperty = - AvaloniaProperty.RegisterAttached("ToolTip"); + internal static readonly AttachedProperty ToolTipProperty = + AvaloniaProperty.RegisterAttached("ToolTip"); - private IPopupHost _popup; + private IPopupHost? _popup; /// /// Initializes static members of the class. @@ -70,6 +71,10 @@ namespace Avalonia.Controls TipProperty.Changed.Subscribe(ToolTipService.Instance.TipChanged); IsOpenProperty.Changed.Subscribe(ToolTipService.Instance.TipOpenChanged); IsOpenProperty.Changed.Subscribe(IsOpenChanged); + + HorizontalOffsetProperty.Changed.Subscribe(RecalculatePositionOnPropertyChanged); + VerticalOffsetProperty.Changed.Subscribe(RecalculatePositionOnPropertyChanged); + PlacementProperty.Changed.Subscribe(RecalculatePositionOnPropertyChanged); } /// @@ -79,7 +84,7 @@ namespace Avalonia.Controls /// /// The content to be displayed in the control's tooltip. /// - public static object GetTip(Control element) + public static object? GetTip(Control element) { return element.GetValue(TipProperty); } @@ -89,7 +94,7 @@ namespace Avalonia.Controls /// /// The control to get the property from. /// The content to be displayed in the control's tooltip. - public static void SetTip(Control element, object value) + public static void SetTip(Control element, object? value) { element.SetValue(TipProperty, value); } @@ -207,8 +212,8 @@ namespace Avalonia.Controls private static void IsOpenChanged(AvaloniaPropertyChangedEventArgs e) { var control = (Control)e.Sender; - var newValue = (bool)e.NewValue; - ToolTip toolTip; + var newValue = (bool)e.NewValue!; + ToolTip? toolTip; if (newValue) { @@ -235,6 +240,23 @@ namespace Avalonia.Controls toolTip?.UpdatePseudoClasses(newValue); } + private static void RecalculatePositionOnPropertyChanged(AvaloniaPropertyChangedEventArgs args) + { + var control = (Control)args.Sender; + var tooltip = control.GetValue(ToolTipProperty); + if (tooltip == null) + { + return; + } + + tooltip.RecalculatePosition(control); + } + + internal void RecalculatePosition(Control control) + { + _popup?.ConfigurePosition(control, GetPlacement(control), new Point(GetHorizontalOffset(control), GetVerticalOffset(control))); + } + private void Open(Control control) { Close(); From 3140c1c15e14cdf4eed536e307b5f0af164153ba Mon Sep 17 00:00:00 2001 From: Max Katz Date: Sun, 3 Jan 2021 03:31:31 -0500 Subject: [PATCH 2/5] Recalculate ToolTip position on target bounds changed --- src/Avalonia.Controls/ToolTipService.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Avalonia.Controls/ToolTipService.cs b/src/Avalonia.Controls/ToolTipService.cs index 341ab2fe81..cd0fad1997 100644 --- a/src/Avalonia.Controls/ToolTipService.cs +++ b/src/Avalonia.Controls/ToolTipService.cs @@ -28,12 +28,14 @@ namespace Avalonia.Controls { control.PointerEnter -= ControlPointerEnter; control.PointerLeave -= ControlPointerLeave; + control.PropertyChanged -= Control_PropertyChanged; } if (e.NewValue != null) { control.PointerEnter += ControlPointerEnter; control.PointerLeave += ControlPointerLeave; + control.PropertyChanged += Control_PropertyChanged; } if (ToolTip.GetIsOpen(control) && e.NewValue != e.OldValue && !(e.NewValue is ToolTip)) @@ -97,6 +99,17 @@ namespace Avalonia.Controls Close(control); } + private void Control_PropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e) + { + var control = (Control)sender; + + if (e.Property == Visual.TransformedBoundsProperty) + { + var toolTip = control.GetValue(ToolTip.ToolTipProperty); + toolTip?.RecalculatePosition(control); + } + } + private void StartShowTimer(int showDelay, Control control) { _timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(showDelay) }; From 2cac9980e1ed21c4413e795394538bb2f039e0a6 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Sun, 3 Jan 2021 03:31:51 -0500 Subject: [PATCH 3/5] Update tooltip samples --- samples/ControlCatalog/Pages/SliderPage.xaml | 14 ++++++++++ samples/ControlCatalog/Pages/ToolTipPage.xaml | 27 ++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/samples/ControlCatalog/Pages/SliderPage.xaml b/samples/ControlCatalog/Pages/SliderPage.xaml index b3f32ed421..eeb198976b 100644 --- a/samples/ControlCatalog/Pages/SliderPage.xaml +++ b/samples/ControlCatalog/Pages/SliderPage.xaml @@ -22,6 +22,20 @@ IsSnapToTickEnabled="True" Ticks="0,20,25,40,75,100" Width="300" /> + + + + + ToolTip A control which pops up a hint when a control is hovered - @@ -38,6 +38,31 @@ ToolTip bottom placement + + + + + Moving offset + From ca947cc912288c464ec5e30e7c21d7b94328dac8 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Sun, 3 Jan 2021 04:04:19 -0500 Subject: [PATCH 4/5] Use Bounds instead of TransformedBoundsProperty to recalculate ToolTip position --- src/Avalonia.Controls/ToolTipService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/ToolTipService.cs b/src/Avalonia.Controls/ToolTipService.cs index cd0fad1997..d40a116dd5 100644 --- a/src/Avalonia.Controls/ToolTipService.cs +++ b/src/Avalonia.Controls/ToolTipService.cs @@ -103,7 +103,7 @@ namespace Avalonia.Controls { var control = (Control)sender; - if (e.Property == Visual.TransformedBoundsProperty) + if (e.Property == Visual.BoundsProperty) { var toolTip = control.GetValue(ToolTip.ToolTipProperty); toolTip?.RecalculatePosition(control); From ee717223f002832853d93e5d7d2b734e9431ca4d Mon Sep 17 00:00:00 2001 From: Max Katz Date: Sun, 3 Jan 2021 16:18:31 -0500 Subject: [PATCH 5/5] Use EffectiveViewportChanged instead of subscribing on PropertyChanged --- src/Avalonia.Controls/ToolTipService.cs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/Avalonia.Controls/ToolTipService.cs b/src/Avalonia.Controls/ToolTipService.cs index d40a116dd5..9e0bf60f42 100644 --- a/src/Avalonia.Controls/ToolTipService.cs +++ b/src/Avalonia.Controls/ToolTipService.cs @@ -28,14 +28,12 @@ namespace Avalonia.Controls { control.PointerEnter -= ControlPointerEnter; control.PointerLeave -= ControlPointerLeave; - control.PropertyChanged -= Control_PropertyChanged; } if (e.NewValue != null) { control.PointerEnter += ControlPointerEnter; control.PointerLeave += ControlPointerLeave; - control.PropertyChanged += Control_PropertyChanged; } if (ToolTip.GetIsOpen(control) && e.NewValue != e.OldValue && !(e.NewValue is ToolTip)) @@ -53,10 +51,12 @@ namespace Avalonia.Controls if (e.OldValue is false && e.NewValue is true) { control.DetachedFromVisualTree += ControlDetaching; + control.EffectiveViewportChanged += ControlEffectiveViewportChanged; } else if(e.OldValue is true && e.NewValue is false) { control.DetachedFromVisualTree -= ControlDetaching; + control.EffectiveViewportChanged -= ControlEffectiveViewportChanged; } } @@ -64,6 +64,7 @@ namespace Avalonia.Controls { var control = (Control)sender; control.DetachedFromVisualTree -= ControlDetaching; + control.EffectiveViewportChanged -= ControlEffectiveViewportChanged; Close(control); } @@ -99,15 +100,11 @@ namespace Avalonia.Controls Close(control); } - private void Control_PropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e) + private void ControlEffectiveViewportChanged(object sender, Layout.EffectiveViewportChangedEventArgs e) { var control = (Control)sender; - - if (e.Property == Visual.BoundsProperty) - { - var toolTip = control.GetValue(ToolTip.ToolTipProperty); - toolTip?.RecalculatePosition(control); - } + var toolTip = control.GetValue(ToolTip.ToolTipProperty); + toolTip?.RecalculatePosition(control); } private void StartShowTimer(int showDelay, Control control)