diff --git a/src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml.cs b/src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml.cs
index 995387b0e7..75c8dd77e2 100644
--- a/src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml.cs
+++ b/src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml.cs
@@ -73,7 +73,7 @@ namespace Debugger.AddIn.Tooltips
}
}
- bool ITooltip.CloseOnHoverEnd {
+ bool ITooltip.CloseWhenMouseMovesAway {
get {
return this.ChildTooltip == null;
}
diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs
index 931687437b..c9b5606026 100755
--- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs
+++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs
@@ -64,7 +64,9 @@ namespace ICSharpCode.AvalonEdit.AddIn
this.MouseHover += TextEditorMouseHover;
this.MouseHoverStopped += TextEditorMouseHoverStopped;
+ this.MouseMove += TextEditorMouseMove;
this.MouseLeave += TextEditorMouseLeave;
+ this.Unloaded += OnUnloaded;
this.TextArea.TextView.MouseDown += TextViewMouseDown;
this.TextArea.Caret.PositionChanged += HighlightBrackets;
this.TextArea.TextView.VisualLinesChanged += CodeEditorView_VisualLinesChanged;
@@ -240,6 +242,11 @@ namespace ICSharpCode.AvalonEdit.AddIn
void TextEditorMouseHover(object sender, MouseEventArgs e)
{
Debug.Assert(sender == this);
+
+ if (!TryCloseExistingPopup(false)) {
+ return;
+ }
+
ToolTipRequestEventArgs args = new ToolTipRequestEventArgs(this.Adapter);
var pos = this.TextArea.TextView.GetPositionFloor(e.GetPosition(this.TextArea.TextView) + this.TextArea.TextView.ScrollOffset);
args.InDocument = pos.HasValue;
@@ -252,21 +259,19 @@ namespace ICSharpCode.AvalonEdit.AddIn
ToolTipRequestService.RequestToolTip(args);
}
- if (!TryCloseExistingPopup(false)) {
- return;
- }
-
if (args.ContentToShow != null) {
popupToolTip = args.ContentToShow as Popup;
if (popupToolTip != null) {
var popupPosition = GetPopupPosition(e);
+ popupToolTip.Closed += ToolTipClosed;
popupToolTip.HorizontalOffset = popupPosition.X;
popupToolTip.VerticalOffset = popupPosition.Y;
popupToolTip.StaysOpen = true; // We will close it ourselves
e.Handled = true;
popupToolTip.IsOpen = true;
+ distanceToPopupLimit = double.PositiveInfinity; // reset limit; we'll re-calculate it on the next mouse movement
} else {
if (toolTip == null) {
toolTip = new ToolTip();
@@ -293,7 +298,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
bool TryCloseExistingPopup(bool mouseClick)
{
if (popupToolTip != null) {
- if (popupToolTip.IsOpen && !mouseClick && popupToolTip is ITooltip && !((ITooltip)popupToolTip).CloseOnHoverEnd) {
+ if (popupToolTip.IsOpen && !mouseClick && popupToolTip is ITooltip && !((ITooltip)popupToolTip).CloseWhenMouseMovesAway) {
return false; // Popup does not want to be closed yet
}
popupToolTip.IsOpen = false;
@@ -324,12 +329,47 @@ namespace ICSharpCode.AvalonEdit.AddIn
void TextEditorMouseHoverStopped(object sender, MouseEventArgs e)
{
+ // Non-popup tooltips get closed as soon as the mouse starts moving again
if (toolTip != null) {
toolTip.IsOpen = false;
e.Handled = true;
}
}
+ double distanceToPopupLimit;
+ const double MaxMovementAwayFromPopup = 5;
+
+ void TextEditorMouseMove(object sender, MouseEventArgs e)
+ {
+ if (popupToolTip != null) {
+ double distanceToPopup = GetDistanceToPopup(e);
+ if (distanceToPopup > distanceToPopupLimit) {
+ // Close popup if mouse moved away, exceeding the limit
+ TryCloseExistingPopup(false);
+ } else {
+ // reduce distanceToPopupLimit
+ distanceToPopupLimit = Math.Min(distanceToPopupLimit, distanceToPopup + MaxMovementAwayFromPopup);
+ }
+ }
+ }
+
+ double GetDistanceToPopup(MouseEventArgs e)
+ {
+ Point p = popupToolTip.Child.PointFromScreen(PointToScreen(e.GetPosition(this)));
+ Size size = popupToolTip.Child.RenderSize;
+ double x = 0;
+ if (p.X < 0)
+ x = -p.X;
+ else if (p.X > size.Width)
+ x = p.X - size.Width;
+ double y = 0;
+ if (p.Y < 0)
+ y = -p.Y;
+ else if (p.Y > size.Height)
+ y = p.Y - size.Height;
+ return Math.Sqrt(x * x + y * y);
+ }
+
void TextEditorMouseLeave(object sender, MouseEventArgs e)
{
if (popupToolTip != null && !popupToolTip.IsMouseOver) {
@@ -337,10 +377,25 @@ namespace ICSharpCode.AvalonEdit.AddIn
TryCloseExistingPopup(false);
}
}
+
+ void OnUnloaded(object sender, EventArgs e)
+ {
+ // Close popup when another document gets selected
+ // TextEditorMouseLeave is not sufficient for this because the mouse might be over the popup when the document switch happens (e.g. Ctrl+Tab)
+ TryCloseExistingPopup(true);
+ }
- void ToolTipClosed(object sender, RoutedEventArgs e)
+ void ToolTipClosed(object sender, EventArgs e)
{
- toolTip = null;
+ if (toolTip == sender) {
+ toolTip = null;
+ }
+ if (popupToolTip == sender) {
+ // Because popupToolTip instances are created by the tooltip provider,
+ // they might be reused; so we should detach the event handler
+ popupToolTip.Closed -= ToolTipClosed;
+ popupToolTip = null;
+ }
}
#endregion
diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/XmlDoc/XmlDocTooltipProvider.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/XmlDoc/XmlDocTooltipProvider.cs
index 28e9732bf9..38774dca6a 100644
--- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/XmlDoc/XmlDocTooltipProvider.cs
+++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/XmlDoc/XmlDocTooltipProvider.cs
@@ -6,6 +6,7 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
+using System.Windows.Input;
using System.Windows.Media;
using ICSharpCode.AvalonEdit.AddIn.Options;
using ICSharpCode.NRefactory.Semantics;
@@ -56,8 +57,14 @@ namespace ICSharpCode.AvalonEdit.AddIn.XmlDoc
document.FontSize = CodeEditorOptions.Instance.FontSize;
}
- public bool CloseOnHoverEnd {
- get { return true; }
+ public bool CloseWhenMouseMovesAway {
+ get { return !this.IsKeyboardFocusWithin; }
+ }
+
+ protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
+ {
+ base.OnLostKeyboardFocus(e);
+ this.IsOpen = false;
}
}
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs
index d52b47ed9d..97c252d5f1 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs
@@ -247,7 +247,7 @@ namespace ICSharpCode.AvalonEdit.Editing
// we re-throw them later to allow the application's unhandled exception handler
// to catch them
textArea.Dispatcher.BeginInvoke(
- DispatcherPriority.Normal,
+ DispatcherPriority.Send,
new Action(delegate {
throw new DragDropException("Exception during drag'n'drop", ex);
}));
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/MemberLookup.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/MemberLookup.cs
index c1d5a9e432..2e0b8aa119 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/MemberLookup.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/MemberLookup.cs
@@ -83,7 +83,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
///
/// Whether protected access to instance members is allowed.
/// True if the type of the reference is derived from the current class.
- /// Protected static members may be accessibe even if false is passed for this parameter.
+ /// Protected static members may be accessible even if false is passed for this parameter.
///
public bool IsAccessible(IEntity entity, bool allowProtectedAccess)
{
diff --git a/src/Main/Base/Project/Editor/ITooltip.cs b/src/Main/Base/Project/Editor/ITooltip.cs
index 5e338ff1d5..cdfb59ec61 100644
--- a/src/Main/Base/Project/Editor/ITooltip.cs
+++ b/src/Main/Base/Project/Editor/ITooltip.cs
@@ -9,6 +9,6 @@ namespace ICSharpCode.SharpDevelop.Editor
public interface ITooltip
{
/// Should the tooltip close when the mouse moves away?
- bool CloseOnHoverEnd { get; }
+ bool CloseWhenMouseMovesAway { get; }
}
}