Browse Source

Close editor popups (FlowDocumentPopup + debugger popups) when the mouse moves away from them.

Fix popup not closing when switching to another document.
pull/32/merge
Daniel Grunwald 12 years ago
parent
commit
f57aee42c0
  1. 2
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml.cs
  2. 69
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs
  3. 11
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/XmlDoc/XmlDocTooltipProvider.cs
  4. 2
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs
  5. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/MemberLookup.cs
  6. 2
      src/Main/Base/Project/Editor/ITooltip.cs

2
src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml.cs

@ -73,7 +73,7 @@ namespace Debugger.AddIn.Tooltips @@ -73,7 +73,7 @@ namespace Debugger.AddIn.Tooltips
}
}
bool ITooltip.CloseOnHoverEnd {
bool ITooltip.CloseWhenMouseMovesAway {
get {
return this.ChildTooltip == null;
}

69
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs

@ -64,7 +64,9 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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

11
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/XmlDoc/XmlDocTooltipProvider.cs

@ -6,6 +6,7 @@ using System.Windows; @@ -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 @@ -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;
}
}

2
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs

@ -247,7 +247,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -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);
}));

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/MemberLookup.cs

@ -83,7 +83,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -83,7 +83,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// <param name="allowProtectedAccess">
/// 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.
/// </param>
public bool IsAccessible(IEntity entity, bool allowProtectedAccess)
{

2
src/Main/Base/Project/Editor/ITooltip.cs

@ -9,6 +9,6 @@ namespace ICSharpCode.SharpDevelop.Editor @@ -9,6 +9,6 @@ namespace ICSharpCode.SharpDevelop.Editor
public interface ITooltip
{
/// <summary> Should the tooltip close when the mouse moves away? </summary>
bool CloseOnHoverEnd { get; }
bool CloseWhenMouseMovesAway { get; }
}
}

Loading…
Cancel
Save