You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
384 lines
11 KiB
384 lines
11 KiB
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) |
|
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) |
|
|
|
using System; |
|
using System.Collections.Generic; |
|
using System.Collections.ObjectModel; |
|
using System.Linq; |
|
using System.Windows; |
|
using System.Windows.Controls; |
|
using System.Windows.Controls.Primitives; |
|
using System.Windows.Input; |
|
using System.Windows.Media.Animation; |
|
using System.Windows.Shapes; |
|
using ICSharpCode.SharpDevelop; |
|
using ICSharpCode.SharpDevelop.Bookmarks; |
|
using ICSharpCode.SharpDevelop.Debugging; |
|
using ICSharpCode.SharpDevelop.Editor; |
|
using ICSharpCode.SharpDevelop.Gui; |
|
using ICSharpCode.SharpDevelop.Services; |
|
|
|
namespace Debugger.AddIn.Tooltips |
|
{ |
|
public partial class PinDebuggerControl : UserControl, IPinDebuggerControl |
|
{ |
|
private const double ChildPopupOpenXOffet = 16; |
|
private const double ChildPopupOpenYOffet = 15; |
|
private const int InitialItemsCount = 12; |
|
private const double MINIMUM_OPACITY = .3d; |
|
|
|
private WindowsDebugger currentDebugger; |
|
private DebuggerPopup childPopup; |
|
private LazyItemsControl<ITreeNode> lazyExpandersGrid; |
|
private LazyItemsControl<ITreeNode> lazyGrid; |
|
private LazyItemsControl<ITreeNode> lazyImagesGrid; |
|
private IEnumerable<ITreeNode> itemsSource; |
|
|
|
public PinDebuggerControl() |
|
{ |
|
InitializeComponent(); |
|
|
|
if (!DebuggerService.IsDebuggerStarted) |
|
Opacity = MINIMUM_OPACITY; |
|
this.PinCloseControl.Opacity = 0; |
|
|
|
Loaded += OnLoaded; |
|
this.PinCloseControl.Closed += PinCloseControl_Closed; |
|
this.PinCloseControl.ShowingComment += PinCloseControl_ShowingComment; |
|
this.PinCloseControl.PinningChanged += PinCloseControl_PinningChanged; |
|
|
|
BookmarkManager.Removed += OnBookmarkRemoved; |
|
|
|
currentDebugger = (WindowsDebugger)DebuggerService.CurrentDebugger; |
|
|
|
currentDebugger.DebugStopped += OnDebugStopped; |
|
currentDebugger.ProcessSelected += OnProcessSelected; |
|
|
|
if (currentDebugger.DebuggedProcess != null) |
|
currentDebugger.DebuggedProcess.Paused += OnDebuggedProcessPaused; |
|
} |
|
|
|
#region Properties |
|
|
|
public PinBookmark Mark { get; set; } |
|
|
|
public IEnumerable<ITreeNode> ItemsSource |
|
{ |
|
get { return this.itemsSource; } |
|
set { |
|
itemsSource = value; |
|
var items = new VirtualizingIEnumerable<ITreeNode>(value); |
|
lazyExpandersGrid = new LazyItemsControl<ITreeNode>(this.ExpandersGrid, InitialItemsCount); |
|
lazyExpandersGrid.ItemsSource = items; |
|
|
|
lazyGrid = new LazyItemsControl<ITreeNode>(this.dataGrid, InitialItemsCount); |
|
lazyGrid.ItemsSource = items; |
|
|
|
lazyImagesGrid = new LazyItemsControl<ITreeNode>(this.ImagesGrid, InitialItemsCount); |
|
lazyImagesGrid.ItemsSource = items; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Relative position of the pin with respect to the screen. |
|
/// </summary> |
|
public Point Location { get; set; } |
|
|
|
#endregion |
|
|
|
#region Main operations |
|
|
|
public void Open() |
|
{ |
|
Pin(); |
|
} |
|
|
|
public void Close() |
|
{ |
|
CloseChildPopups(); |
|
Unpin(); |
|
|
|
BookmarkManager.Removed -= OnBookmarkRemoved; |
|
if (currentDebugger != null) { |
|
currentDebugger.DebugStopped -= OnDebugStopped; |
|
currentDebugger.ProcessSelected -= OnProcessSelected; |
|
currentDebugger = null; |
|
} |
|
} |
|
|
|
void Pin() |
|
{ |
|
var provider = WorkbenchSingleton.Workbench.ActiveContent as ITextEditorProvider; |
|
if(provider != null) { |
|
var pinLayer = PinningBinding.GetPinlayer(provider.TextEditor); |
|
if (pinLayer != null) |
|
pinLayer.Pin(this); |
|
} |
|
} |
|
|
|
void Unpin() |
|
{ |
|
var provider = WorkbenchSingleton.Workbench.ActiveContent as ITextEditorProvider; |
|
if(provider != null) { |
|
var pinLayer = PinningBinding.GetPinlayer(provider.TextEditor); |
|
if (pinLayer != null) |
|
pinLayer.Unpin(this); |
|
} |
|
} |
|
|
|
#endregion |
|
|
|
#region Debugger events |
|
|
|
void OnDebugStopped(object sender, EventArgs e) |
|
{ |
|
if (currentDebugger.DebuggedProcess != null) |
|
currentDebugger.DebuggedProcess.Paused -= OnDebuggedProcessPaused; |
|
} |
|
|
|
void OnProcessSelected(object sender, ProcessEventArgs e) |
|
{ |
|
Opacity = 1d; |
|
if (currentDebugger.DebuggedProcess != null) |
|
currentDebugger.DebuggedProcess.Paused += OnDebuggedProcessPaused; |
|
} |
|
|
|
void OnDebuggedProcessPaused(object sender, ProcessEventArgs e) |
|
{ |
|
//var nodes = new StackFrameNode(e.Process.SelectedStackFrame).ChildNodes; |
|
|
|
// if (!lazyGrid.ItemsSource.ContainsNode(node)) |
|
// return; |
|
// TODO : find the current expression so we don't update every pin |
|
// var observable = new List<ITreeNode>(); |
|
// |
|
// foreach (var node in lazyGrid.ItemsSource) { |
|
// var resultNode = currentDebugger.GetNode(node.FullName); |
|
// // HACK for updating the pins in tooltip |
|
// observable.Add(resultNode); |
|
// } |
|
// |
|
// // update UI |
|
// var newSource = new VirtualizingIEnumerable<ITreeNode>(observable); |
|
// lazyGrid.ItemsSource = newSource; |
|
// lazyExpandersGrid.ItemsSource = newSource; |
|
} |
|
|
|
#endregion |
|
|
|
#region Expand button |
|
|
|
private ToggleButton expandedButton; |
|
|
|
/// <summary> |
|
/// Closes the child popup of this control, if it exists. |
|
/// </summary> |
|
void CloseChildPopups() |
|
{ |
|
if (this.expandedButton != null) { |
|
this.expandedButton = null; |
|
// nice simple example of indirect recursion |
|
this.childPopup.CloseSelfAndChildren(); |
|
} |
|
} |
|
|
|
void BtnExpander_Checked(object sender, RoutedEventArgs e) |
|
{ |
|
if (!DebuggerService.IsDebuggerStarted) |
|
return; |
|
|
|
var clickedButton = (ToggleButton)e.OriginalSource; |
|
var clickedNode = (ITreeNode)clickedButton.DataContext; |
|
// use device independent units, because child popup Left/Top are in independent units |
|
Point buttonPos = clickedButton.PointToScreen(new Point(0, 0)).TransformFromDevice(clickedButton); |
|
|
|
if (clickedButton.IsChecked.GetValueOrDefault(false)) { |
|
|
|
this.expandedButton = clickedButton; |
|
|
|
// open child Popup |
|
if (this.childPopup == null) { |
|
this.childPopup = new DebuggerPopup(null, ICSharpCode.NRefactory.Location.Empty, false); |
|
this.childPopup.PlacementTarget = this; |
|
this.childPopup.Closed += new EventHandler(PinDebuggerControl_Closed); |
|
this.childPopup.Placement = PlacementMode.Absolute; |
|
} |
|
|
|
this.childPopup.IsLeaf = true; |
|
this.childPopup.HorizontalOffset = buttonPos.X + ChildPopupOpenXOffet; |
|
this.childPopup.VerticalOffset = buttonPos.Y + ChildPopupOpenYOffet; |
|
if (clickedNode.GetChildren != null) { |
|
this.childPopup.ItemsSource = clickedNode.GetChildren().ToList(); |
|
this.childPopup.Open(); |
|
} |
|
} else { |
|
|
|
} |
|
} |
|
|
|
void PinDebuggerControl_Closed(object sender, EventArgs e) |
|
{ |
|
if (expandedButton != null && expandedButton.IsChecked.GetValueOrDefault(false)) |
|
expandedButton.IsChecked = false; |
|
} |
|
|
|
void BtnExpander_Unchecked(object sender, RoutedEventArgs e) |
|
{ |
|
CloseChildPopups(); |
|
} |
|
|
|
#endregion |
|
|
|
#region PinCloseControl |
|
|
|
void PinCloseControl_Closed(object sender, EventArgs e) |
|
{ |
|
BookmarkManager.RemoveMark(Mark); |
|
Close(); |
|
} |
|
|
|
void PinCloseControl_PinningChanged(object sender, EventArgs e) |
|
{ |
|
if (this.PinCloseControl.IsChecked) { |
|
BookmarkManager.RemoveMark(Mark); |
|
} |
|
else { |
|
if(BookmarkManager.Bookmarks.Contains(Mark)) |
|
BookmarkManager.RemoveMark(Mark); |
|
|
|
BookmarkManager.AddMark(Mark); |
|
} |
|
} |
|
|
|
void PinCloseControl_ShowingComment(object sender, ShowingCommentEventArgs e) |
|
{ |
|
ShowComment(e.ShowComment); |
|
} |
|
|
|
void AnimateCloseControl(bool show) |
|
{ |
|
DoubleAnimation animation = new DoubleAnimation(); |
|
animation.From = show ? 0 : 1; |
|
animation.To = show ? 1 : 0; |
|
animation.BeginTime = new TimeSpan(0, 0, show ? 0 : 1); |
|
animation.Duration = new Duration(TimeSpan.FromMilliseconds(500)); |
|
animation.SetValue(Storyboard.TargetProperty, this.PinCloseControl); |
|
animation.SetValue(Storyboard.TargetPropertyProperty, new PropertyPath(Rectangle.OpacityProperty)); |
|
|
|
Storyboard board = new Storyboard(); |
|
board.Children.Add(animation); |
|
|
|
board.Begin(this); |
|
} |
|
|
|
#endregion |
|
|
|
void OnBookmarkRemoved(object sender, BookmarkEventArgs e) |
|
{ |
|
// if the bookmark was removed from pressing the button, return |
|
if (this.PinCloseControl.IsChecked) |
|
return; |
|
|
|
if (e.Bookmark is PinBookmark) { |
|
var pin = (PinBookmark)e.Bookmark; |
|
if (pin.Location == Mark.Location && pin.FileName == Mark.FileName) { |
|
Close(); |
|
} |
|
} |
|
} |
|
|
|
private void OnLoaded(object sender, RoutedEventArgs e) |
|
{ |
|
this.CommentTextBox.Text = Mark.Comment; |
|
} |
|
|
|
private void Button_Click(object sender, RoutedEventArgs e) |
|
{ |
|
if (!DebuggerService.IsDebuggerStarted) |
|
return; |
|
|
|
// refresh content |
|
ITreeNode node = ((FrameworkElement)e.OriginalSource).DataContext as ITreeNode; |
|
|
|
var resultNode = currentDebugger.GetNode(node.Name, node.ImageName); |
|
if (resultNode == null) |
|
return; |
|
// HACK for updating the pins in tooltip |
|
var observable = new ObservableCollection<ITreeNode>(); |
|
var source = lazyGrid.ItemsSource; |
|
source.ForEach(item => { |
|
if (item.Name == node.Name) |
|
observable.Add(resultNode); |
|
else |
|
observable.Add(item); |
|
}); |
|
|
|
Mark.Nodes = observable; |
|
// update UI |
|
var newSource = new VirtualizingIEnumerable<ITreeNode>(observable); |
|
lazyGrid.ItemsSource = newSource; |
|
lazyExpandersGrid.ItemsSource = newSource; |
|
} |
|
|
|
#region Comment |
|
|
|
void ShowComment(bool show) |
|
{ |
|
if(show && BorderComment.Height != 0) |
|
return; |
|
if(!show && BorderComment.Height != 40) |
|
return; |
|
|
|
DoubleAnimation animation = new DoubleAnimation(); |
|
animation.From = show ? 0 : 40; |
|
animation.To = show ? 40 : 0; |
|
|
|
animation.Duration = new Duration(TimeSpan.FromMilliseconds(300)); |
|
animation.SetValue(Storyboard.TargetProperty, BorderComment); |
|
animation.SetValue(Storyboard.TargetPropertyProperty, new PropertyPath(Border.HeightProperty)); |
|
|
|
Storyboard board = new Storyboard(); |
|
board.Children.Add(animation); |
|
board.Begin(this); |
|
} |
|
|
|
void CommentTextBox_TextChanged(object sender, TextChangedEventArgs e) |
|
{ |
|
Mark.Comment = this.CommentTextBox.Text; |
|
} |
|
|
|
#endregion |
|
|
|
#region Overrides |
|
|
|
protected override void OnMouseEnter(System.Windows.Input.MouseEventArgs e) |
|
{ |
|
AnimateCloseControl(true); |
|
Opacity = 1d; |
|
Cursor = Cursors.Arrow; |
|
base.OnMouseEnter(e); |
|
} |
|
|
|
protected override void OnMouseMove(MouseEventArgs e) |
|
{ |
|
Opacity = 1d; |
|
Cursor = Cursors.Arrow; |
|
base.OnMouseMove(e); |
|
} |
|
|
|
protected override void OnMouseLeave(System.Windows.Input.MouseEventArgs e) |
|
{ |
|
if (DebuggerService.IsDebuggerStarted) |
|
Opacity = 1; |
|
else |
|
Opacity = MINIMUM_OPACITY; |
|
|
|
AnimateCloseControl(false); |
|
|
|
Cursor = Cursors.IBeam; |
|
base.OnMouseLeave(e); |
|
} |
|
|
|
#endregion |
|
} |
|
} |