mirror of https://github.com/icsharpcode/ILSpy.git
8 changed files with 419 additions and 167 deletions
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -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); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue