From f59c66ba3d896de574c7616211d5648e2e5c6fdc Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Thu, 3 Feb 2011 22:39:24 +0100 Subject: [PATCH] move MouseHover logic from TextView to separate class and make it reusable --- .../Src/ChangeMarkerMargin.cs | 18 +--- .../ICSharpCode.AvalonEdit.csproj | 1 + .../Rendering/MouseHoverLogic.cs | 102 ++++++++++++++++++ .../Rendering/TextView.cs | 65 ++--------- 4 files changed, 114 insertions(+), 72 deletions(-) create mode 100644 src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/MouseHoverLogic.cs diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ChangeMarkerMargin.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ChangeMarkerMargin.cs index f4edcadc1d..c3d8071d95 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ChangeMarkerMargin.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ChangeMarkerMargin.cs @@ -33,10 +33,8 @@ namespace ICSharpCode.AvalonEdit.AddIn public ChangeMarkerMargin(IChangeWatcher changeWatcher) { this.changeWatcher = changeWatcher; - this.delayTimer = new DispatcherTimer() { - Interval = SystemParameters.MouseHoverTime - }; - delayTimer.Tick += delegate { DisplayTooltip(); }; + this.hoverLogic = new MouseHoverLogic(this); + this.hoverLogic.MouseHover += delegate { DisplayTooltip(); }; changeWatcher.ChangeOccurred += ChangeOccurred; } @@ -128,19 +126,10 @@ namespace ICSharpCode.AvalonEdit.AddIn Popup tooltip = new Popup() { StaysOpen = false }; ITextMarker marker; ITextMarkerService markerService; - DispatcherTimer delayTimer; - - protected override void OnMouseEnter(MouseEventArgs e) - { - delayTimer.Start(); - - base.OnMouseEnter(e); - } + MouseHoverLogic hoverLogic; void DisplayTooltip() { - delayTimer.Stop(); - int line = GetLineFromMousePosition(); if (line == 0) @@ -239,7 +228,6 @@ namespace ICSharpCode.AvalonEdit.AddIn protected override void OnMouseLeave(MouseEventArgs e) { - delayTimer.Stop(); if (marker != null && !tooltip.IsOpen) markerService.Remove(marker); base.OnMouseLeave(e); diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj index d572f6c8b0..8484dd233b 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj @@ -257,6 +257,7 @@ TextView.cs + FormattedTextElement.cs diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/MouseHoverLogic.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/MouseHoverLogic.cs new file mode 100644 index 0000000000..3c3a70c486 --- /dev/null +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/MouseHoverLogic.cs @@ -0,0 +1,102 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Windows; +using System.Windows.Input; +using System.Windows.Threading; + +namespace ICSharpCode.AvalonEdit.Rendering +{ + public class MouseHoverLogic : IDisposable + { + UIElement target; + + DispatcherTimer mouseHoverTimer; + Point mouseHoverStartPoint; + MouseEventArgs mouseHoverLastEventArgs; + bool mouseHovering; + + public MouseHoverLogic(UIElement target) + { + if (target == null) + throw new ArgumentNullException("target"); + this.target = target; + this.target.MouseLeave += MouseHoverLogicMouseLeave; + this.target.MouseMove += MouseHoverLogicMouseMove; + } + + void MouseHoverLogicMouseMove(object sender, MouseEventArgs e) + { + Point newPosition = e.GetPosition(this.target); + Vector mouseMovement = mouseHoverStartPoint - newPosition; + if (Math.Abs(mouseMovement.X) > SystemParameters.MouseHoverWidth + || Math.Abs(mouseMovement.Y) > SystemParameters.MouseHoverHeight) + { + StopHovering(); + mouseHoverStartPoint = newPosition; + mouseHoverLastEventArgs = e; + mouseHoverTimer = new DispatcherTimer(SystemParameters.MouseHoverTime, DispatcherPriority.Background, + OnMouseHoverTimerElapsed, this.target.Dispatcher); + mouseHoverTimer.Start(); + } + // do not set e.Handled - allow others to also handle MouseMove + } + + void MouseHoverLogicMouseLeave(object sender, MouseEventArgs e) + { + StopHovering(); + // do not set e.Handled - allow others to also handle MouseLeave + } + + void StopHovering() + { + if (mouseHoverTimer != null) { + mouseHoverTimer.Stop(); + mouseHoverTimer = null; + } + if (mouseHovering) { + mouseHovering = false; + OnMouseHoverStopped(mouseHoverLastEventArgs); + } + } + + void OnMouseHoverTimerElapsed(object sender, EventArgs e) + { + mouseHoverTimer.Stop(); + mouseHoverTimer = null; + + mouseHovering = true; + OnMouseHover(mouseHoverLastEventArgs); + } + + public event EventHandler MouseHover; + + protected virtual void OnMouseHover(MouseEventArgs e) + { + if (MouseHover != null) { + MouseHover(this, e); + } + } + + public event EventHandler MouseHoverStopped; + + protected virtual void OnMouseHoverStopped(MouseEventArgs e) + { + if (MouseHoverStopped != null) { + MouseHoverStopped(this, e); + } + } + + bool disposed; + + public void Dispose() + { + if (!disposed) { + this.target.MouseLeave -= MouseHoverLogicMouseLeave; + this.target.MouseMove -= MouseHoverLogicMouseMove; + } + disposed = true; + } + } +} diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs index 1a67c34bdb..76b4a55635 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs @@ -55,6 +55,10 @@ namespace ICSharpCode.AvalonEdit.Rendering layers = new UIElementCollection(this, this); InsertLayer(textLayer, KnownLayer.Text, LayerInsertionPosition.Replace); + + this.hoverLogic = new MouseHoverLogic(this); + this.hoverLogic.MouseHover += (sender, e) => RaiseHoverEventPair(e, PreviewMouseHoverEvent, MouseHoverEvent); + this.hoverLogic.MouseHoverStopped += (sender, e) => RaiseHoverEventPair(e, PreviewMouseHoverStoppedEvent, MouseHoverStoppedEvent); } #endregion @@ -1566,63 +1570,12 @@ namespace ICSharpCode.AvalonEdit.Rendering remove { RemoveHandler(MouseHoverStoppedEvent, value); } } - DispatcherTimer mouseHoverTimer; - Point mouseHoverStartPoint; - MouseEventArgs mouseHoverLastEventArgs; - bool mouseHovering; - - /// - protected override void OnMouseMove(MouseEventArgs e) - { - base.OnMouseMove(e); - Point newPosition = e.GetPosition(this); - Vector mouseMovement = mouseHoverStartPoint - newPosition; - if (Math.Abs(mouseMovement.X) > SystemParameters.MouseHoverWidth - || Math.Abs(mouseMovement.Y) > SystemParameters.MouseHoverHeight) - { - StopHovering(); - mouseHoverStartPoint = newPosition; - mouseHoverLastEventArgs = e; - mouseHoverTimer = new DispatcherTimer(SystemParameters.MouseHoverTime, DispatcherPriority.Background, - OnMouseHoverTimerElapsed, this.Dispatcher); - mouseHoverTimer.Start(); - } - // do not set e.Handled - allow others to also handle MouseMove - } - - /// - protected override void OnMouseLeave(MouseEventArgs e) - { - base.OnMouseLeave(e); - StopHovering(); - // do not set e.Handled - allow others to also handle MouseLeave - } - - void StopHovering() - { - if (mouseHoverTimer != null) { - mouseHoverTimer.Stop(); - mouseHoverTimer = null; - } - if (mouseHovering) { - mouseHovering = false; - RaiseHoverEventPair(PreviewMouseHoverStoppedEvent, MouseHoverStoppedEvent); - } - } + MouseHoverLogic hoverLogic; - void OnMouseHoverTimerElapsed(object sender, EventArgs e) + void RaiseHoverEventPair(MouseEventArgs e, RoutedEvent tunnelingEvent, RoutedEvent bubblingEvent) { - mouseHoverTimer.Stop(); - mouseHoverTimer = null; - - mouseHovering = true; - RaiseHoverEventPair(PreviewMouseHoverEvent, MouseHoverEvent); - } - - void RaiseHoverEventPair(RoutedEvent tunnelingEvent, RoutedEvent bubblingEvent) - { - var mouseDevice = mouseHoverLastEventArgs.MouseDevice; - var stylusDevice = mouseHoverLastEventArgs.StylusDevice; + var mouseDevice = e.MouseDevice; + var stylusDevice = e.StylusDevice; int inputTime = Environment.TickCount; var args1 = new MouseEventArgs(mouseDevice, inputTime, stylusDevice) { RoutedEvent = tunnelingEvent, @@ -1636,8 +1589,6 @@ namespace ICSharpCode.AvalonEdit.Rendering }; RaiseEvent(args2); } - - #endregion ///