Browse Source

Add tooltips controls

pull/191/merge
Eusebiu Marcu 16 years ago
parent
commit
9f1028cbf3
  1. 105
      Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs
  2. 54
      Debugger/ILSpy.Debugger/AvalonEdit/TextEditorWeakEventManager.cs
  3. 4
      Debugger/ILSpy.Debugger/ILSpy.Debugger.csproj
  4. 121
      Debugger/ILSpy.Debugger/Services/Debugger/DebuggerService.cs
  5. 24
      Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs
  6. 71
      Debugger/ILSpy.Debugger/ToolTips/Models/ToolTipRequestEventArgs.cs
  7. 197
      Debugger/ILSpy.Debugger/ToolTips/TextEditorListener.cs
  8. 6
      ILSpy/TextView/DecompilerTextView.cs

105
Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs

@ -28,6 +28,7 @@ using ICSharpCode.AvalonEdit.Utils;
using ICSharpCode.Decompiler.Disassembler; using ICSharpCode.Decompiler.Disassembler;
using ILSpy.Debugger.Bookmarks; using ILSpy.Debugger.Bookmarks;
using ILSpy.Debugger.Services; using ILSpy.Debugger.Services;
using ILSpy.Debugger.ToolTips;
using Mono.Cecil; using Mono.Cecil;
namespace ILSpy.Debugger.AvalonEdit namespace ILSpy.Debugger.AvalonEdit
@ -87,47 +88,12 @@ namespace ILSpy.Debugger.AvalonEdit
BookmarkBase bm; BookmarkBase bm;
if (bookmarkDict.TryGetValue(lineNumber, out bm)) { if (bookmarkDict.TryGetValue(lineNumber, out bm)) {
Rect rect = new Rect(0, PixelSnapHelpers.Round(line.VisualTop - textView.VerticalOffset, pixelSize.Height), 16, 16); Rect rect = new Rect(0, PixelSnapHelpers.Round(line.VisualTop - textView.VerticalOffset, pixelSize.Height), 16, 16);
if (dragDropBookmark == bm && dragStarted)
drawingContext.PushOpacity(0.5);
drawingContext.DrawImage(bm.Image, rect); drawingContext.DrawImage(bm.Image, rect);
if (dragDropBookmark == bm && dragStarted)
drawingContext.Pop();
} }
} }
if (dragDropBookmark != null && dragStarted) {
Rect rect = new Rect(0, PixelSnapHelpers.Round(dragDropCurrentPoint - 8, pixelSize.Height), 16, 16);
drawingContext.DrawImage(dragDropBookmark.Image, rect);
}
} }
} }
IBookmark dragDropBookmark; // bookmark being dragged (!=null if drag'n'drop is active)
double dragDropStartPoint;
double dragDropCurrentPoint;
bool dragStarted; // whether drag'n'drop operation has started (mouse was moved minimum distance)
protected override void OnMouseDown(MouseButtonEventArgs e)
{
CancelDragDrop();
base.OnMouseDown(e);
int line = GetLineFromMousePosition(e);
if (!e.Handled && line > 0) {
IBookmark bm = GetBookmarkFromLine(line);
if (bm != null) {
bm.MouseDown(e);
if (!e.Handled) {
if (e.ChangedButton == MouseButton.Left && bm.CanDragDrop && CaptureMouse()) {
StartDragDrop(bm, e);
e.Handled = true;
}
}
}
}
// don't allow selecting text through the IconBarMargin
if (e.ChangedButton == MouseButton.Left)
e.Handled = true;
}
BookmarkBase GetBookmarkFromLine(int line) BookmarkBase GetBookmarkFromLine(int line)
{ {
BookmarkBase result = null; BookmarkBase result = null;
@ -142,46 +108,6 @@ namespace ILSpy.Debugger.AvalonEdit
return result; return result;
} }
protected override void OnLostMouseCapture(MouseEventArgs e)
{
CancelDragDrop();
base.OnLostMouseCapture(e);
}
void StartDragDrop(IBookmark bm, MouseEventArgs e)
{
dragDropBookmark = bm;
dragDropStartPoint = dragDropCurrentPoint = e.GetPosition(this).Y;
if (TextView != null) {
TextArea area = TextView.Services.GetService(typeof(TextArea)) as TextArea;
if (area != null)
area.PreviewKeyDown += TextArea_PreviewKeyDown;
}
}
void CancelDragDrop()
{
if (dragDropBookmark != null) {
dragDropBookmark = null;
dragStarted = false;
if (TextView != null) {
TextArea area = TextView.Services.GetService(typeof(TextArea)) as TextArea;
if (area != null)
area.PreviewKeyDown -= TextArea_PreviewKeyDown;
}
ReleaseMouseCapture();
InvalidateVisual();
}
}
void TextArea_PreviewKeyDown(object sender, KeyEventArgs e)
{
// any key press cancels drag'n'drop
CancelDragDrop();
if (e.Key == Key.Escape)
e.Handled = true;
}
int GetLineFromMousePosition(MouseEventArgs e) int GetLineFromMousePosition(MouseEventArgs e)
{ {
TextView textView = this.TextView; TextView textView = this.TextView;
@ -193,44 +119,25 @@ namespace ILSpy.Debugger.AvalonEdit
return vl.FirstDocumentLine.LineNumber; return vl.FirstDocumentLine.LineNumber;
} }
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (dragDropBookmark != null) {
dragDropCurrentPoint = e.GetPosition(this).Y;
if (Math.Abs(dragDropCurrentPoint - dragDropStartPoint) > SystemParameters.MinimumVerticalDragDistance)
dragStarted = true;
InvalidateVisual();
}
}
protected override void OnMouseUp(MouseButtonEventArgs e) protected override void OnMouseUp(MouseButtonEventArgs e)
{ {
base.OnMouseUp(e); base.OnMouseUp(e);
int line = GetLineFromMousePosition(e); int line = GetLineFromMousePosition(e);
if (!e.Handled && dragDropBookmark != null) {
if (dragStarted) {
if (line != 0)
dragDropBookmark.Drop(line);
e.Handled = true;
}
CancelDragDrop();
}
if (!e.Handled && line != 0) { if (!e.Handled && line != 0) {
IBookmark bm = GetBookmarkFromLine(line); IBookmark bm = GetBookmarkFromLine(line);
if (bm != null) { if (bm != null) {
bm.MouseUp(e); bm.MouseUp(e);
if (IconBarMargin.CurrentType != null) { if (CurrentType != null) {
DebuggerService.ToggleBreakpointAt(IconBarMargin.CurrentType.FullName, line); DebuggerService.ToggleBreakpointAt(CurrentType.FullName, line);
} }
InvalidateVisual(); InvalidateVisual();
if (e.Handled) if (e.Handled)
return; return;
} }
if (e.ChangedButton == MouseButton.Left && TextView != null) { if (e.ChangedButton == MouseButton.Left) {
if (IconBarMargin.CurrentType != null) { if (CurrentType != null) {
// no bookmark on the line: create a new breakpoint // no bookmark on the line: create a new breakpoint
DebuggerService.ToggleBreakpointAt(IconBarMargin.CurrentType.FullName, line); DebuggerService.ToggleBreakpointAt(CurrentType.FullName, line);
} }
} }
InvalidateVisual(); InvalidateVisual();

54
Debugger/ILSpy.Debugger/AvalonEdit/TextEditorWeakEventManager.cs

@ -0,0 +1,54 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows;
using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.Utils;
namespace ILSpy.Debugger.AvalonEdit
{
public static class TextEditorWeakEventManager
{
public sealed class MouseHover : WeakEventManagerBase<MouseHover, TextEditor>
{
protected override void StopListening(TextEditor source)
{
source.MouseHover -= DeliverEvent;
}
protected override void StartListening(TextEditor source)
{
source.MouseHover += DeliverEvent;
}
}
public sealed class MouseHoverStopped : WeakEventManagerBase<MouseHoverStopped, TextEditor>
{
protected override void StopListening(TextEditor source)
{
source.MouseHoverStopped -= DeliverEvent;
}
protected override void StartListening(TextEditor source)
{
source.MouseHoverStopped += DeliverEvent;
}
}
}
}

4
Debugger/ILSpy.Debugger/ILSpy.Debugger.csproj

@ -52,6 +52,7 @@
<Reference Include="WindowsBase" /> <Reference Include="WindowsBase" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="AvalonEdit\TextEditorWeakEventManager.cs" />
<Compile Include="AvalonEdit\Editor\AvalonEditTextSourceAdapter.cs" /> <Compile Include="AvalonEdit\Editor\AvalonEditTextSourceAdapter.cs" />
<Compile Include="AvalonEdit\Editor\IDocument.cs" /> <Compile Include="AvalonEdit\Editor\IDocument.cs" />
<Compile Include="AvalonEdit\Editor\IDocumentLine.cs" /> <Compile Include="AvalonEdit\Editor\IDocumentLine.cs" />
@ -97,6 +98,8 @@
<DependentUpon>DebuggerTooltipControl.xaml</DependentUpon> <DependentUpon>DebuggerTooltipControl.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="ToolTips\LazyItemsControl.cs" /> <Compile Include="ToolTips\LazyItemsControl.cs" />
<Compile Include="ToolTips\Models\ToolTipRequestEventArgs.cs" />
<Compile Include="ToolTips\TextEditorListener.cs" />
<Compile Include="ToolTips\VirtualizingIEnumerable.cs" /> <Compile Include="ToolTips\VirtualizingIEnumerable.cs" />
<Compile Include="UI\AttachToProcessWindow.xaml.cs"> <Compile Include="UI\AttachToProcessWindow.xaml.cs">
<DependentUpon>AttachToProcessWindow.xaml</DependentUpon> <DependentUpon>AttachToProcessWindow.xaml</DependentUpon>
@ -106,6 +109,7 @@
<ItemGroup> <ItemGroup>
<Folder Include="Models\TreeModel" /> <Folder Include="Models\TreeModel" />
<Folder Include="ToolTips" /> <Folder Include="ToolTips" />
<Folder Include="ToolTips\Models" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Page Include="ToolTips\DebuggerTooltipControl.xaml" /> <Page Include="ToolTips\DebuggerTooltipControl.xaml" />

121
Debugger/ILSpy.Debugger/Services/Debugger/DebuggerService.cs

@ -3,10 +3,15 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Text; using System.Text;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.NRefactory; using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ILSpy.Debugger.Bookmarks; using ILSpy.Debugger.Bookmarks;
using ILSpy.Debugger.ToolTips;
namespace ILSpy.Debugger.Services namespace ILSpy.Debugger.Services
{ {
@ -194,52 +199,72 @@ namespace ILSpy.Debugger.Services
/// showing its current value (when in debugging mode) can be returned /// showing its current value (when in debugging mode) can be returned
/// through the ToolTipRequestEventArgs.SetTooltip() method. /// through the ToolTipRequestEventArgs.SetTooltip() method.
/// </summary> /// </summary>
// internal static void HandleToolTipRequest(ToolTipRequestEventArgs e) internal static void HandleToolTipRequest(ToolTipRequestEventArgs e)
// { {
if (currentDebugger == null || !currentDebugger.IsDebugging) {
e.ContentToShow = "test";
}
else {
e.ContentToShow = currentDebugger.GetTooltipControl(e.LogicalPosition, "test");
}
// FIXME
// if (!e.InDocument) // if (!e.InDocument)
// return; // return;
// Location logicPos = e.LogicalPosition; // var logicPos = e.LogicalPosition;
// var doc = e.Editor.Document; // var doc = (TextDocument)e.Editor.Document;
// IExpressionFinder expressionFinder = ParserService.GetExpressionFinder(e.Editor.FileName); //
// if (expressionFinder == null) // using (var sr = new StringReader(doc.Text))
// return; // {
// var currentLine = doc.GetLine(logicPos.Y); // var parser = new CSharpParser();
// if (logicPos.X > currentLine.Length) // parser.Parse(sr);
// return; //
// string textContent = doc.Text; // IExpressionFinder expressionFinder = ParserService.GetExpressionFinder();
// ExpressionResult expressionResult = expressionFinder.FindFullExpression(textContent, doc.PositionToOffset(logicPos.Line, logicPos.Column)); // if (expressionFinder == null)
// string expression = (expressionResult.Expression ?? "").Trim(); // return;
// if (expression.Length > 0) { // var currentLine = doc.GetLine(logicPos.Y);
// // Look if it is variable // if (logicPos.X > currentLine.Length)
// ResolveResult result = ParserService.Resolve(expressionResult, logicPos.Y, logicPos.X, e.Editor.FileName, textContent); // return;
// bool debuggerCanShowValue; // string textContent = doc.Text;
// string toolTipText = GetText(result, expression, out debuggerCanShowValue); // ExpressionResult expressionResult = expressionFinder.FindFullExpression(textContent, doc.GetOffset(new TextLocation(logicPos.Line, logicPos.Column)));
// if (Control.ModifierKeys == Keys.Control) { // string expression = (expressionResult.Expression ?? "").Trim();
// toolTipText = "expr: " + expressionResult.ToString() + "\n" + toolTipText; // if (expression.Length > 0) {
// debuggerCanShowValue = false; // // Look if it is variable
// } // ResolveResult result = ParserService.Resolve(expressionResult, logicPos.Y, logicPos.X, e.Editor.FileName, textContent);
// if (toolTipText != null) { // bool debuggerCanShowValue;
// if (debuggerCanShowValue && currentDebugger != null) { // string toolTipText = GetText(result, expression, out debuggerCanShowValue);
// object toolTip = currentDebugger.GetTooltipControl(e.LogicalPosition, expressionResult.Expression); // if (Control.ModifierKeys == Keys.Control) {
// if (toolTip != null) // toolTipText = "expr: " + expressionResult.ToString() + "\n" + toolTipText;
// e.SetToolTip(toolTip); // debuggerCanShowValue = false;
// else // }
// if (toolTipText != null) {
// if (debuggerCanShowValue && currentDebugger != null) {
// object toolTip = currentDebugger.GetTooltipControl(e.LogicalPosition, expressionResult.Expression);
// if (toolTip != null)
// e.SetToolTip(toolTip);
// else
// e.SetToolTip(toolTipText);
// } else {
// e.SetToolTip(toolTipText); // e.SetToolTip(toolTipText);
// } else { // }
// e.SetToolTip(toolTipText);
// } // }
// } // }
// } else { // else {
// #if DEBUG // #if DEBUG
// if (Control.ModifierKeys == Keys.Control) { // if (Control.ModifierKeys == Keys.Control) {
// e.SetToolTip("no expr: " + expressionResult.ToString()); // e.SetToolTip("no expr: " + expressionResult.ToString());
// }
// #endif
// } // }
// #endif
// } // }
// } }
//
// static string GetText(ResolveResult result, string expression, out bool debuggerCanShowValue) static string GetText(ResolveResult result, string expression, out bool debuggerCanShowValue)
// { {
debuggerCanShowValue = false;
return "FIXME";
// FIXME
// debuggerCanShowValue = false; // debuggerCanShowValue = false;
// if (result == null) { // if (result == null) {
// // when pressing control, show the expression even when it could not be resolved // // when pressing control, show the expression even when it could not be resolved
@ -303,8 +328,8 @@ namespace ILSpy.Debugger.Services
// return null; // return null;
// } // }
// } // }
// } }
//
// static string GetMemberText(IAmbience ambience, IEntity member, string expression, out bool debuggerCanShowValue) // static string GetMemberText(IAmbience ambience, IEntity member, string expression, out bool debuggerCanShowValue)
// { // {
// bool tryDisplayValue = false; // bool tryDisplayValue = false;
@ -344,18 +369,4 @@ namespace ILSpy.Debugger.Services
// } // }
#endregion #endregion
} }
/// <summary>
/// Provides the default debugger tooltips on the text area.
/// </summary>
/// <remarks>
/// This class must be public because it is accessed via the AddInTree.
/// </remarks>
// public class DebuggerTextAreaToolTipProvider : ITextAreaToolTipProvider
// {
// public void HandleToolTipRequest(ToolTipRequestEventArgs e)
// {
// DebuggerService.HandleToolTipRequest(e);
// }
// }
} }

24
Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs

@ -16,6 +16,7 @@ using ICSharpCode.NRefactory.Visitors;
using ILSpy.Debugger.Bookmarks; using ILSpy.Debugger.Bookmarks;
using ILSpy.Debugger.Models.TreeModel; using ILSpy.Debugger.Models.TreeModel;
using ILSpy.Debugger.Services.Debugger; using ILSpy.Debugger.Services.Debugger;
using ILSpy.Debugger.Tooltips;
using CorDbg = Debugger; using CorDbg = Debugger;
using Process = Debugger.Process; using Process = Debugger.Process;
@ -384,17 +385,18 @@ namespace ILSpy.Debugger.Services
/// </summary> /// </summary>
public object GetTooltipControl(AstLocation logicalPosition, string variableName) public object GetTooltipControl(AstLocation logicalPosition, string variableName)
{ {
try { return new DebuggerTooltipControl(logicalPosition, new ExpressionNode(ImageService.Breakpoint, variableName, null));
var tooltipExpression = GetExpression(variableName); //FIXME
string imageName; // try {
var image = ExpressionNode.GetImageForLocalVariable(out imageName); // var tooltipExpression = GetExpression(variableName);
ExpressionNode expressionNode = new ExpressionNode(image, variableName, tooltipExpression); // string imageName;
expressionNode.ImageName = imageName; // var image = ExpressionNode.GetImageForLocalVariable(out imageName);
return null; // ExpressionNode expressionNode = new ExpressionNode(image, variableName, tooltipExpression);
// return new DebuggerTooltipControl(logicalPosition, expressionNode); // expressionNode.ImageName = imageName;
} catch (GetValueException) { // return new DebuggerTooltipControl(logicalPosition, expressionNode);
return null; // } catch (GetValueException) {
} // return null;
// }
} }
public ITreeNode GetNode(string variable, string currentImageName = null) public ITreeNode GetNode(string variable, string currentImageName = null)

71
Debugger/ILSpy.Debugger/ToolTips/Models/ToolTipRequestEventArgs.cs

@ -0,0 +1,71 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using ICSharpCode.AvalonEdit;
using ICSharpCode.NRefactory.CSharp;
namespace ILSpy.Debugger.ToolTips
{
public class ToolTipRequestEventArgs : EventArgs
{
/// <summary>
/// Gets whether the tool tip request was handled.
/// </summary>
public bool Handled { get; set; }
/// <summary>
/// Gets the editor causing the request.
/// </summary>
public TextEditor Editor { get; private set; }
/// <summary>
/// Gets whether the mouse was inside the document bounds.
/// </summary>
public bool InDocument { get; set; }
/// <summary>
/// The mouse position, in document coordinates.
/// </summary>
public AstLocation LogicalPosition { get; set; }
/// <summary>
/// Gets/Sets the content to show as a tooltip.
/// </summary>
public object ContentToShow { get; set; }
/// <summary>
/// Sets the tooltip to be shown.
/// </summary>
public void SetToolTip(object content)
{
if (content == null)
throw new ArgumentNullException("content");
this.Handled = true;
this.ContentToShow = content;
}
public ToolTipRequestEventArgs(TextEditor editor)
{
if (editor == null)
throw new ArgumentNullException("editor");
this.Editor = editor;
this.InDocument = true;
}
}
}

197
Debugger/ILSpy.Debugger/ToolTips/TextEditorListener.cs

@ -0,0 +1,197 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.NRefactory.CSharp;
using ILSpy.Debugger.AvalonEdit;
using ILSpy.Debugger.Services;
namespace ILSpy.Debugger.ToolTips
{
/// <summary>
/// Description of TextEditorListener.
/// </summary>
public class TextEditorListener : IWeakEventListener
{
private static readonly TextEditorListener instance;
static TextEditorListener()
{
instance = new TextEditorListener();
}
private TextEditorListener() { }
Popup popup;
ToolTip toolTip;
TextEditor editor;
public static TextEditorListener Instance {
get { return instance; }
}
public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
{
if (managerType == typeof(ILSpy.Debugger.AvalonEdit.TextEditorWeakEventManager.MouseHover)) {
editor = (TextEditor)sender;
OnMouseHover((MouseEventArgs)e);
}
if (managerType == typeof(ILSpy.Debugger.AvalonEdit.TextEditorWeakEventManager.MouseHoverStopped)) {
OnMouseHoverStopped((MouseEventArgs)e);
}
return true;
}
void OnMouseHoverStopped(MouseEventArgs e)
{
if (popup != null)
popup.IsOpen = false;
if (toolTip != null)
toolTip.IsOpen = false;
}
void OnMouseHover(MouseEventArgs e)
{
ToolTipRequestEventArgs args = new ToolTipRequestEventArgs(editor);
var pos = editor.GetPositionFromPoint(e.GetPosition(editor));
args.InDocument = pos.HasValue;
if (pos.HasValue) {
args.LogicalPosition = new AstLocation(pos.Value.Column, pos.Value.Line);
}
DebuggerService.HandleToolTipRequest(args);
if (args.ContentToShow != null) {
var contentToShowITooltip = args.ContentToShow as ITooltip;
if (contentToShowITooltip != null && contentToShowITooltip.ShowAsPopup) {
if (!(args.ContentToShow is UIElement)) {
throw new NotSupportedException("Content to show in Popup must be UIElement: " + args.ContentToShow);
}
if (popup == null) {
popup = CreatePopup();
}
if (TryCloseExistingPopup(false)) {
// when popup content decides to close, close the popup
contentToShowITooltip.Closed += delegate { popup.IsOpen = false; };
popup.Child = (UIElement)args.ContentToShow;
//ICSharpCode.SharpDevelop.Debugging.DebuggerService.CurrentDebugger.IsProcessRunningChanged
SetPopupPosition(popup, e);
popup.IsOpen = true;
}
e.Handled = true;
} else {
if (toolTip == null) {
toolTip = new ToolTip();
toolTip.Closed += delegate { toolTip = null; };
}
toolTip.PlacementTarget = editor; // required for property inheritance
if(args.ContentToShow is string) {
toolTip.Content = new TextBlock
{
Text = args.ContentToShow as string,
TextWrapping = TextWrapping.Wrap
};
}
else
toolTip.Content = args.ContentToShow;
toolTip.IsOpen = true;
e.Handled = true;
}
} else {
// close popup if mouse hovered over empty area
if (popup != null) {
e.Handled = true;
}
TryCloseExistingPopup(false);
}
}
bool TryCloseExistingPopup(bool mouseClick)
{
bool canClose = true;
if (popup != null) {
var popupContentITooltip = popup.Child as ITooltip;
if (popupContentITooltip != null) {
canClose = popupContentITooltip.Close(mouseClick);
}
if (canClose) {
popup.IsOpen = false;
}
}
return canClose;
}
void SetPopupPosition(Popup popup, MouseEventArgs mouseArgs)
{
var popupPosition = GetPopupPosition(mouseArgs);
popup.HorizontalOffset = popupPosition.X;
popup.VerticalOffset = popupPosition.Y;
}
/// <summary> Returns Popup position based on mouse position, in device independent units </summary>
Point GetPopupPosition(MouseEventArgs mouseArgs)
{
Point mousePos = mouseArgs.GetPosition(editor);
Point positionInPixels;
// align Popup with line bottom
TextViewPosition? logicalPos = editor.GetPositionFromPoint(mousePos);
if (logicalPos.HasValue) {
var textView = editor.TextArea.TextView;
positionInPixels =
textView.PointToScreen(
textView.GetVisualPosition(logicalPos.Value, VisualYPosition.LineBottom) - textView.ScrollOffset);
positionInPixels.X -= 4;
} else {
positionInPixels = editor.PointToScreen(mousePos + new Vector(-4, 6));
}
// use device independent units, because Popup Left/Top are in independent units
return positionInPixels.TransformFromDevice(editor);
}
Popup CreatePopup()
{
popup = new Popup();
popup.Closed += delegate { popup = null; };
popup.AllowsTransparency = true;
popup.PlacementTarget = editor; // required for property inheritance
popup.Placement = PlacementMode.Absolute;
popup.StaysOpen = true;
return popup;
}
bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
{
return ReceiveWeakEvent(managerType, sender, e);
}
}
}

6
ILSpy/TextView/DecompilerTextView.cs

@ -29,6 +29,7 @@ using System.Windows.Media.Animation;
using System.Windows.Threading; using System.Windows.Threading;
using System.Xml; using System.Xml;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Folding; using ICSharpCode.AvalonEdit.Folding;
using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Highlighting.Xshd; using ICSharpCode.AvalonEdit.Highlighting.Xshd;
@ -36,6 +37,7 @@ using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
using ILSpy.Debugger.AvalonEdit; using ILSpy.Debugger.AvalonEdit;
using ILSpy.Debugger.Bookmarks; using ILSpy.Debugger.Bookmarks;
using ILSpy.Debugger.ToolTips;
using Microsoft.Win32; using Microsoft.Win32;
using Mono.Cecil; using Mono.Cecil;
@ -80,6 +82,10 @@ namespace ICSharpCode.ILSpy.TextView
// add margin // add margin
iconMargin = new IconBarMargin(); iconMargin = new IconBarMargin();
textEditor.TextArea.LeftMargins.Add(iconMargin); textEditor.TextArea.LeftMargins.Add(iconMargin);
// wire the mouse events
TextEditorWeakEventManager.MouseHover.AddListener(textEditor, TextEditorListener.Instance);
TextEditorWeakEventManager.MouseHoverStopped.AddListener(textEditor, TextEditorListener.Instance);
textEditor.TextArea.TextView.VisualLinesChanged += (s, e) => iconMargin.InvalidateVisual(); textEditor.TextArea.TextView.VisualLinesChanged += (s, e) => iconMargin.InvalidateVisual();
BookmarkManager.Added += BookmarkManager_Added; BookmarkManager.Added += BookmarkManager_Added;
BookmarkManager.Removed += (s, e) => iconMargin.InvalidateVisual(); BookmarkManager.Removed += (s, e) => iconMargin.InvalidateVisual();

Loading…
Cancel
Save