// ----------------------------------------------------------------------- // // Copyright 2015 MIT Licence. See licence.md for more information. // // ----------------------------------------------------------------------- namespace Perspex.Controls { using Perspex.Input; using Perspex.Threading; using System; using System.Reactive.Linq; using System.Reactive.Subjects; /// /// A tooltip control. /// /// /// You will probably not want to create a control directly: if added to /// the tree it will act as a simple styled to look like a tooltip. /// To add a tooltip to a control, use the attached property, /// assigning the content that you want displayed. /// public class ToolTip : ContentControl { /// /// Defines the ToolTip.Tip attached property. /// public static readonly PerspexProperty TipProperty = PerspexProperty.RegisterAttached("Tip"); /// /// The popup window used to display the active tooltip. /// private static PopupRoot popup; /// /// The control that the currently visible tooltip is attached to. /// private static Control current; /// /// Observable fired when a tooltip should be displayed for a control. The output from this /// observable is throttled and calls when the time /// period expires. /// private static Subject show = new Subject(); /// /// Statically constructs the tooltip class. /// static ToolTip() { TipProperty.Changed.Subscribe(TipChanged); show.Throttle(TimeSpan.FromSeconds(0.5), PerspexScheduler.Instance).Subscribe(ShowToolTip); } /// /// Gets the value of the ToolTip.Tip attached property. /// /// The control to get the property from. /// /// The content to be displayed in the control's tooltip. /// public static object GetTip(Control element) { return element.GetValue(TipProperty); } /// /// Sets the value of the ToolTip.Tip attached property. /// /// 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) { element.SetValue(TipProperty, value); } /// /// called when the property changes on a control. /// /// private static void TipChanged(PerspexPropertyChangedEventArgs e) { var control = (Control)e.Sender; if (e.OldValue != null) { control.PointerEnter -= ControlPointerEnter; control.PointerLeave -= ControlPointerLeave; } if (e.NewValue != null) { control.PointerEnter += ControlPointerEnter; control.PointerLeave += ControlPointerLeave; } } /// /// Shows a tooltip for the specified control. /// /// The control. private static void ShowToolTip(Control control) { if (control != null) { if (popup == null) { popup = new PopupRoot { Content = new ToolTip(), }; } var cp = MouseDevice.Instance.GetPosition(control); var position = control.PointToScreen(cp) + new Vector(0, 22); popup.Parent = control; ((ToolTip)popup.Content).Content = GetTip(control); popup.SetPosition(position); popup.Show(); current = control; } } /// /// Called when the pointer enters a control with an attached tooltip. /// /// The event sender. /// The event args. private static void ControlPointerEnter(object sender, PointerEventArgs e) { current = (Control)sender; show.OnNext(current); } /// /// Called when the pointer leaves a control with an attached tooltip. /// /// The event sender. /// The event args. private static void ControlPointerLeave(object sender, PointerEventArgs e) { var control = (Control)sender; if (control == current) { if (popup != null && popup.IsVisible) { popup.Hide(); } show.OnNext(null); } } } }