Browse Source

implement tooltip handling for IconBarMargin/Bookmarks

filemodels
Siegfried Pammer 12 years ago
parent
commit
8bae9c401f
  1. 153
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/IconBarMargin.cs
  2. 5
      src/Main/Base/Project/Editor/Bookmarks/BookmarkBase.cs
  3. 5
      src/Main/Base/Project/Editor/Bookmarks/EntityBookmark.cs
  4. 5
      src/Main/Base/Project/Editor/Bookmarks/IBookmark.cs

153
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/IconBarMargin.cs

@ -18,13 +18,17 @@ @@ -18,13 +18,17 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.AvalonEdit.Utils;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.Bookmarks;
@ -37,12 +41,17 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -37,12 +41,17 @@ namespace ICSharpCode.AvalonEdit.AddIn
public class IconBarMargin : AbstractMargin, IDisposable
{
readonly IBookmarkMargin manager;
readonly MouseHoverLogic hoverLogic;
public IconBarMargin(IBookmarkMargin manager)
{
if (manager == null)
throw new ArgumentNullException("manager");
this.manager = manager;
this.hoverLogic = new MouseHoverLogic(this);
this.hoverLogic.MouseHover += (sender, e) => MouseHover(this, e);
this.hoverLogic.MouseHoverStopped += (sender, e) => MouseHoverStopped(this, e);
this.Unloaded += OnUnloaded;
}
#region OnTextViewChanged
@ -51,11 +60,13 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -51,11 +60,13 @@ namespace ICSharpCode.AvalonEdit.AddIn
{
if (oldTextView != null) {
oldTextView.VisualLinesChanged -= OnRedrawRequested;
oldTextView.MouseMove -= TextViewMouseMove;
manager.RedrawRequested -= OnRedrawRequested;
}
base.OnTextViewChanged(oldTextView, newTextView);
if (newTextView != null) {
newTextView.VisualLinesChanged += OnRedrawRequested;
newTextView.MouseMove += TextViewMouseMove;
manager.RedrawRequested += OnRedrawRequested;
}
InvalidateVisual();
@ -228,6 +239,7 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -228,6 +239,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
dragStarted = true;
InvalidateVisual();
}
TextViewMouseMove(TextView, e);
}
protected override void OnMouseUp(MouseButtonEventArgs e)
@ -259,5 +271,146 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -259,5 +271,146 @@ namespace ICSharpCode.AvalonEdit.AddIn
}
}
}
#region Tooltip
ToolTip toolTip;
Popup popupToolTip;
void MouseHover(object sender, MouseEventArgs e)
{
Debug.Assert(sender == this);
if (!TryCloseExistingPopup(false)) {
return;
}
int line = GetLineFromMousePosition(e);
if (line < 1) return;
IBookmark bm = GetBookmarkFromLine(line);
if (bm == null) return;
object content = bm.CreateTooltipContent();
popupToolTip = content as Popup;
if (popupToolTip != null) {
var popupPosition = GetPopupPosition(line);
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();
toolTip.Closed += ToolTipClosed;
}
toolTip.PlacementTarget = this; // required for property inheritance
if (content is string) {
toolTip.Content = new TextBlock
{
Text = content as string,
TextWrapping = TextWrapping.Wrap
};
} else toolTip.Content = content;
e.Handled = true;
toolTip.IsOpen = true;
}
}
bool TryCloseExistingPopup(bool mouseClick)
{
if (popupToolTip != null) {
if (popupToolTip.IsOpen && !mouseClick && popupToolTip is ITooltip && !((ITooltip)popupToolTip).CloseWhenMouseMovesAway) {
return false; // Popup does not want to be closed yet
}
popupToolTip.IsOpen = false;
popupToolTip = null;
}
return true;
}
Point GetPopupPosition(int line)
{
Point positionInPixels = TextView.PointToScreen(TextView.GetVisualPosition(new TextViewPosition(line, 1), VisualYPosition.LineBottom) - this.TextView.ScrollOffset);
positionInPixels.X -= 50;
// use device independent units, because Popup Left/Top are in independent units
return positionInPixels.TransformFromDevice(this);
}
void MouseHoverStopped(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;
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);
}
protected override void OnMouseLeave(MouseEventArgs e)
{
if (popupToolTip != null && !popupToolTip.IsMouseOver) {
// do not close popup if mouse moved from editor to popup
TryCloseExistingPopup(false);
}
}
void TextViewMouseMove(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);
}
}
}
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, EventArgs e)
{
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
}
}

5
src/Main/Base/Project/Editor/Bookmarks/BookmarkBase.cs

@ -194,5 +194,10 @@ namespace ICSharpCode.SharpDevelop.Editor.Bookmarks @@ -194,5 +194,10 @@ namespace ICSharpCode.SharpDevelop.Editor.Bookmarks
public virtual void Drop(int lineNumber)
{
}
public virtual object CreateTooltipContent()
{
return null;
}
}
}

5
src/Main/Base/Project/Editor/Bookmarks/EntityBookmark.cs

@ -97,5 +97,10 @@ namespace ICSharpCode.SharpDevelop.Editor.Bookmarks @@ -97,5 +97,10 @@ namespace ICSharpCode.SharpDevelop.Editor.Bookmarks
{
throw new NotSupportedException();
}
object IBookmark.CreateTooltipContent()
{
return null;
}
}
}

5
src/Main/Base/Project/Editor/Bookmarks/IBookmark.cs

@ -60,5 +60,10 @@ namespace ICSharpCode.SharpDevelop.Editor.Bookmarks @@ -60,5 +60,10 @@ namespace ICSharpCode.SharpDevelop.Editor.Bookmarks
/// Notifies the bookmark that it was dropped on the specified line.
/// </summary>
void Drop(int lineNumber);
/// <summary>
/// Creates the tooltip content for the bookmark.
/// </summary>
object CreateTooltipContent();
}
}

Loading…
Cancel
Save