Browse Source

move tooltips to Debugger.AddIn

move pin to Debugger.AddIn
pull/11/head
Eusebiu Marcu 15 years ago
parent
commit
70b33f5963
  1. BIN
      data/resources/image/BitmapResources/BitmapResources-data/Icons.16x16.Refresh.png
  2. 9
      src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin
  3. 29
      src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj
  4. 2
      src/AddIns/Debugger/Debugger.AddIn/Pads/LocalVarPad.cs
  5. 2
      src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPadModel.cs
  6. 28
      src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs
  7. 101
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerPopup.cs
  8. 229
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml
  9. 406
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml.cs
  10. 113
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/LazyItemsControl.cs
  11. 29
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinCloseControl.xaml
  12. 74
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinCloseControl.xaml.cs
  13. 337
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinControlsDictionary.xaml
  14. 258
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinDebuggerControl.xaml
  15. 378
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinDebuggerControl.xaml.cs
  16. 226
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinLayer.cs
  17. 121
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinningBinding.cs
  18. 53
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/VirtualizingIEnumerable.cs
  19. 48
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/VisualizerPicker.cs
  20. 135
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/VisualizerPicker.xaml
  21. BIN
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/magnifier.png
  22. 2
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/Adapters/TreeViewVarNode.cs
  23. 6
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/ArrayRangeNode.cs
  24. 12
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/ChildNodesOfObject.cs
  25. 126
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/ExpressionNode.cs
  26. 30
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/SavedTreeNode.cs
  27. 12
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/StackFrameNode.cs
  28. 21
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/TreeNode.cs
  29. 7
      src/Main/Base/Project/ICSharpCode.SharpDevelop.addin
  30. 28
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  31. 2
      src/Main/Base/Project/Src/Bookmarks/BookmarkConverter.cs
  32. 2
      src/Main/Base/Project/Src/Services/Debugger/Tooltips/DebuggerPopup.cs
  33. 67
      src/Main/Base/Project/Src/Services/Debugger/Tooltips/DebuggerTooltipControl.xaml.cs
  34. 20
      src/Main/Base/Project/Src/Services/Debugger/Tooltips/IPinDebuggerControl.cs
  35. 4
      src/Main/Base/Project/Src/Services/Debugger/Tooltips/ITreeNode.cs
  36. 8
      src/Main/Base/Project/Src/Services/Debugger/Tooltips/PinBookmark.cs
  37. 37
      src/Main/Base/Project/Src/Services/Debugger/Tooltips/PinDebuggerControl.xaml
  38. 252
      src/Main/Base/Project/Src/Services/Debugger/Tooltips/PinDebuggerControl.xaml.cs
  39. BIN
      src/Main/StartUp/Project/Resources/BitmapResources.resources

BIN
data/resources/image/BitmapResources/BitmapResources-data/Icons.16x16.Refresh.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 858 B

After

Width:  |  Height:  |  Size: 1.0 KiB

9
src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin

@ -14,7 +14,14 @@ @@ -14,7 +14,14 @@
<ConditionEvaluator name = "IsBreakpointActive" class="Debugger.AddIn.IsActiveBreakpointCondition" />
</Import>
<Import assembly="Debugger.Core.dll"/>
</Runtime>
</Runtime>
<Path name="/SharpDevelop/Workbench/LanguageBindings">
<LanguageBinding
id="Pin"
class="Debugger.AddIn.Tooltips.PinningBinding"
extensions="" />
</Path>
<Path name="/SharpDevelop/Services/DebuggerService/Debugger">
<Debugger id="DefaultDebugger"

29
src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj

@ -79,9 +79,6 @@ @@ -79,9 +79,6 @@
<Reference Include="WindowsBase">
<RequiredTargetFramework>3.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsFormsIntegration">
<RequiredTargetFramework>3.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsFormsIntegration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
@ -155,7 +152,26 @@ @@ -155,7 +152,26 @@
<DependentUpon>EditBreakpointScriptWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Tooltips\DebuggerPopup.cs" />
<Compile Include="Tooltips\DebuggerTooltipControl.xaml.cs">
<DependentUpon>DebuggerTooltipControl.xaml</DependentUpon>
</Compile>
<Compile Include="Tooltips\LazyItemsControl.cs" />
<Compile Include="Tooltips\PinCloseControl.xaml.cs">
<DependentUpon>PinCloseControl.xaml</DependentUpon>
</Compile>
<Compile Include="Tooltips\PinDebuggerControl.xaml.cs">
<DependentUpon>PinDebuggerControl.xaml</DependentUpon>
</Compile>
<Compile Include="Tooltips\PinLayer.cs" />
<Compile Include="Tooltips\PinningBinding.cs" />
<Compile Include="Tooltips\VirtualizingIEnumerable.cs" />
<Compile Include="Tooltips\VisualizerPicker.cs">
<DependentUpon>VisualizerPicker.xaml</DependentUpon>
</Compile>
<Compile Include="TreeModel\DebuggerResourceService.cs" />
<Compile Include="TreeModel\SavedTreeNode.cs" />
<Compile Include="TreeModel\TreeNode.cs" />
<Compile Include="Visualizers\Commands\ExpressionVisualizerCommand.cs" />
<Compile Include="Visualizers\Commands\GridVisualizerCommand.cs" />
<Compile Include="Visualizers\Commands\IVisualizerDescriptor.cs" />
@ -298,6 +314,7 @@ @@ -298,6 +314,7 @@
<Compile Include="Visualizers\PresentationBindings\EnumViewModel.cs" />
<Compile Include="Visualizers\PresentationBindings\ViewModelBase.cs" />
<None Include="COPYING" />
<None Include="Tooltips\magnifier.png" />
</ItemGroup>
<ItemGroup>
<Content Include="Debugger.AddIn.addin">
@ -347,6 +364,11 @@ @@ -347,6 +364,11 @@
<Page Include="Pads\Controls\WatchList.xaml" />
<Page Include="Pads\WatchInputBox.xaml" />
<Page Include="Service\EditBreakpointScriptWindow.xaml" />
<Page Include="Tooltips\DebuggerTooltipControl.xaml" />
<Page Include="Tooltips\PinCloseControl.xaml" />
<Page Include="Tooltips\PinControlsDictionary.xaml" />
<Page Include="Tooltips\PinDebuggerControl.xaml" />
<Page Include="Tooltips\VisualizerPicker.xaml" />
<Page Include="Visualizers\Graph\Drawing\NodeControlResources.xaml" />
<Page Include="Visualizers\Graph\Drawing\PositionedGraphNodeControl.xaml" />
<Page Include="Visualizers\Graph\ObjectGraphControl.xaml" />
@ -368,6 +390,7 @@ @@ -368,6 +390,7 @@
<Private>False</Private>
</ProjectReference>
<Folder Include="Pads\Controls" />
<Folder Include="Tooltips" />
<Folder Include="Visualizers\Graph" />
<Folder Include="Visualizers\Graph\Drawing" />
<Folder Include="Visualizers\Graph\Layout" />

2
src/AddIns/Debugger/Debugger.AddIn/Pads/LocalVarPad.cs

@ -7,7 +7,7 @@ using Debugger.AddIn.Pads.Controls; @@ -7,7 +7,7 @@ using Debugger.AddIn.Pads.Controls;
using Debugger.AddIn.TreeModel;
using ICSharpCode.Core;
using Exception = System.Exception;
using TreeNode = ICSharpCode.SharpDevelop.Debugging.TreeNode;
using TreeNode = Debugger.AddIn.TreeModel.TreeNode;
namespace ICSharpCode.SharpDevelop.Gui.Pads
{

2
src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPadModel.cs

@ -22,7 +22,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -22,7 +22,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
}
}
public new bool SetText(string text)
public override bool SetText(string text)
{
this.Text = text;
return true;

28
src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs

@ -11,7 +11,7 @@ using System.Text; @@ -11,7 +11,7 @@ using System.Text;
using System.Windows.Forms;
using Debugger;
using Debugger.AddIn;
using Debugger.AddIn.Tooltips;
using Debugger.AddIn.TreeModel;
using Debugger.Interop.CorPublish;
using ICSharpCode.Core;
@ -404,13 +404,37 @@ namespace ICSharpCode.SharpDevelop.Services @@ -404,13 +404,37 @@ namespace ICSharpCode.SharpDevelop.Services
{
try {
var tooltipExpression = GetExpression(variableName);
ExpressionNode expressionNode = new ExpressionNode(ExpressionNode.GetImageForLocalVariable(), variableName, tooltipExpression);
string imageName;
var image = ExpressionNode.GetImageForLocalVariable(out imageName);
ExpressionNode expressionNode = new ExpressionNode(image, variableName, tooltipExpression);
expressionNode.ImageName = imageName;
return new DebuggerTooltipControl(expressionNode);
} catch (GetValueException) {
return null;
}
}
public ITreeNode GetNode(string variable, string currentImageName = null)
{
try {
var expression = GetExpression(variable);
string imageName;
IImage image;
if (string.IsNullOrEmpty(currentImageName)) {
image = ExpressionNode.GetImageForLocalVariable(out imageName);
}
else {
image = new ResourceServiceImage(currentImageName);
imageName = currentImageName;
}
ExpressionNode expressionNode = new ExpressionNode(image, variable, expression);
expressionNode.ImageName = imageName;
return expressionNode;
} catch (GetValueException) {
return null;
}
}
public bool CanSetInstructionPointer(string filename, int line, int column)
{
if (debuggedProcess != null && debuggedProcess.IsPaused && debuggedProcess.SelectedStackFrame != null) {

101
src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerPopup.cs

@ -0,0 +1,101 @@ @@ -0,0 +1,101 @@
// 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.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Gui;
namespace Debugger.AddIn.Tooltips
{
/// <summary>
/// Popup containing <see cref="DebuggerTooltipControl"></see>.
/// </summary>
public class DebuggerPopup : Popup
{
internal DebuggerTooltipControl contentControl;
public DebuggerPopup(DebuggerTooltipControl parentControl, bool showPins = true)
{
this.contentControl = new DebuggerTooltipControl(parentControl, showPins);
this.contentControl.containingPopup = this;
this.Child = this.contentControl;
this.IsLeaf = false;
//this.KeyDown += new KeyEventHandler(DebuggerPopup_KeyDown);
//this.contentControl.Focusable = true;
//Keyboard.Focus(this.contentControl);
//this.AllowsTransparency = true;
//this.PopupAnimation = PopupAnimation.Slide;
}
// attempt to propagate shortcuts to main windows when Popup is focusable (needed for keyboard scrolling + editing)
/*void DebuggerPopup_KeyDown(object sender, KeyEventArgs e)
{
LoggingService.Debug("Unhandled popup key down: " + e.Key);
RaiseEventPair(WorkbenchSingleton.MainWindow, PreviewKeyDownEvent, KeyDownEvent,
new KeyEventArgs(e.KeyboardDevice, e.InputSource, e.Timestamp, e.Key));
}
// copied from CompletionWindowBase
static bool RaiseEventPair(UIElement target, RoutedEvent previewEvent, RoutedEvent @event, RoutedEventArgs args)
{
if (target == null)
throw new ArgumentNullException("target");
if (previewEvent == null)
throw new ArgumentNullException("previewEvent");
if (@event == null)
throw new ArgumentNullException("event");
if (args == null)
throw new ArgumentNullException("args");
args.RoutedEvent = previewEvent;
target.RaiseEvent(args);
args.RoutedEvent = @event;
target.RaiseEvent(args);
return args.Handled;
}*/
public IEnumerable<ITreeNode> ItemsSource
{
get { return this.contentControl.ItemsSource; }
set { this.contentControl.SetItemsSource(value); }
}
private bool isLeaf;
public bool IsLeaf
{
get { return isLeaf; }
set
{
isLeaf = value;
// leaf popup closes on lost focus
this.StaysOpen = !isLeaf;
}
}
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
if (isLeaf) {
this.contentControl.CloseOnLostFocus();
}
}
public void Open()
{
this.IsOpen = true;
}
public void CloseSelfAndChildren()
{
this.contentControl.CloseChildPopups();
this.IsOpen = false;
}
}
}

229
src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml

@ -0,0 +1,229 @@ @@ -0,0 +1,229 @@
<?xml version="1.0" encoding="utf-8"?>
<UserControl
x:Class="Debugger.AddIn.Tooltips.DebuggerTooltipControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:aero="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
xmlns:debugging="clr-namespace:Debugger.AddIn.Tooltips" xmlns:core="http://icsharpcode.net/sharpdevelop/core" xmlns:localControls="clr-namespace:Debugger.AddIn.Tooltips"
Background="Transparent">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="VisualizerPicker.xaml" />
<ResourceDictionary
Source="PinControlsDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<StackPanel
Orientation="Vertical">
<RepeatButton
Name="btnUp"
Focusable="False"
Style="{StaticResource upButtonStyle}"
Content="^"
Click="BtnUp_Click"></RepeatButton>
<DataGrid
VerticalScrollBarVisibility="Disabled"
HorizontalScrollBarVisibility="Disabled"
GridLinesVisibility="None"
RowHeight="18"
MaxHeight="202"
SelectionMode="Single"
SelectionUnit="FullRow"
ItemsSource="{Binding}"
Name="dataGrid"
AutoGenerateColumns="False"
CanUserAddRows="False"
HeadersVisibility="None"
BorderBrush="Gray"
BorderThickness="1">
<DataGrid.Background>
<!-- Control backgound -->
<LinearGradientBrush
StartPoint="0,-0.03"
EndPoint="0,1">
<GradientStop
Color="White" />
<GradientStop
Color="#FFFAFCFE"
Offset="0.983" />
<GradientStop
Color="#FFECF7FC"
Offset="0.07" />
<GradientStop
Color="#FFEEF7FA"
Offset="0.436" />
</LinearGradientBrush>
</DataGrid.Background>
<DataGrid.RowStyle>
<Style
TargetType="{x:Type DataGridRow}">
<Setter
Property="Background"
Value="Transparent"></Setter>
<Style.Triggers>
<Trigger
Property="IsMouseOver"
Value="True">
<Setter
Property="Background"
Value="#FFE2F6FE" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
<DataGrid.CellStyle>
<Style
TargetType="{x:Type DataGridCell}">
<Setter
Property="Focusable"
Value="false" />
<!-- Focusable=true blocks shortcuts if cell is focused -->
<Setter
Property="BorderThickness"
Value="0" />
<Style.Triggers>
<Trigger
Property="IsSelected"
Value="True">
<!-- disable selection highlight -->
<Setter
Property="Foreground"
Value="Black" />
<Setter
Property="Background"
Value="{x:Null}" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>
<DataGrid.Columns>
<DataGridTemplateColumn>
<!-- "Plus" expander -->
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid
Background="White">
<StackPanel
VerticalAlignment="Center">
<ToggleButton
x:Name="btnExpander"
Style="{StaticResource ExpandCollapseToggleStyle}"
Click="btnExpander_Click"
Padding="0"
Margin="0" />
</StackPanel>
</Grid>
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding Path=HasChildNodes}"
Value="False">
<Setter
TargetName="btnExpander"
Property="Visibility"
Value="Collapsed" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!-- Icon -->
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image
Source="{Binding ImageSource}"></Image>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn
MinWidth="20"
Header="Name">
<!-- Name -->
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border
BorderBrush="#FFDDDDDD"
BorderThickness="0 0 1 0">
<TextBlock
Style="{StaticResource TextBlockStyle}"
Text="{Binding Path=Name, Mode=OneWay}"
VerticalAlignment="Top"></TextBlock>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!-- Visualizer picker -->
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<debugging:VisualizerPicker
Focusable="False"
x:Name="visPicker"
ItemsSource="{Binding Path=VisualizerCommands, Mode=OneWay}"
Margin="4 0 0 0"></debugging:VisualizerPicker>
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding Path=HasVisualizerCommands}"
Value="False">
<Setter
TargetName="visPicker"
Property="Visibility"
Value="Collapsed" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn
MinWidth="20"
Header="Text">
<!-- Text (value) -->
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox
Style="{StaticResource TextStyle}"
IsEnabled="{Binding CanSetText}"
KeyUp="TextBox_KeyUp"
Text="{Binding Path=Text}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<!-- Pin -->
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ToggleButton
IsChecked="{Binding IsPinned}"
DataContext="{Binding}"
Visibility="Collapsed"
Name="PinButton"
VerticalAlignment="Center"
Checked="PinButton_Checked"
Unchecked="PinButton_Unchecked"
Template="{StaticResource PinTooltipButtonTemplate}" />
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding Path=IsMouseOver, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGridRow}}"
Value="True">
<Setter
TargetName="PinButton"
Property="Visibility"
Value="Visible" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<RepeatButton
Name="btnDown"
Focusable="False"
Style="{StaticResource downButtonStyle}"
Content="v"
Click="BtnDown_Click"></RepeatButton>
</StackPanel>
</UserControl>

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

@ -0,0 +1,406 @@ @@ -0,0 +1,406 @@
// 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.Globalization;
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 System.Windows.Media.Animation;
using System.Windows.Shapes;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Bookmarks;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Gui;
using Services.Debugger.Tooltips;
namespace Debugger.AddIn.Tooltips
{
/// <summary>
/// Default Control used as content of SharpDevelop debugger tooltips.
/// </summary>
public partial class DebuggerTooltipControl : UserControl, ITooltip
{
private const double ChildPopupOpenXOffet = 16;
private const double ChildPopupOpenYOffet = 15;
private const int InitialItemsCount = 12;
private const int VisibleItemsCount = 11;
private bool showPins = true;
private LazyItemsControl<ITreeNode> lazyGrid;
private IEnumerable<ITreeNode> itemsSource;
public DebuggerTooltipControl()
{
InitializeComponent();
Loaded += new RoutedEventHandler(OnLoaded);
}
public DebuggerTooltipControl(ITreeNode node)
: this(new ITreeNode[] { node })
{
}
public DebuggerTooltipControl(IEnumerable<ITreeNode> nodes)
: this()
{
this.itemsSource = nodes;
}
public DebuggerTooltipControl(DebuggerTooltipControl parentControl, bool showPins = true)
: this()
{
this.parentControl = parentControl;
this.showPins = showPins;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
if (!showPins) {
dataGrid.Columns[5].Visibility = Visibility.Collapsed;
}
SetItemsSource(this.itemsSource);
}
public event RoutedEventHandler Closed;
protected void OnClosed()
{
if (this.Closed != null) {
this.Closed(this, new RoutedEventArgs());
}
}
public IEnumerable<ITreeNode> ItemsSource {
get { return this.itemsSource; }
}
public void SetItemsSource(IEnumerable<ITreeNode> value) {
this.itemsSource = value;
this.lazyGrid = new LazyItemsControl<ITreeNode>(this.dataGrid, InitialItemsCount);
// HACK for updating the pins in tooltip
var observable = new List<ITreeNode>();
this.itemsSource.ForEach(item => observable.Add(item));
// verify if at the line of the root there's a pin bookmark
ITextEditorProvider provider = WorkbenchSingleton.Workbench.ActiveViewContent as ITextEditorProvider;
var editor = provider.TextEditor;
if (editor != null) {
var pin = BookmarkManager.Bookmarks.Find(
b => b is PinBookmark &&
b.Location.Line == LogicalPosition.Line &&
b.FileName == editor.FileName) as PinBookmark;
if (pin != null) {
observable.ForEach(item => { // TODO: find a way not to use "observable"
if (pin.ContainsNode(item))
item.IsPinned = true;
});
}
}
var source = new VirtualizingIEnumerable<ITreeNode>(observable);
lazyGrid.ItemsSource = source;
this.dataGrid.AddHandler(ScrollViewer.ScrollChangedEvent, new ScrollChangedEventHandler(handleScroll));
if (this.lazyGrid.ItemsSourceTotalCount != null) {
// hide up/down buttons if too few items
btnUp.Visibility = btnDown.Visibility =
this.lazyGrid.ItemsSourceTotalCount.Value <= VisibleItemsCount ? Visibility.Collapsed : Visibility.Visible;
}
}
public Location LogicalPosition { get; set; }
/// <inheritdoc/>
public bool ShowAsPopup
{
get
{
return true;
}
}
/// <inheritdoc/>
public bool Close(bool mouseClick)
{
if (mouseClick || (!mouseClick && !isChildExpanded)) {
CloseChildPopups();
return true;
} else {
return false;
}
}
private DebuggerPopup childPopup { get; set; }
private DebuggerTooltipControl parentControl { get; set; }
internal DebuggerPopup containingPopup { get; set; }
bool isChildExpanded
{
get
{
return this.childPopup != null && this.childPopup.IsOpen;
}
}
private ToggleButton expandedButton;
/// <summary>
/// Closes the child popup of this control, if it exists.
/// </summary>
public void CloseChildPopups()
{
if (this.expandedButton != null) {
this.expandedButton.IsChecked = false;
this.expandedButton = null;
// nice simple example of indirect recursion
this.childPopup.CloseSelfAndChildren();
}
}
public void CloseOnLostFocus()
{
// when we close, parent becomes leaf
if (this.containingPopup != null) {
this.containingPopup.IsLeaf = true;
}
if (!this.IsMouseOver) {
if (this.containingPopup != null) {
this.containingPopup.IsOpen = false;
this.containingPopup.IsLeaf = false;
}
if (this.parentControl != null) {
this.parentControl.CloseOnLostFocus();
}
OnClosed();
} else {
// leaf closed because of click inside this control - stop the closing chain
if (this.expandedButton != null && !this.expandedButton.IsMouseOver) {
this.expandedButton.IsChecked = false;
this.expandedButton = null;
}
}
}
private void btnExpander_Click(object sender, RoutedEventArgs e)
{
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)) {
CloseChildPopups();
this.expandedButton = clickedButton;
// open child Popup
if (this.childPopup == null) {
this.childPopup = new DebuggerPopup(this);
this.childPopup.Placement = PlacementMode.Absolute;
this.childPopup.contentControl.LogicalPosition = LogicalPosition;
}
if (this.containingPopup != null) {
this.containingPopup.IsLeaf = false;
}
this.childPopup.IsLeaf = true;
this.childPopup.HorizontalOffset = buttonPos.X + ChildPopupOpenXOffet;
this.childPopup.VerticalOffset = buttonPos.Y + ChildPopupOpenYOffet;
this.childPopup.ItemsSource = clickedNode.ChildNodes;
this.childPopup.Open();
} else {
CloseChildPopups();
}
}
private void handleScroll(object sender, ScrollChangedEventArgs e)
{
btnUp.IsEnabled = !this.lazyGrid.IsScrolledToStart;
btnDown.IsEnabled = !this.lazyGrid.IsScrolledToEnd;
}
void BtnUp_Click(object sender, RoutedEventArgs e)
{
this.lazyGrid.ScrollViewer.ScrollUp(1);
}
void BtnDown_Click(object sender, RoutedEventArgs e)
{
this.lazyGrid.ScrollViewer.ScrollDown(1);
}
#region Edit value in tooltip
void TextBox_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape) {
dataGrid.Focus();
return;
}
if (e.Key == Key.Enter) {
dataGrid.Focus();
// set new value
var textBox = (TextBox)e.OriginalSource;
var newValue = textBox.Text;
var node = ((FrameworkElement)sender).DataContext as ITreeNode;
SaveNewValue(node, textBox.Text);
}
}
void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
var textBox = (TextBox)e.OriginalSource;
var newValue = textBox.Text;
var node = ((FrameworkElement)sender).DataContext as ITreeNode;
SaveNewValue(node, textBox.Text);
}
void SaveNewValue(ITreeNode node, string newValue)
{
if(node != null && node.SetText(newValue)) {
// show adorner
var adornerLayer = AdornerLayer.GetAdornerLayer(dataGrid);
var adorners = adornerLayer.GetAdorners(dataGrid);
if (adorners != null && adorners.Length != 0)
adornerLayer.Remove(adorners[0]);
SavedAdorner adorner = new SavedAdorner(dataGrid);
adornerLayer.Add(adorner);
}
}
#endregion
#region Pining checked/unchecked
void PinButton_Checked(object sender, RoutedEventArgs e)
{
ITextEditorProvider provider = WorkbenchSingleton.Workbench.ActiveViewContent as ITextEditorProvider;
var editor = provider.TextEditor;
if (editor == null) return;
var node = (ITreeNode)(((ToggleButton)(e.OriginalSource)).DataContext);
if (!string.IsNullOrEmpty(editor.FileName)) {
// verify if at the line of the root there's a pin bookmark
var pin = BookmarkManager.Bookmarks.Find(
b => b is PinBookmark &&
b.LineNumber == LogicalPosition.Line &&
b.FileName == editor.FileName) as PinBookmark;
if (pin == null) {
pin = new PinBookmark(editor.FileName, LogicalPosition);
// show pinned DebuggerPopup
if (pin.Popup == null) {
pin.Popup = new PinDebuggerControl();
pin.Popup.Mark = pin;
Rect rect = new Rect(this.DesiredSize);
var point = this.PointToScreen(rect.TopRight);
pin.Popup.Location = new Point { X = 500, Y = point.Y - 150 };
pin.Nodes.Add(node);
pin.Popup.ItemsSource = pin.Nodes;
}
// do actions
pin.Popup.Open();
BookmarkManager.AddMark(pin);
}
else
{
if (!pin.ContainsNode(node)) {
pin.Nodes.Add(node);
pin.Popup.ItemsSource = pin.Nodes;
}
}
}
}
void PinButton_Unchecked(object sender, RoutedEventArgs e)
{
ITextEditorProvider provider = WorkbenchSingleton.Workbench.ActiveViewContent as ITextEditorProvider;
var editor = provider.TextEditor;
if (editor == null) return;
if (!string.IsNullOrEmpty(editor.FileName)) {
// remove from pinned DebuggerPopup
var pin = BookmarkManager.Bookmarks.Find(
b => b is PinBookmark &&
b.LineNumber == LogicalPosition.Line &&
b.FileName == editor.FileName) as PinBookmark;
if (pin == null) return;
ToggleButton button = (ToggleButton)e.OriginalSource;
pin.RemoveNode((ITreeNode)button.DataContext);
pin.Popup.ItemsSource = pin.Nodes;
// remove if no more data pins are available
if (pin.Nodes.Count == 0) {
pin.Popup.Close();
BookmarkManager.RemoveMark(pin);
}
}
}
#endregion
#region Saved Adorner
class SavedAdorner : Adorner
{
public SavedAdorner(UIElement adornedElement) : base(adornedElement)
{
Loaded += delegate { Show(); };
}
protected override void OnRender(DrawingContext drawingContext)
{
Rect adornedElementRect = new Rect(this.AdornedElement.DesiredSize);
// Some arbitrary drawing implements.
var formatedText = new FormattedText(StringParser.Parse("${res:ICSharpCode.SharpDevelop.Debugging.SavedString}"),
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface(new FontFamily("Arial"),
FontStyles.Normal,
FontWeights.Black,
FontStretches.Expanded),
8d,
Brushes.Black);
drawingContext.DrawText(formatedText,
new Point(adornedElementRect.TopRight.X - formatedText.Width - 2,
adornedElementRect.TopRight.Y));
}
private void Show()
{
DoubleAnimation animation = new DoubleAnimation();
animation.From = 1;
animation.To = 0;
animation.Duration = new Duration(TimeSpan.FromSeconds(2));
animation.SetValue(Storyboard.TargetProperty, this);
animation.SetValue(Storyboard.TargetPropertyProperty, new PropertyPath(Rectangle.OpacityProperty));
Storyboard board = new Storyboard();
board.Children.Add(animation);
board.Begin(this);
}
}
#endregion
}
}

113
src/AddIns/Debugger/Debugger.AddIn/Tooltips/LazyItemsControl.cs

@ -0,0 +1,113 @@ @@ -0,0 +1,113 @@
// 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.Windows.Controls;
using ICSharpCode.SharpDevelop;
namespace Debugger.AddIn.Tooltips
{
/// <summary>
/// ItemsControl wrapper that takes VirtualizingIEnumerable as source,
/// and adds additional items from the source to underlying ItemsControl when scrolled to bottom.
/// </summary>
public class LazyItemsControl<T>
{
private ItemsControl itemsControl;
private int initialItemsCount;
/// <summary>
/// Creates new instance of LazyItemsControl.
/// </summary>
/// <param name="wrappedItemsControl">ItemsControl to wrap and add items to it when scrolled to bottom.</param>
/// <param name="initialItemsCount">Number of items to be initially displayed in wrapped ItemsControl.</param>
public LazyItemsControl(ItemsControl wrappedItemsControl, int initialItemsCount)
{
if (wrappedItemsControl == null)
throw new ArgumentNullException("wrappedItemsControl");
this.initialItemsCount = initialItemsCount;
this.itemsControl = wrappedItemsControl;
this.itemsControl.AddHandler(ScrollViewer.ScrollChangedEvent, new ScrollChangedEventHandler(handleScroll));
}
private ScrollViewer scrollViewerCached;
public ScrollViewer ScrollViewer
{
get
{
if (this.scrollViewerCached == null)
this.scrollViewerCached = this.itemsControl.GetScrollViewer();
return this.scrollViewerCached;
}
}
public bool IsScrolledToStart
{
get
{
if (ScrollViewer == null) // Visual tree not initialized yet
return false;
return ScrollViewer.VerticalOffset == 0;
}
}
public bool IsScrolledToEnd
{
get
{
if (itemsSourceTotalCount == null) {
// not scrolled to end of IEnumerable yet
return false;
}
// already scrolled to end of IEnumerable
int totalItems = itemsSourceTotalCount.Value;
return (ScrollViewer.VerticalOffset >= totalItems - ScrollViewer.ViewportHeight);
}
}
private int? itemsSourceTotalCount = null;
/// <summary> Items count of underlying IEnumerable. Null until scrolled to the end of IEnumerable. </summary>
public int? ItemsSourceTotalCount
{
get
{
return this.itemsSourceTotalCount;
}
}
private VirtualizingIEnumerable<T> itemsSource;
/// <summary> The collection that underlying ItemsControl sees. </summary>
public VirtualizingIEnumerable<T> ItemsSource
{
get { return itemsSource; }
set
{
this.itemsSource = value;
addNextItems(this.itemsSource, initialItemsCount);
this.itemsControl.ItemsSource = value;
}
}
private void addNextItems(VirtualizingIEnumerable<T> sourceToAdd, int nItems)
{
sourceToAdd.AddNextItems(nItems);
if (!sourceToAdd.HasNext) {
// all items from IEnumerable have been added
this.itemsSourceTotalCount = sourceToAdd.Count;
}
}
private void handleScroll(object sender, ScrollChangedEventArgs e)
{
if (e.VerticalChange > 0) {
// scrolled to bottom
if (e.VerticalOffset >= this.itemsSource.Count - e.ViewportHeight) {
addNextItems(this.itemsSource, (int)e.VerticalChange);
}
}
}
}
}

29
src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinCloseControl.xaml

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<UserControl
Background="Transparent"
x:Class="Debugger.AddIn.Tooltips.PinCloseControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="PinControlsDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<StackPanel>
<Button
Name="CloseButton"
Click="CloseButton_Click"
Template="{StaticResource CloseButtonTemplate}" />
<ToggleButton
Name="UnpinButton"
Checked="UnpinButton_Checked"
Unchecked="UnpinButton_Unchecked"
Template="{StaticResource PinButtonTemplate}" />
<ToggleButton
Name="CommentButton"
Checked="CommentButton_Checked"
Unchecked="CommentButton_Unchecked"
Template="{StaticResource CommentButtonTemplate}" />
</StackPanel>
</UserControl>

74
src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinCloseControl.xaml.cs

@ -0,0 +1,74 @@ @@ -0,0 +1,74 @@
// 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.Windows;
using System.Windows.Controls;
namespace Debugger.AddIn.Tooltips
{
public class ShowingCommentEventArgs : EventArgs
{
public bool ShowComment { get; private set; }
public ShowingCommentEventArgs(bool showComment)
{
ShowComment = showComment;
}
}
public partial class PinCloseControl : UserControl
{
public event EventHandler Closed;
public event EventHandler PinningChanged;
public event EventHandler<ShowingCommentEventArgs> ShowingComment;
public PinCloseControl()
{
InitializeComponent();
}
public bool IsChecked {
get {
return UnpinButton.IsChecked.GetValueOrDefault(false);
}
}
void CloseButton_Click(object sender, RoutedEventArgs e)
{
var handler = Closed;
if (handler != null)
handler(this, EventArgs.Empty);
}
void CommentButton_Checked(object sender, RoutedEventArgs e)
{
var handler = ShowingComment;
if (handler != null)
handler(this, new ShowingCommentEventArgs(true));
}
void CommentButton_Unchecked(object sender, RoutedEventArgs e)
{
var handler = ShowingComment;
if (handler != null)
handler(this, new ShowingCommentEventArgs(false));
}
void UnpinButton_Checked(object sender, RoutedEventArgs e)
{
var handler = PinningChanged;
if (handler != null)
handler(this, EventArgs.Empty);
}
void UnpinButton_Unchecked(object sender, RoutedEventArgs e)
{
var handler = PinningChanged;
if (handler != null)
handler(this, EventArgs.Empty);
}
}
}

337
src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinControlsDictionary.xaml

@ -0,0 +1,337 @@ @@ -0,0 +1,337 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Debugger.AddIn.Tooltips"
>
<LinearGradientBrush x:Key="OrangeBrushKey" EndPoint="0,1" StartPoint="0,0">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0" Color="White" />
<GradientStop Offset="0.5" Color="Orange" />
<GradientStop Offset="1" Color="Orange" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="OrangePressedBrushKey" EndPoint="0,1" StartPoint="0,0">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="1" Color="White" />
<GradientStop Offset="0.5" Color="Orange" />
<GradientStop Offset="0" Color="Orange" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="SilverBrushKey" EndPoint="0,1" StartPoint="0,0">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0" Color="White" />
<GradientStop Offset="0.5" Color="LightGray" />
<GradientStop Offset="1" Color="LightGray" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="SilverPressedBrushKey" EndPoint="0,1" StartPoint="0,0">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="1" Color="White" />
<GradientStop Offset="0.5" Color="LightGray" />
<GradientStop Offset="0" Color="LightGray" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<ControlTemplate x:Key="CloseButtonTemplate" TargetType="Button">
<Border Width="16" Height="16" Name="TheBorder" CornerRadius="2,2,0,0" BorderThickness="1" BorderBrush="Black" Background="{StaticResource SilverPressedBrushKey}">
<Canvas>
<Line X1="3.5" X2="10.5" Y1="3.5" Y2="10.5" Stroke="Black" StrokeThickness="2"/>
<Line X1="3.5" X2="10.5" Y1="10.5" Y2="3.5" Stroke="Black" StrokeThickness="2"/>
</Canvas>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsMouseOver" Value="true">
<Setter TargetName="TheBorder" Property="Background" Value="{StaticResource OrangeBrushKey}"/>
<Setter TargetName="TheBorder" Property="BorderBrush" Value="Silver"/>
</Trigger>
<Trigger Property="ButtonBase.IsPressed" Value="True">
<Setter TargetName="TheBorder" Property="Background" Value="{StaticResource OrangePressedBrushKey}"/>
<Setter TargetName="TheBorder" Property="BorderBrush" Value="Silver"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<TransformGroup x:Key="Rotate">
<RotateTransform Angle="270" CenterX="7" CenterY="7"/>
</TransformGroup>
<TransformGroup x:Key="RotateUnpin">
<RotateTransform Angle="270" CenterX="7" CenterY="7"/>
<RotateTransform Angle="-90" CenterX="7" CenterY="7"/>
<ScaleTransform ScaleY="-1" CenterX="7" CenterY="7"/>
</TransformGroup>
<TransformGroup x:Key="RotatePin">
<RotateTransform Angle="-90" CenterX="7" CenterY="7"/>
</TransformGroup>
<TransformGroup x:Key="FlipComment">
<ScaleTransform CenterX="7" CenterY="7" ScaleY="-1"/>
</TransformGroup>
<ControlTemplate x:Key="PinButtonTemplate" TargetType="ToggleButton">
<Border Width="16" Height="16" Name="TheBorder" CornerRadius="0" BorderThickness="1" BorderBrush="Black" Background="{StaticResource SilverPressedBrushKey}">
<Canvas Name="TheCanvas">
<Line X1="4" X2="10" Y1="2" Y2="2" Stroke="Black" StrokeThickness="1"/>
<Line X1="9" X2="9" Y1="2" Y2="8" Stroke="Black" StrokeThickness="1"/>
<Line X1="2" X2="12" Y1="8" Y2="8" Stroke="Black" StrokeThickness="1"/>
<Rectangle Fill="Black" Width="2" Height="5" Canvas.Left="4" Canvas.Top="3"/>
<Line X1="7" X2="7" Y1="9" Y2="12" Stroke="Black" StrokeThickness="1"/>
</Canvas>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsMouseOver" Value="true">
<Setter TargetName="TheBorder" Property="Background" Value="{StaticResource OrangeBrushKey}"/>
<Setter TargetName="TheBorder" Property="BorderBrush" Value="Silver"/>
</Trigger>
<Trigger Property="ButtonBase.IsPressed" Value="True">
<Setter TargetName="TheCanvas" Property="RenderTransform" Value="{StaticResource RotatePin}"/>
<Setter TargetName="TheBorder" Property="Background" Value="{StaticResource OrangePressedBrushKey}"/>
<Setter TargetName="TheBorder" Property="BorderBrush" Value="Silver"/>
</Trigger>
<Trigger Property="IsChecked" Value="true">
<Setter TargetName="TheCanvas" Property="RenderTransform" Value="{StaticResource RotatePin}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="CommentButtonTemplate" TargetType="ToggleButton">
<Border Width="16" Height="16" Name="TheBorder" CornerRadius="0,0,2,2" BorderThickness="1" BorderBrush="Black" Background="{StaticResource SilverPressedBrushKey}">
<Canvas Name="TheCanvas">
<Line X1="3" Y1="3" X2="7" Y2="7.5" Stroke="Black" StrokeThickness="1"/>
<Line X1="7" Y1="7.4" X2="11" Y2="3" Stroke="Black" StrokeThickness="1"/>
<Line X1="3" Y1="7.5" X2="7" Y2="12" Stroke="Black" StrokeThickness="1"/>
<Line X1="7" Y1="12" X2="11" Y2="7.5" Stroke="Black" StrokeThickness="1"/>
</Canvas>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsMouseOver" Value="true">
<Setter TargetName="TheBorder" Property="Background" Value="{StaticResource OrangeBrushKey}"/>
<Setter TargetName="TheBorder" Property="BorderBrush" Value="Silver"/>
</Trigger>
<Trigger Property="ButtonBase.IsPressed" Value="True">
<Setter TargetName="TheBorder" Property="Background" Value="{StaticResource OrangePressedBrushKey}"/>
<Setter TargetName="TheBorder" Property="BorderBrush" Value="Silver"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="TheCanvas" Property="RenderTransform" Value="{StaticResource FlipComment}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<SolidColorBrush x:Key="MouseOverPinBrush" Color="Black" />
<ControlTemplate x:Key="PinTooltipButtonTemplate" TargetType="ToggleButton">
<Border Width="16" Height="16" Name="TheBorder" CornerRadius="2" BorderBrush="Transparent" BorderThickness="1" Background="Transparent">
<Canvas RenderTransform="{StaticResource Rotate}" Name="TheCanvas">
<Line X1="4" X2="10" Y1="2" Y2="2" Stroke="Silver" StrokeThickness="1" Name="Line1"/>
<Line X1="9" X2="9" Y1="2" Y2="8" Stroke="Silver" StrokeThickness="1" Name="Line2"/>
<Line X1="2" X2="12" Y1="8" Y2="8" Stroke="Silver" StrokeThickness="1" Name="Line3"/>
<Rectangle Fill="Silver" Width="2" Height="7" Canvas.Left="4" Canvas.Top="2" Name="Rectangle"/>
<Line X1="7" X2="7" Y1="9" Y2="12" Stroke="Silver" StrokeThickness="1" Name="Line4"/>
</Canvas>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="ButtonBase.IsPressed" Value="True">
<Setter TargetName="TheCanvas" Property="RenderTransform" Value="{StaticResource RotateUnpin}"/>
</Trigger>
<Trigger Property="ButtonBase.IsMouseOver" Value="True">
<Setter TargetName="Line1" Property="Stroke" Value="{StaticResource MouseOverPinBrush}"/>
<Setter TargetName="Line2" Property="Stroke" Value="{StaticResource MouseOverPinBrush}"/>
<Setter TargetName="Line3" Property="Stroke" Value="{StaticResource MouseOverPinBrush}"/>
<Setter TargetName="Line4" Property="Stroke" Value="{StaticResource MouseOverPinBrush}"/>
<Setter TargetName="Rectangle" Property="Fill" Value="{StaticResource MouseOverPinBrush}"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="TheCanvas" Property="RenderTransform" Value="{StaticResource RotateUnpin}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style
TargetType="{x:Type TextBox}"
x:Key="TextStyle">
<Setter
Property="OverridesDefaultStyle"
Value="True" />
<Setter
Property="VerticalAlignment"
Value="Center" />
<Setter
Property="FontFamily" Value="Khmer UI" />
<Setter Property="FontSize" Value="12" />
<Setter
Property="KeyboardNavigation.TabNavigation"
Value="None" />
<Setter
Property="FocusVisualStyle"
Value="{x:Null}" />
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="{x:Type TextBoxBase}">
<Border
Name="Border"
Background="Transparent"
BorderBrush="Transparent"
BorderThickness="0">
<ScrollViewer
Margin="0"
Name="PART_ContentHost" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="TextBlock" x:Key="TextBlockStyle">
<Setter Property="Margin" Value="4 0" />
<Setter
Property="FontFamily" Value="Khmer UI" />
<Setter Property="FontSize" Value="12" />
</Style>
<Style x:Key="PinThumbStyle" TargetType="Thumb">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Thumb">
<StackPanel x:Name="Container"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
x:Key="ExpandCollapseToggleStyle"
TargetType="{x:Type ToggleButton}">
<Setter
Property="Focusable"
Value="False" />
<Setter
Property="Width"
Value="19" />
<Setter
Property="Height"
Value="13" />
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="{x:Type ToggleButton}">
<Border
Width="19"
Height="13"
Background="Transparent">
<Border
Width="9"
Height="9"
BorderThickness="1"
BorderBrush="#FF7898B5"
CornerRadius="1"
SnapsToDevicePixels="true">
<Border.Background>
<LinearGradientBrush
StartPoint="0,0"
EndPoint="1,1">
<LinearGradientBrush.GradientStops>
<GradientStop
Color="White"
Offset=".2" />
<GradientStop
Color="#FFC0B7A6"
Offset="1" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Border.Background>
<Path
x:Name="ExpandPath"
Margin="1,1,1,1"
Fill="Black"
Data="M 0 2 L 0 3 L 2 3 L 2 5 L 3 5 L 3 3 L 5 3 L 5 2 L 3 2 L 3 0 L 2 0 L 2 2 Z" />
</Border>
</Border>
<ControlTemplate.Triggers>
<Trigger
Property="IsChecked"
Value="True">
<Setter
Property="Data"
TargetName="ExpandPath"
Value="M 0 2 L 0 3 L 5 3 L 5 2 Z" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
x:Key="upDownBorderStyle"
TargetType="{x:Type Border}">
<Setter
Property="BorderBrush"
Value="Gray" />
<Setter
Property="HorizontalAlignment"
Value="Stretch" />
<Setter
Property="Margin"
Value="0" />
<Setter
Property="Padding"
Value="0" />
<Setter
Property="Background"
Value="#FFECF7FC" />
<Setter
Property="Height"
Value="14" />
<Style.Triggers>
<DataTrigger
Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsEnabled}"
Value="False">
<Setter
Property="Background"
Value="#FFE0E0E0"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
<Style
x:Key="upButtonStyle"
TargetType="{x:Type RepeatButton}">
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="{x:Type RepeatButton}">
<Border
Style="{StaticResource upDownBorderStyle}"
BorderThickness="1 1 1 0">
<ContentPresenter
HorizontalAlignment="Center"></ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
x:Key="downButtonStyle"
TargetType="{x:Type RepeatButton}">
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="{x:Type RepeatButton}">
<Border
Style="{StaticResource upDownBorderStyle}"
BorderThickness="1 0 1 1">
<ContentPresenter
HorizontalAlignment="Center"></ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

258
src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinDebuggerControl.xaml

@ -0,0 +1,258 @@ @@ -0,0 +1,258 @@
<UserControl x:Class="Debugger.AddIn.Tooltips.PinDebuggerControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:local="clr-namespace:Debugger.AddIn.Tooltips"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:core="http://icsharpcode.net/sharpdevelop/core"
>
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="PinControlsDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.Resources>
<LinearGradientBrush x:Key="DataGridBackground"
StartPoint="0,-0.03"
EndPoint="0,1">
<GradientStop
Color="White" />
<GradientStop
Color="#FFFAFCFE"
Offset="0.983" />
<GradientStop
Color="#FFECF7FC"
Offset="0.07" />
<GradientStop
Color="#FFEEF7FA"
Offset="0.436" />
</LinearGradientBrush>
<Style x:Key="CellStyle"
TargetType="{x:Type DataGridCell}">
<Setter
Property="Focusable"
Value="false" />
<!-- Focusable=true blocks shortcuts if cell is focused -->
<Setter
Property="BorderThickness"
Value="0" />
<Setter Property="Width" Value="Auto" />
<Style.Triggers>
<Trigger
Property="IsSelected"
Value="True">
<!-- disable selection highlight -->
<Setter
Property="Foreground"
Value="Black" />
<Setter
Property="Background"
Value="{x:Null}" />
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="RowStyle"
TargetType="{x:Type DataGridRow}">
<Setter
Property="Background"
Value="Transparent"></Setter>
</Style>
<Style x:Key="DataGridStyle" TargetType="DataGrid">
<Setter Property="VerticalScrollBarVisibility" Value="Disabled"/>
<Setter Property="HorizontalScrollBarVisibility" Value="Disabled"/>
<Setter Property="GridLinesVisibility" Value="None"/>
<Setter Property="RowHeight" Value="18"/>
<Setter Property="MaxHeight" Value="202"/>
<Setter Property="MinHeight" Value="20" />
<Setter Property="SelectionMode" Value="Single"/>
<Setter Property="SelectionUnit" Value="FullRow"/>
<Setter Property="AutoGenerateColumns" Value="False"/>
<Setter Property="CanUserAddRows" Value="False"/>
<Setter Property="HeadersVisibility" Value="None"/>
<Setter Property="BorderBrush" Value="Gray"/>
<Setter Property="Background" Value="{StaticResource DataGridBackground}"/>
<Setter Property="CellStyle" Value="{StaticResource CellStyle}"/>
<Setter Property="RowStyle" Value="{StaticResource RowStyle}"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Cursor" Value="Arrow"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel VerticalAlignment="Center">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<DataGrid
Width="21"
BorderThickness="1,1,0,1"
Background="White"
x:Name="ExpandersGrid"
Style="{StaticResource DataGridStyle}"
ItemsSource="{Binding}">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid
Background="White">
<StackPanel
VerticalAlignment="Center">
<ToggleButton
x:Name="btnExpander"
Style="{StaticResource ExpandCollapseToggleStyle}"
Checked="BtnExpander_Checked"
Unchecked="BtnExpander_Unchecked"
Padding="0"
Margin="0" />
</StackPanel>
</Grid>
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding Path=HasChildNodes}"
Value="False">
<Setter
TargetName="btnExpander"
Property="Visibility"
Value="Collapsed" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<DataGrid
BorderThickness="0,1,0,1"
Grid.Column="1"
IsEnabled="False"
ColumnWidth="SizeToCells"
Style="{StaticResource DataGridStyle}"
ItemsSource="{Binding}"
Foreground="Black"
Name="dataGrid">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image
Source="{Binding ImageSource}"></Image>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn
MinWidth="20"
Header="Name">
<!-- Name -->
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border
BorderBrush="#FFDDDDDD"
BorderThickness="0 0 1 0">
<TextBlock
Style="{StaticResource TextBlockStyle}"
Text="{Binding Path=FullName, Mode=OneWay}"
VerticalAlignment="Center"></TextBlock>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn IsReadOnly="True"
Width="SizeToCells"
Header="Text">
<!-- Text (value) -->
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox
Style="{StaticResource TextStyle}"
IsEnabled="false"
Text="{Binding Path=Text}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<DataGrid
MaxWidth="20"
BorderThickness="1"
Grid.Column="2"
x:Name="ImagesGrid"
Style="{StaticResource DataGridStyle}"
ItemsSource="{Binding}">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border
Name="ImageBorder"
CornerRadius="7"
BorderBrush="Transparent"
BorderThickness="1"
Height="14"
Width="14">
<Image Width="9" Height="9" Margin="2 2"
x:Name="RefreshContentImage"
MouseDown="RefreshContentImage_MouseDown"
Tag="{Binding}"
Source="{core:GetBitmap Icons.16x16.Refresh}"/>
</Border>
<DataTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter
TargetName="ImageBorder"
Property="BorderBrush"
Value="Gray" />
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
<!-- comment textbox -->
<Border
Name="BorderComment"
Background="White"
BorderThickness="1,0,1,1"
BorderBrush="Gray"
Height="0"
MaxHeight="50">
<TextBox
Name="CommentTextBox"
TextChanged="CommentTextBox_TextChanged"
Margin="3"/>
</Border>
</StackPanel>
<local:PinCloseControl
VerticalAlignment="Center"
Background="Transparent"
Grid.Column="1"
Margin="5,0,0,0"
x:Name="PinCloseControl">
<local:PinCloseControl.Effect>
<DropShadowEffect
ShadowDepth="5"
Direction="330"
Color="Black"
Opacity="0.5"/>
</local:PinCloseControl.Effect>
</local:PinCloseControl>
</Grid>
</UserControl>

378
src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinDebuggerControl.xaml.cs

@ -0,0 +1,378 @@ @@ -0,0 +1,378 @@
// 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.ComponentModel;
using System.Collections.Generic;
using System.Collections.ObjectModel;
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 Debugger.AddIn.TreeModel;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Bookmarks;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Services;
using Services.Debugger.Tooltips;
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.IsDebuggerRunning)
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) {
PinningBinding.GetPinlayer(provider.TextEditor).Pin(this);
}
}
void Unpin()
{
var provider = WorkbenchSingleton.Workbench.ActiveContent as ITextEditorProvider;
if(provider != null) {
PinningBinding.GetPinlayer(provider.TextEditor).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 buton
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)
{
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, 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;
this.childPopup.ItemsSource = clickedNode.ChildNodes;
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();
}
}
}
void OnLoaded(object sender, RoutedEventArgs e)
{
this.CommentTextBox.Text = Mark.Comment;
}
#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
void RefreshContentImage_MouseDown(object sender, MouseButtonEventArgs e)
{
// refresh content
ITreeNode node = ((Image)sender).DataContext as ITreeNode;
if (!DebuggerService.IsDebuggerRunning)
return;
var resultNode = currentDebugger.GetNode(node.FullName, 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.CompareTo(node) == 0)
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 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.IsDebuggerRunning)
Opacity = 1;
else
Opacity = MINIMUM_OPACITY;
AnimateCloseControl(false);
Cursor = Cursors.IBeam;
base.OnMouseLeave(e);
}
#endregion
}
}

226
src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinLayer.cs

@ -0,0 +1,226 @@ @@ -0,0 +1,226 @@
// 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.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.SharpDevelop.Refactoring;
using Services.Debugger.Tooltips;
namespace Debugger.AddIn.Tooltips
{
/// <summary>
/// Pin layer class. This class handles the pinning and unpinning operations.
/// </summary>
public class PinLayer : Layer
{
private Canvas pinningSurface;
private double verticalOffset = 0;
/// <summary>
/// PinLayer constructor.
/// </summary>
/// <param name="textArea">Text area for this layer.</param>
public PinLayer(TextArea textArea) : base(textArea.TextView, KnownLayer.DataPins)
{
pinningSurface = new Canvas();
this.Children.Add(pinningSurface);
textView.VisualLinesChanged += new EventHandler(textView_VisualLinesChanged);
}
/// <summary>
/// Pins an element;
/// </summary>
/// <param name="element">Element to pin.</param>
public void Pin(PinDebuggerControl element)
{
if (element == null)
throw new NullReferenceException("Element is null!");
Thumb currentThumb = new Thumb();
// check for saved position
if (!element.Mark.PinPosition.HasValue) {
// this is satisfied when pinning the first time
element.Mark.PinPosition = new Point {
X = element.Location.X + textView.HorizontalOffset,
Y = element.Location.Y + textView.VerticalOffset
};
Canvas.SetTop(currentThumb, element.Location.Y);
Canvas.SetLeft(currentThumb, element.Location.X);
}
else {
// this is satisfied when loading the pins - so we might have hidden pins
element.Location = new Point {
X = element.Mark.PinPosition.Value.X - textView.HorizontalOffset,
Y = element.Mark.PinPosition.Value.Y - textView.VerticalOffset
};
Canvas.SetTop(currentThumb, element.Mark.PinPosition.Value.Y);
Canvas.SetLeft(currentThumb, element.Mark.PinPosition.Value.X);
}
currentThumb.Style = element.TryFindResource("PinThumbStyle") as Style;
currentThumb.ApplyTemplate();
currentThumb.DragDelta += onDragDelta;
currentThumb.DragStarted += currentThumb_DragStarted;
currentThumb.DragCompleted += currentThumb_DragCompleted;
var container = TryFindChild<StackPanel>(currentThumb);
container.Children.Add(element);
pinningSurface.Children.Add(currentThumb);
}
/// <summary>
/// Unpins an element.
/// </summary>
/// <param name="element">Element to unpin.</param>
public void Unpin(PinDebuggerControl element)
{
if (element == null)
throw new NullReferenceException("Element is null!");
foreach (var thumb in this.pinningSurface.Children) {
PinDebuggerControl pinControl = TryFindChild<PinDebuggerControl>((DependencyObject)thumb);
if (pinControl != null && pinControl == element)
{
pinningSurface.Children.Remove((UIElement)thumb);
element.Close();
break;
}
}
}
void textView_VisualLinesChanged(object sender, EventArgs e)
{
foreach (var ctrl in this.pinningSurface.Children) {
var currentThumb = ctrl as Thumb;
PinDebuggerControl pinControl = TryFindChild<PinDebuggerControl>(currentThumb);
if (pinControl != null)
{
// update relative location
Point location = pinControl.Location;
location.X -= textView.HorizontalOffset;
location.Y += verticalOffset - textView.VerticalOffset;
Canvas.SetLeft(currentThumb, location.X);
Canvas.SetTop(currentThumb, location.Y);
pinControl.Location = location;
pinControl.Mark.PinPosition = new Point {
X = location.X + textView.HorizontalOffset,
Y = location.Y + textView.VerticalOffset,
};
}
}
verticalOffset = textView.VerticalOffset;
}
#region Mouse move
void onDragDelta(object sender, DragDeltaEventArgs e)
{
Thumb currnetThumb = (Thumb)sender;
currnetThumb.Cursor = Cursors.Arrow;
double left = Canvas.GetLeft(currnetThumb) + e.HorizontalChange;
double top = Canvas.GetTop(currnetThumb) + e.VerticalChange;
Canvas.SetLeft(currnetThumb, left);
Canvas.SetTop(currnetThumb, top);
}
void currentThumb_DragCompleted(object sender, DragCompletedEventArgs e)
{
Thumb currnetThumb = (Thumb)sender;
currnetThumb.Cursor = Cursors.Arrow;
var pinControl = TryFindChild<PinDebuggerControl>(currnetThumb);
if (pinControl != null) {
double left = Canvas.GetLeft(currnetThumb);
double top = Canvas.GetTop(currnetThumb);
pinControl.Opacity = 1d;
pinControl.Location = new Point { X = left, Y = top };
// pin's position is with respect to the layer.
pinControl.Mark.PinPosition =
new Point
{
X = textView.HorizontalOffset + left,
Y = textView.VerticalOffset + top
};
}
}
void currentThumb_DragStarted(object sender, DragStartedEventArgs e)
{
Thumb currnetThumb = (Thumb)sender;
currnetThumb.Cursor = Cursors.Arrow;
var pinControl = TryFindChild<PinDebuggerControl>(currnetThumb);
if (pinControl != null)
pinControl.Opacity = 1d;
}
#endregion
#region Static helpers
static T TryFindChild<T>(DependencyObject root) where T : DependencyObject
{
return ContextActionsControl.SearchVisualTree<T>(root);
}
static T TryFindParent<T>(DependencyObject child) where T : DependencyObject
{
if (child is T) return child as T;
DependencyObject parentObject = GetParentObject(child);
if (parentObject == null) return null;
var parent = parentObject as T;
if (parent != null && parent is T)
{
return parent;
}
else
{
return TryFindParent<T>(parentObject);
}
}
static DependencyObject GetParentObject(DependencyObject child)
{
if (child == null) return null;
ContentElement contentElement = child as ContentElement;
if (contentElement != null)
{
DependencyObject parent = ContentOperations.GetParent(contentElement);
if (parent != null) return parent;
FrameworkContentElement fce = contentElement as FrameworkContentElement;
return fce != null ? fce.Parent : null;
}
FrameworkElement frameworkElement = child as FrameworkElement;
if (frameworkElement != null)
{
DependencyObject parent = frameworkElement.Parent;
if (parent != null) return parent;
}
return VisualTreeHelper.GetParent(child);
}
#endregion
}
}

121
src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinningBinding.cs

@ -0,0 +1,121 @@ @@ -0,0 +1,121 @@
// 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.ObjectModel;
using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Bookmarks;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Editor;
using Services.Debugger.Tooltips;
namespace Debugger.AddIn.Tooltips
{
public class PinningBinding : DefaultLanguageBinding
{
ITextEditor _editor;
PinLayer pinLayer;
public PinningBinding()
{}
public override void Attach(ITextEditor editor)
{
if (editor == null)
return;
var textEditor = editor.GetService(typeof(TextEditor)) as TextEditor;
if (textEditor != null) {
pinLayer = new PinLayer(textEditor.TextArea);
textEditor.TextArea.TextView.InsertLayer(
pinLayer,
KnownLayer.Caret,
LayerInsertionPosition.Above);
}
_editor = editor;
CreatePins(_editor);
base.Attach(editor);
}
public override void Detach()
{
ClosePins(_editor);
pinLayer = null;
base.Detach();
}
public void CreatePins(ITextEditor editor)
{
// load pins
var pins = BookmarkManager.Bookmarks.FindAll(
b => b is PinBookmark && b.FileName == editor.FileName);
foreach (var bookmark in pins) {
var pin = (PinBookmark)bookmark;
pin.Popup = new PinDebuggerControl();
pin.Popup.Mark = pin;
var nodes = new ObservableCollection<ITreeNode>();
foreach (var tuple in pin.SavedNodes) {
string imageName = !string.IsNullOrEmpty(tuple.Item1) ? tuple.Item1 : "Icons.16x16.Field";
var node = new Debugger.AddIn.TreeModel.SavedTreeNode(
new ResourceServiceImage(imageName),
tuple.Item2,
tuple.Item3);
node.ImageName = imageName;
nodes.Add(node);
}
pin.SavedNodes.Clear();
pin.Popup.ItemsSource = nodes;
pin.Nodes = nodes;
pin.Popup.Open();
pinLayer.Pin((PinDebuggerControl)pin.Popup);
}
}
public void ClosePins(ITextEditor editor)
{
// save pins
var pins = BookmarkManager.Bookmarks.FindAll(
b => b is PinBookmark && b.FileName == editor.FileName);
foreach (var bookmark in pins) {
var pin = (PinBookmark)bookmark;
if (!pin.PinPosition.HasValue)
pin.PinPosition = pin.Popup.Location;
// nodes
if (pin.SavedNodes == null)
pin.SavedNodes = new System.Collections.Generic.List<Tuple<string, string, string>>();
foreach (var node in pin.Nodes) {
pin.SavedNodes.Add(
new Tuple<string, string, string>(
"Icons.16x16.Field",
node.FullName,
node.Text));
}
pinLayer.Unpin((PinDebuggerControl)pin.Popup);
pin.Popup = null;
}
}
public static PinLayer GetPinlayer(ITextEditor editor) {
var textEditor = editor.GetService(typeof(TextEditor)) as TextEditor;
if (textEditor != null) {
foreach(var layer in textEditor.TextArea.TextView.Layers)
if(((Layer)layer).LayerType == KnownLayer.DataPins)
return (PinLayer)layer;
}
return null;
}
}
}

53
src/AddIns/Debugger/Debugger.AddIn/Tooltips/VirtualizingIEnumerable.cs

@ -0,0 +1,53 @@ @@ -0,0 +1,53 @@
// 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;
namespace Debugger.AddIn.Tooltips
{
/// <summary>
/// A wrapper around IEnumerable&lt;T&gt; with AddNextItems method for pulling additional items
/// from underlying IEnumerable&lt;T&gt;.
/// Can be used as source for <see cref="LazyItemsControl" />.
/// </summary>
public class VirtualizingIEnumerable<T> : ObservableCollection<T>
{
private IEnumerator<T> originalSourceEnumerator;
public VirtualizingIEnumerable(IEnumerable<T> originalSource)
{
if (originalSource == null)
throw new ArgumentNullException("originalSource");
this.originalSourceEnumerator = originalSource.GetEnumerator();
}
private bool hasNext = true;
/// <summary>
/// False if all items from underlying IEnumerable have already been added.
/// </summary>
public bool HasNext
{
get
{
return this.hasNext;
}
}
/// <summary>
/// Requests next <paramref name="count"/> items from underlying IEnumerable source and adds them to the collection.
/// </summary>
public void AddNextItems(int count)
{
for (int i = 0; i < count; i++) {
if (!originalSourceEnumerator.MoveNext()) {
this.hasNext = false;
break;
}
this.Add(originalSourceEnumerator.Current);
}
}
}
}

48
src/AddIns/Debugger/Debugger.AddIn/Tooltips/VisualizerPicker.cs

@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
// 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.Linq;
using System.Windows.Controls;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Debugging;
namespace Debugger.AddIn.Tooltips
{
/// <summary>
/// Control displaying and executing <see cref="IVisualizerCommand">visualizer commands</see>.
/// </summary>
public class VisualizerPicker : ComboBox
{
public VisualizerPicker()
{
this.SelectionChanged += VisualizerPicker_SelectionChanged;
}
void VisualizerPicker_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (this.SelectedItem == null) {
return;
}
var clickedCommand = this.SelectedItem as IVisualizerCommand;
if (clickedCommand == null) {
throw new InvalidOperationException(
string.Format("{0} clicked, only instances of {1} must be present in {2}.",
this.SelectedItem.GetType().ToString(), typeof(IVisualizerCommand).Name, typeof(VisualizerPicker).Name));
}
clickedCommand.Execute();
// Make no item selected, so that multiple selections of the same item always execute the command.
// This triggers VisualizerPicker_SelectionChanged again, which returns immediately.
this.SelectedIndex = -1;
}
public new IEnumerable<IVisualizerCommand> ItemsSource
{
get { return (IEnumerable<IVisualizerCommand>)base.ItemsSource; }
set { base.ItemsSource = value; }
}
}
}

135
src/AddIns/Debugger/Debugger.AddIn/Tooltips/VisualizerPicker.xaml

@ -0,0 +1,135 @@ @@ -0,0 +1,135 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
xmlns:debugging="clr-namespace:Debugger.AddIn.Tooltips">
<BitmapImage x:Key="MagnifierImage" UriSource="magnifier.png" />
<Style x:Key="ComboBoxFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Stroke="Black" StrokeDashArray="1 2" StrokeThickness="1" Margin="4,4,21,4" SnapsToDevicePixels="true"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<LinearGradientBrush x:Key="ButtonNormalBackground" EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#F3F3F3" Offset="0"/>
<GradientStop Color="#EBEBEB" Offset="0.5"/>
<GradientStop Color="#DDDDDD" Offset="0.5"/>
<GradientStop Color="#CDCDCD" Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="ButtonNormalBorder" Color="#FF707070"/>
<Geometry x:Key="DownArrowGeometry">M 0 0 L 2 3 L 4 0 Z</Geometry>
<Style x:Key="ComboBoxReadonlyToggleButton" TargetType="{x:Type ToggleButton}">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Focusable" Value="false"/>
<Setter Property="ClickMode" Value="Press"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<!-- Button face - changed from original ButtonChrome to Border -->
<Border Name="FaceBorder" Background="Transparent" CornerRadius="2" BorderBrush="Transparent" BorderThickness="1" Padding="1" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="5"/>
</Grid.ColumnDefinitions>
<!--
<Rectangle Width="10" Height="10" Grid.Column="0" Fill="Black"></Rectangle> -->
<Image Grid.Column="0" Width="10" Height="10" Stretch="Fill" Source="{StaticResource MagnifierImage}" />
<Path Grid.Column="1" x:Name="Arrow" Fill="Black" HorizontalAlignment="Center" Margin="0" VerticalAlignment="Center" Data="{StaticResource DownArrowGeometry}"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter TargetName="FaceBorder" Property="Background" Value="White"/>
<Setter TargetName="FaceBorder" Property="BorderBrush" Value="#FFE0EDFF"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="FaceBorder" Property="Background" Value="White"/>
<Setter TargetName="FaceBorder" Property="BorderBrush" Value="#FFE0EDFF"/>
<!-- #FFE0EDFF border -->
<!-- #FFD9D9E9 fill -->
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<LinearGradientBrush x:Key="TextBoxBorder" EndPoint="0,20" StartPoint="0,0" MappingMode="Absolute">
<GradientStop Color="#ABADB3" Offset="0.05"/>
<GradientStop Color="#E2E3EA" Offset="0.07"/>
<GradientStop Color="#E3E9EF" Offset="1"/>
</LinearGradientBrush>
<Style TargetType="{x:Type debugging:VisualizerPicker}">
<Setter Property="FocusVisualStyle" Value="{StaticResource ComboBoxFocusVisual}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"/>
<Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/>
<Setter Property="BorderBrush" Value="{StaticResource ButtonNormalBorder}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="Padding" Value="4,3"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type debugging:VisualizerPicker}">
<!-- ComboBox face -->
<Grid x:Name="MainGrid" SnapsToDevicePixels="true" Width="18" Height="16">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="5"/>
</Grid.ColumnDefinitions>
<Popup x:Name="PART_Popup" Margin="1" AllowsTransparency="true" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" Placement="Bottom" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Grid.ColumnSpan="2">
<Microsoft_Windows_Themes:SystemDropShadowChrome x:Name="Shdw" MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{Binding ActualWidth, ElementName=MainGrid}" Color="Transparent">
<Border x:Name="DropDownBorder" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="1">
<ScrollViewer CanContentScroll="true">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" KeyboardNavigation.DirectionalNavigation="Contained"/>
</ScrollViewer>
</Border>
</Microsoft_Windows_Themes:SystemDropShadowChrome>
</Popup>
<ToggleButton Style="{StaticResource ComboBoxReadonlyToggleButton}" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" Grid.ColumnSpan="2" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"/>
<!-- Content of ComboBox face -->
<ContentPresenter
HorizontalAlignment="Left"
Margin="0"
VerticalAlignment="Center"
IsHitTestVisible="false"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}"
Content=" "
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasDropShadow" SourceName="PART_Popup" Value="true">
<Setter Property="Margin" TargetName="Shdw" Value="0,0,5,5"/>
<Setter Property="Color" TargetName="Shdw" Value="#71000000"/>
</Trigger>
<Trigger Property="HasItems" Value="false">
<Setter Property="Height" TargetName="DropDownBorder" Value="95"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
<Setter Property="Background" Value="#FFF4F4F4"/>
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEditable" Value="true">
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>

BIN
src/AddIns/Debugger/Debugger.AddIn/Tooltips/magnifier.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

2
src/AddIns/Debugger/Debugger.AddIn/TreeModel/Adapters/TreeViewVarNode.cs

@ -10,7 +10,7 @@ using System.Windows.Forms; @@ -10,7 +10,7 @@ using System.Windows.Forms;
using Aga.Controls.Tree;
using Aga.Controls.Tree.NodeControls;
using ICSharpCode.Core;
using TreeNode = ICSharpCode.SharpDevelop.Debugging.TreeNode;
using TreeNode = Debugger.AddIn.TreeModel.TreeNode;
namespace Debugger.AddIn.TreeModel
{

6
src/AddIns/Debugger/Debugger.AddIn/TreeModel/ArrayRangeNode.cs

@ -85,7 +85,11 @@ namespace Debugger.AddIn.TreeModel @@ -85,7 +85,11 @@ namespace Debugger.AddIn.TreeModel
// The whole array is small - just add all elements as childs
if (bounds.TotalElementCount <= MaxElementCount) {
foreach(int[] indices in bounds.Indices) {
yield return new ExpressionNode(ExpressionNode.GetImageForArrayIndexer(), GetName(indices), arrayTarget.AppendIndexer(indices));
string imageName;
var image = ExpressionNode.GetImageForArrayIndexer(out imageName);
var expression = new ExpressionNode(image, GetName(indices), arrayTarget.AppendIndexer(indices));
expression.ImageName = imageName;
yield return expression;
}
yield break;
}

12
src/AddIns/Debugger/Debugger.AddIn/TreeModel/ChildNodesOfObject.cs

@ -85,7 +85,11 @@ namespace Debugger.AddIn.TreeModel @@ -85,7 +85,11 @@ namespace Debugger.AddIn.TreeModel
{
List<TreeNode> nodes = new List<TreeNode>();
foreach(MemberInfo memberInfo in members) {
nodes.Add(new ExpressionNode(ExpressionNode.GetImageForMember((IDebugMemberInfo)memberInfo), memberInfo.Name, expression.AppendMemberReference((IDebugMemberInfo)memberInfo)));
string imageName;
var image = ExpressionNode.GetImageForMember((IDebugMemberInfo)memberInfo, out imageName);
var exp = new ExpressionNode(image, memberInfo.Name, expression.AppendMemberReference((IDebugMemberInfo)memberInfo));
exp.ImageName = imageName;
nodes.Add(exp);
}
nodes.Sort();
return nodes;
@ -114,7 +118,11 @@ namespace Debugger.AddIn.TreeModel @@ -114,7 +118,11 @@ namespace Debugger.AddIn.TreeModel
yield return new TreeNode(null, "(empty)", null, null, null);
} else {
for(int i = 0; i < count; i++) {
yield return new ExpressionNode(ExpressionNode.GetImageForArrayIndexer(), "[" + i + "]", targetObject.AppendIndexer(i));
string imageName;
var image = ExpressionNode.GetImageForArrayIndexer(out imageName);
var expression = new ExpressionNode(image, "[" + i + "]", targetObject.AppendIndexer(i));
expression.ImageName = imageName;
yield return expression;
}
}
}

126
src/AddIns/Debugger/Debugger.AddIn/TreeModel/ExpressionNode.cs

@ -16,7 +16,7 @@ using ICSharpCode.NRefactory.Ast; @@ -16,7 +16,7 @@ using ICSharpCode.NRefactory.Ast;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Services;
using TreeNode = ICSharpCode.SharpDevelop.Debugging.TreeNode;
using TreeNode = Debugger.AddIn.TreeModel.TreeNode;
namespace Debugger.AddIn.TreeModel
{
@ -34,7 +34,7 @@ namespace Debugger.AddIn.TreeModel @@ -34,7 +34,7 @@ namespace Debugger.AddIn.TreeModel
string fullName;
string fullText;
public bool Evaluated {
public bool Evaluated {
get { return evaluated; }
set { evaluated = value; }
}
@ -57,7 +57,7 @@ namespace Debugger.AddIn.TreeModel @@ -57,7 +57,7 @@ namespace Debugger.AddIn.TreeModel
}
}
public string FullText {
public string FullText {
get { return fullText; }
}
@ -74,18 +74,35 @@ namespace Debugger.AddIn.TreeModel @@ -74,18 +74,35 @@ namespace Debugger.AddIn.TreeModel
}
}
public override string FullName {
public override string FullName {
get {
if (!evaluated) EvaluateExpression();
if(!string.IsNullOrEmpty(fullName))
return fullName;
return GetFullName() ?? Name.Trim();
}
}
private string GetFullName()
{
// TODO : do this better
if (expression is MemberReferenceExpression) {
var memberExpression = (MemberReferenceExpression)expression;
Expression currentExpression = memberExpression;
Stack<string> stack = new Stack<string>();
while (currentExpression is MemberReferenceExpression)
{
var exp = (MemberReferenceExpression)currentExpression;
stack.Push(exp.MemberName);
stack.Push(".");
currentExpression = exp.TargetObject;
}
if (expression is MemberReferenceExpression) {
var memberExpression = (MemberReferenceExpression)expression;
if (currentExpression is CastExpression) {
var castExpression = (CastExpression)currentExpression;
currentExpression = castExpression.Expression;
Expression currentExpression = memberExpression;
Stack<string> stack = new Stack<string>();
while (currentExpression is MemberReferenceExpression)
{
var exp = (MemberReferenceExpression)currentExpression;
@ -94,42 +111,27 @@ namespace Debugger.AddIn.TreeModel @@ -94,42 +111,27 @@ namespace Debugger.AddIn.TreeModel
currentExpression = exp.TargetObject;
}
if (currentExpression is CastExpression) {
var castExpression = (CastExpression)currentExpression;
currentExpression = castExpression.Expression;
if (currentExpression is IdentifierExpression) {
var identifierExpression = (IdentifierExpression)castExpression.Expression;
stack.Push(identifierExpression.Identifier);
}
while (currentExpression is MemberReferenceExpression)
{
var exp = (MemberReferenceExpression)currentExpression;
stack.Push(exp.MemberName);
stack.Push(".");
currentExpression = exp.TargetObject;
}
}
if (currentExpression is ThisReferenceExpression) {
stack.Push("this");
}
// create fullname
StringBuilder sb = new StringBuilder();
while(stack.Count > 0)
sb.Append(stack.Pop());
fullName = sb.ToString();
return fullName;
}
fullName = Name.Trim();
if (currentExpression is IdentifierExpression) {
var identifierExpression = (IdentifierExpression)currentExpression;
stack.Push(identifierExpression.Identifier);
}
if (currentExpression is ThisReferenceExpression) {
stack.Push("this");
}
// create fullname
StringBuilder sb = new StringBuilder();
while(stack.Count > 0)
sb.Append(stack.Pop());
fullName = sb.ToString();
return fullName;
}
return null;
}
public override string Type {
@ -151,7 +153,7 @@ namespace Debugger.AddIn.TreeModel @@ -151,7 +153,7 @@ namespace Debugger.AddIn.TreeModel
if (!evaluated) EvaluateExpression();
return base.HasChildNodes;
}
}
}
/// <summary> Used to determine available VisualizerCommands </summary>
private DebugType expressionType;
@ -282,7 +284,7 @@ namespace Debugger.AddIn.TreeModel @@ -282,7 +284,7 @@ namespace Debugger.AddIn.TreeModel
.Replace("\a", "\\a")
.Replace("\f", "\\f")
.Replace("\v", "\\v")
.Replace("\"", "\\\"");
.Replace("\"", "\\\"");
}
string FormatInteger(object i)
@ -373,27 +375,31 @@ namespace Debugger.AddIn.TreeModel @@ -373,27 +375,31 @@ namespace Debugger.AddIn.TreeModel
return false;
}
public static IImage GetImageForThis()
public static IImage GetImageForThis(out string imageName)
{
return DebuggerResourceService.GetImage("Icons.16x16.Parameter");
imageName = "Icons.16x16.Parameter";
return DebuggerResourceService.GetImage(imageName);
}
public static IImage GetImageForParameter()
public static IImage GetImageForParameter(out string imageName)
{
return DebuggerResourceService.GetImage("Icons.16x16.Parameter");
imageName = "Icons.16x16.Parameter";
return DebuggerResourceService.GetImage(imageName);
}
public static IImage GetImageForLocalVariable()
public static IImage GetImageForLocalVariable(out string imageName)
{
return DebuggerResourceService.GetImage("Icons.16x16.Local");
imageName = "Icons.16x16.Local";
return DebuggerResourceService.GetImage(imageName);
}
public static IImage GetImageForArrayIndexer()
public static IImage GetImageForArrayIndexer(out string imageName)
{
return DebuggerResourceService.GetImage("Icons.16x16.Field");
imageName = "Icons.16x16.Field";
return DebuggerResourceService.GetImage(imageName);
}
public static IImage GetImageForMember(IDebugMemberInfo memberInfo)
public static IImage GetImageForMember(IDebugMemberInfo memberInfo, out string imageName)
{
string name = string.Empty;
if (memberInfo.IsPublic) {
@ -413,15 +419,17 @@ namespace Debugger.AddIn.TreeModel @@ -413,15 +419,17 @@ namespace Debugger.AddIn.TreeModel
} else {
throw new DebuggerException("Unknown member type " + memberInfo.GetType().FullName);
}
return DebuggerResourceService.GetImage("Icons.16x16." + name);
imageName = "Icons.16x16." + name;
return DebuggerResourceService.GetImage(imageName);
}
// public ContextMenuStrip GetContextMenu()
// {
// if (this.Error != null) return GetErrorContextMenu();
//
//
// ContextMenuStrip menu = new ContextMenuStrip();
//
//
// ToolStripMenuItem copyItem;
// copyItem = new ToolStripMenuItem();
// copyItem.Text = ResourceService.GetString("MainWindow.Windows.Debug.LocalVariables.CopyToClipboard");
@ -429,7 +437,7 @@ namespace Debugger.AddIn.TreeModel @@ -429,7 +437,7 @@ namespace Debugger.AddIn.TreeModel
// copyItem.Click += delegate {
// ClipboardWrapper.SetText(fullText);
// };
// ToolStripMenuItem hexView;
// hexView = new ToolStripMenuItem();
// hexView.Text = ResourceService.GetString("MainWindow.Windows.Debug.LocalVariables.ShowInHexadecimal");
@ -443,12 +451,12 @@ namespace Debugger.AddIn.TreeModel @@ -443,12 +451,12 @@ namespace Debugger.AddIn.TreeModel
// if (WatchPad.Instance != null)
// WatchPad.Instance.RefreshPad();
// };
// menu.Items.AddRange(new ToolStripItem[] {
// copyItem,
// //hexView
// });
//
//
// return menu;
// }

30
src/AddIns/Debugger/Debugger.AddIn/TreeModel/SavedTreeNode.cs

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
// 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 ICSharpCode.SharpDevelop;
namespace Debugger.AddIn.TreeModel
{
/// <summary>
/// Description of SavedTreeNode.
/// </summary>
public class SavedTreeNode : TreeNode
{
public override bool CanSetText {
get { return true; }
}
public SavedTreeNode(IImage image, string fullname, string text)
{
base.IconImage = image;
FullName = fullname;
Text = text;
}
public override bool SetText(string newValue) {
Text = newValue;
return false;
}
}
}

12
src/AddIns/Debugger/Debugger.AddIn/TreeModel/StackFrameNode.cs

@ -27,10 +27,18 @@ namespace Debugger.AddIn.TreeModel @@ -27,10 +27,18 @@ namespace Debugger.AddIn.TreeModel
IEnumerable<TreeNode> LazyGetChildNodes()
{
foreach(DebugParameterInfo par in stackFrame.MethodInfo.GetParameters()) {
yield return new ExpressionNode(ExpressionNode.GetImageForParameter(), par.Name, par.GetExpression());
string imageName;
var image = ExpressionNode.GetImageForParameter(out imageName);
var expression = new ExpressionNode(image, par.Name, par.GetExpression());
expression.ImageName = imageName;
yield return expression;
}
foreach(DebugLocalVariableInfo locVar in stackFrame.MethodInfo.GetLocalVariables(this.StackFrame.IP)) {
yield return new ExpressionNode(ExpressionNode.GetImageForLocalVariable(), locVar.Name, locVar.GetExpression());
string imageName;
var image = ExpressionNode.GetImageForLocalVariable(out imageName);
var expression = new ExpressionNode(image, locVar.Name, locVar.GetExpression());
expression.ImageName = imageName;
yield return expression;
}
if (stackFrame.Thread.CurrentException != null) {
yield return new ExpressionNode(null, "__exception", new IdentifierExpression("__exception"));

21
src/AddIns/Debugger/Debugger.AddIn/TreeModel/TreeNode.cs

@ -17,10 +17,11 @@ namespace Debugger.AddIn.TreeModel @@ -17,10 +17,11 @@ namespace Debugger.AddIn.TreeModel
/// A node in the variable tree.
/// The node is imutable.
/// </summary>
public class TreeNode: IComparable<TreeNode>, ITreeNode
public class TreeNode : ITreeNode
{
IImage iconImage = null;
string name = string.Empty;
string imageName = string.Empty;
string text = string.Empty;
string type = string.Empty;
IEnumerable<TreeNode> childNodes = null;
@ -56,6 +57,16 @@ namespace Debugger.AddIn.TreeModel @@ -56,6 +57,16 @@ namespace Debugger.AddIn.TreeModel
set { name = value; }
}
public string ImageName {
get { return imageName; }
set { imageName = value; }
}
public virtual string FullName {
get { return name; }
set { name = value; }
}
public virtual string Text
{
get { return text; }
@ -96,6 +107,8 @@ namespace Debugger.AddIn.TreeModel @@ -96,6 +107,8 @@ namespace Debugger.AddIn.TreeModel
}
}
public bool IsPinned { get; set; }
public TreeNode()
{
}
@ -109,13 +122,13 @@ namespace Debugger.AddIn.TreeModel @@ -109,13 +122,13 @@ namespace Debugger.AddIn.TreeModel
this.childNodes = childNodes;
}
public int CompareTo(TreeNode other)
public int CompareTo(ITreeNode other)
{
return this.Name.CompareTo(other.Name);
return this.FullName.CompareTo(other.FullName);
}
public virtual bool SetText(string newValue) {
return false;
}
}
}
}

7
src/Main/Base/Project/ICSharpCode.SharpDevelop.addin

@ -61,13 +61,6 @@ @@ -61,13 +61,6 @@
class = "ICSharpCode.SharpDevelop.BrowserDisplayBinding.BrowserDisplayBinding"/>
</Path>
<Path name="/SharpDevelop/Workbench/LanguageBindings">
<LanguageBinding
id="Pin"
class="Services.Debugger.Tooltips.PinningBinding"
extensions="" />
</Path>
<Path name = "/SharpDevelop/Workbench/FileFilter">
<FileFilter id = "AllFiles"
name = "${res:SharpDevelop.FileFilter.AllFiles}"

28
src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj

@ -103,7 +103,6 @@ @@ -103,7 +103,6 @@
<Compile Include="Src\Editor\AvalonEdit\AvalonEditTextSourceAdapter.cs" />
<Compile Include="Src\Editor\AvalonEdit\IndentationStrategyAdapter.cs" />
<Compile Include="Src\Editor\AvalonEdit\ISnippetElementProvider.cs" />
<Compile Include="Src\Editor\AvalonEdit\PinLayer.cs" />
<Compile Include="Src\Editor\AvalonEdit\TextContentCondition.cs" />
<Compile Include="Src\Editor\AvalonEdit\TextSelectedCondition.cs" />
<Compile Include="Src\Editor\CodeCompletion\CodeCompletionPanel.cs">
@ -313,26 +312,10 @@ @@ -313,26 +312,10 @@
<Compile Include="Src\Project\TargetFramework.cs" />
<Compile Include="Src\Services\Debugger\BreakpointBookmark.cs" />
<Compile Include="Src\Services\Debugger\BreakpointBookmarkEventArgs.cs" />
<Compile Include="Src\Services\Debugger\Tooltips\DebuggerPopup.cs" />
<Compile Include="Src\Services\Debugger\Tooltips\DebuggerTooltipControl.xaml.cs">
<DependentUpon>DebuggerTooltipControl.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Src\Services\Debugger\Tooltips\IPinDebuggerControl.cs" />
<Compile Include="Src\Services\Debugger\Tooltips\ITreeNode.cs" />
<Compile Include="Src\Services\Debugger\Tooltips\IVisualizerCommand.cs" />
<Compile Include="Src\Services\Debugger\Tooltips\LazyItemsControl.cs" />
<Compile Include="Src\Services\Debugger\Tooltips\PinBookmark.cs" />
<Compile Include="Src\Services\Debugger\Tooltips\PinCloseControl.xaml.cs">
<DependentUpon>PinCloseControl.xaml</DependentUpon>
</Compile>
<Compile Include="Src\Services\Debugger\Tooltips\PinDebuggerControl.xaml.cs">
<DependentUpon>PinDebuggerControl.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Src\Services\Debugger\Tooltips\PinningBinding.cs" />
<Compile Include="Src\Services\Debugger\Tooltips\VirtualizingIEnumerable.cs" />
<Compile Include="Src\Services\Debugger\Tooltips\VisualizerPicker.cs" />
<Compile Include="Src\Services\Debugger\TreeNode.cs" />
<Compile Include="Src\Services\DisplayBinding\ExternalProcessDisplayBinding.cs" />
<Compile Include="Src\Services\DisplayBinding\ISecondaryDisplayBinding.cs" />
<Compile Include="Src\Services\DisplayBinding\ShellExecuteDisplayBinding.cs" />
@ -396,9 +379,6 @@ @@ -396,9 +379,6 @@
<Compile Include="Src\Services\ProjectBinding\ProjectBindingService.cs" />
<Resource Include="Src\Services\RefactoringService\ContextActions\bulb.png" />
<Resource Include="Src\Services\RefactoringService\ContextActions\pencil.png" />
<Resource Include="Src\Services\Debugger\Tooltips\magnifier.png">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</Resource>
<Compile Include="Src\Services\DisplayBinding\DisplayBindingDoozer.cs" />
<Compile Include="Src\Internal\ConditionEvaluators\CombineOpenEvaluator.cs" />
<Compile Include="Src\Services\ProjectBinding\ProjectBindingDoozer.cs" />
@ -832,9 +812,6 @@ @@ -832,9 +812,6 @@
</ItemGroup>
<ItemGroup>
<Page Include="Src\Bookmarks\Pad\Controls\ListViewPad.xaml" />
<Page Include="Src\Services\Debugger\Tooltips\PinCloseControl.xaml" />
<Page Include="Src\Services\Debugger\Tooltips\PinControlsDictionary.xaml" />
<Page Include="Src\Services\Debugger\Tooltips\PinDebuggerControl.xaml" />
<Page Include="Src\Services\RefactoringService\ContextActions\ContextActionsBulbControl.xaml" />
<Page Include="Src\Services\RefactoringService\ContextActions\ContextActionsControl.xaml" />
<Page Include="Src\Services\RefactoringService\ContextActions\ContextActionsHeaderedControl.xaml" />
@ -864,6 +841,7 @@ @@ -864,6 +841,7 @@
<Folder Include="Src\Editor\Commands" />
<Folder Include="Src\Editor\Search" />
<Folder Include="Src\Gui\Pads\TaskList" />
<Folder Include="Src\Services\Debugger\Tooltips" />
<Folder Include="Src\Services\RefactoringService\ContextActions" />
<Folder Include="Src\Util" />
<Folder Include="Src\Gui\Pads\ClassBrowser\NodeBuilder" />
@ -901,8 +879,6 @@ @@ -901,8 +879,6 @@
<Page Include="Src\Gui\Dialogs\TreeViewOptionsDialog.xaml" />
<Page Include="Src\Gui\Workbench\WpfWorkbench.xaml" />
<Page Include="Src\Project\Converter\UpgradeView.xaml" />
<Page Include="Src\Services\Debugger\Tooltips\DebuggerTooltipControl.xaml" />
<Page Include="Src\Services\Debugger\Tooltips\VisualizerPicker.xaml" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<Import Project="PostBuildEvent.proj" />

2
src/Main/Base/Project/Src/Bookmarks/BookmarkConverter.cs

@ -127,7 +127,7 @@ namespace ICSharpCode.SharpDevelop.Bookmarks @@ -127,7 +127,7 @@ namespace ICSharpCode.SharpDevelop.Bookmarks
//popup nodes
foreach(var node in pin.Nodes) {
b.Append('|');
b.Append(""); // image
b.Append(node.ImageName);
b.Append('|');
b.Append(node.FullName);
b.Append('|');

2
src/Main/Base/Project/Src/Services/Debugger/Tooltips/DebuggerPopup.cs

@ -63,7 +63,7 @@ namespace ICSharpCode.SharpDevelop.Debugging @@ -63,7 +63,7 @@ namespace ICSharpCode.SharpDevelop.Debugging
public IEnumerable<ITreeNode> ItemsSource
{
get { return this.contentControl.ItemsSource; }
set { this.contentControl.ItemsSource = value; }
set { this.contentControl.SetItemsSource(value); }
}
private bool isLeaf;

67
src/Main/Base/Project/Src/Services/Debugger/Tooltips/DebuggerTooltipControl.xaml.cs

@ -52,7 +52,7 @@ namespace ICSharpCode.SharpDevelop.Debugging @@ -52,7 +52,7 @@ namespace ICSharpCode.SharpDevelop.Debugging
public DebuggerTooltipControl(IEnumerable<ITreeNode> nodes)
: this()
{
this.ItemsSource = nodes;
this.itemsSource = nodes;
}
public DebuggerTooltipControl(DebuggerTooltipControl parentControl, bool showPins = true)
@ -67,6 +67,8 @@ namespace ICSharpCode.SharpDevelop.Debugging @@ -67,6 +67,8 @@ namespace ICSharpCode.SharpDevelop.Debugging
if (!showPins) {
dataGrid.Columns[5].Visibility = Visibility.Collapsed;
}
SetItemsSource(this.itemsSource);
}
public event RoutedEventHandler Closed;
@ -79,40 +81,41 @@ namespace ICSharpCode.SharpDevelop.Debugging @@ -79,40 +81,41 @@ namespace ICSharpCode.SharpDevelop.Debugging
public IEnumerable<ITreeNode> ItemsSource {
get { return this.itemsSource; }
set{
this.itemsSource = value;
this.lazyGrid = new LazyItemsControl<ITreeNode>(this.dataGrid, InitialItemsCount);
// HACK for updating the pinns in tooltip
var observable = new List<ITreeNode>();
this.itemsSource.ForEach(item => observable.Add(item));
}
public void SetItemsSource(IEnumerable<ITreeNode> value) {
this.itemsSource = value;
this.lazyGrid = new LazyItemsControl<ITreeNode>(this.dataGrid, InitialItemsCount);
// HACK for updating the pins in tooltip
var observable = new List<ITreeNode>();
this.itemsSource.ForEach(item => observable.Add(item));
// verify if at the line of the root there's a pin bookmark
ITextEditorProvider provider = WorkbenchSingleton.Workbench.ActiveViewContent as ITextEditorProvider;
var editor = provider.TextEditor;
if (editor != null) {
var pin = BookmarkManager.Bookmarks.Find(
b => b is PinBookmark &&
b.Location.Line == LogicalPosition.Line &&
b.FileName == editor.FileName) as PinBookmark;
// verify if at the line of the root there's a pin bookmark
ITextEditorProvider provider = WorkbenchSingleton.Workbench.ActiveViewContent as ITextEditorProvider;
var editor = provider.TextEditor;
if (editor != null) {
var pin = BookmarkManager.Bookmarks.Find(
b => b is PinBookmark &&
b.Location.Line == LogicalPosition.Line &&
b.FileName == editor.FileName) as PinBookmark;
if (pin != null) {
observable.ForEach(item => { // TODO: find a way not to use "observable"
if (pin.ContainsNode(item))
item.IsPinned = true;
});
}
if (pin != null) {
observable.ForEach(item => { // TODO: find a way not to use "observable"
if (pin.ContainsNode(item))
item.IsPinned = true;
});
}
var source = new VirtualizingIEnumerable<ITreeNode>(observable);
lazyGrid.ItemsSource = source;
this.dataGrid.AddHandler(ScrollViewer.ScrollChangedEvent, new ScrollChangedEventHandler(handleScroll));
}
var source = new VirtualizingIEnumerable<ITreeNode>(observable);
lazyGrid.ItemsSource = source;
this.dataGrid.AddHandler(ScrollViewer.ScrollChangedEvent, new ScrollChangedEventHandler(handleScroll));
if (this.lazyGrid.ItemsSourceTotalCount != null) {
// hide up/down buttons if too few items
btnUp.Visibility = btnDown.Visibility =
this.lazyGrid.ItemsSourceTotalCount.Value <= VisibleItemsCount ? Visibility.Collapsed : Visibility.Visible;
}
if (this.lazyGrid.ItemsSourceTotalCount != null) {
// hide up/down buttons if too few items
btnUp.Visibility = btnDown.Visibility =
this.lazyGrid.ItemsSourceTotalCount.Value <= VisibleItemsCount ? Visibility.Collapsed : Visibility.Visible;
}
}

20
src/Main/Base/Project/Src/Services/Debugger/Tooltips/IPinDebuggerControl.cs

@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
// 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.Windows;
using ICSharpCode.SharpDevelop.Debugging;
namespace Services.Debugger.Tooltips
{
public interface IPinDebuggerControl
{
void Open();
void Close();
PinBookmark Mark { get; set; }
IEnumerable<ITreeNode> ItemsSource { set; }
Point Location { get; set; }
}
}

4
src/Main/Base/Project/Src/Services/Debugger/Tooltips/ITreeNode.cs

@ -10,12 +10,14 @@ namespace ICSharpCode.SharpDevelop.Debugging @@ -10,12 +10,14 @@ namespace ICSharpCode.SharpDevelop.Debugging
/// <summary>
/// Node that can be bound to <see cref="DebuggerTooltipControl" />.
/// </summary>
public interface ITreeNode
public interface ITreeNode : IComparable<ITreeNode>
{
string Name { get; }
string FullName { get; }
string ImageName { get; }
string Text { get; }
bool CanSetText { get; }

8
src/Main/Base/Project/Src/Services/Debugger/Tooltips/PinBookmark.cs

@ -19,7 +19,7 @@ namespace Services.Debugger.Tooltips @@ -19,7 +19,7 @@ namespace Services.Debugger.Tooltips
{
string tooltip;
public PinDebuggerControl Popup { get; set; }
public IPinDebuggerControl Popup { get; set; }
public static readonly IImage PinImage = new ResourceServiceImage("Bookmarks.Pin");
@ -56,7 +56,7 @@ namespace Services.Debugger.Tooltips @@ -56,7 +56,7 @@ namespace Services.Debugger.Tooltips
get { return tooltip; }
set { tooltip = value; }
}
public override bool CanDragDrop {
get { return true; }
}
@ -77,7 +77,7 @@ namespace Services.Debugger.Tooltips @@ -77,7 +77,7 @@ namespace Services.Debugger.Tooltips
throw new ArgumentNullException("Node is null");
foreach (var currentNode in mark.Nodes) {
if (node.FullName.Trim() == currentNode.FullName.Trim())
if (node.FullName == currentNode.FullName)
return true;
}
@ -92,7 +92,7 @@ namespace Services.Debugger.Tooltips @@ -92,7 +92,7 @@ namespace Services.Debugger.Tooltips
throw new ArgumentNullException("Node is null");
foreach (var currentNode in mark.Nodes) {
if (node.FullName.Trim() == currentNode.FullName.Trim()) {
if (node.FullName == currentNode.FullName) {
mark.Nodes.Remove(currentNode);
return;
}

37
src/Main/Base/Project/Src/Services/Debugger/Tooltips/PinDebuggerControl.xaml

@ -39,6 +39,7 @@ @@ -39,6 +39,7 @@
<Setter
Property="BorderThickness"
Value="0" />
<Setter Property="Width" Value="Auto" />
<Style.Triggers>
<Trigger
Property="IsSelected"
@ -88,7 +89,7 @@ @@ -88,7 +89,7 @@
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel>
<StackPanel VerticalAlignment="Center">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
@ -113,7 +114,8 @@ @@ -113,7 +114,8 @@
<ToggleButton
x:Name="btnExpander"
Style="{StaticResource ExpandCollapseToggleStyle}"
Click="btnExpander_Click"
Checked="BtnExpander_Checked"
Unchecked="BtnExpander_Unchecked"
Padding="0"
Margin="0" />
</StackPanel>
@ -138,8 +140,10 @@ @@ -138,8 +140,10 @@
BorderThickness="0,1,0,1"
Grid.Column="1"
IsEnabled="False"
ColumnWidth="SizeToCells"
Style="{StaticResource DataGridStyle}"
ItemsSource="{Binding}"
Foreground="Black"
Name="dataGrid">
<DataGrid.Columns>
<DataGridTemplateColumn>
@ -168,7 +172,7 @@ @@ -168,7 +172,7 @@
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn IsReadOnly="True"
MinWidth="20"
Width="SizeToCells"
Header="Text">
<!-- Text (value) -->
<DataGridTemplateColumn.CellTemplate>
@ -194,12 +198,27 @@ @@ -194,12 +198,27 @@
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Width="12" Height="12"
VerticalAlignment="Center"
x:Name="RefreshContentImage"
MouseDown="RefreshContentImage_MouseDown"
Tag="{Binding}"
Source="{core:GetBitmap Icons.16x16.Refresh}"/>
<Border
Name="ImageBorder"
CornerRadius="7"
BorderBrush="Transparent"
BorderThickness="1"
Height="14"
Width="14">
<Image Width="9" Height="9" Margin="2 2"
x:Name="RefreshContentImage"
MouseDown="RefreshContentImage_MouseDown"
Tag="{Binding}"
Source="{core:GetBitmap Icons.16x16.Refresh}"/>
</Border>
<DataTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter
TargetName="ImageBorder"
Property="BorderBrush"
Value="Gray" />
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

252
src/Main/Base/Project/Src/Services/Debugger/Tooltips/PinDebuggerControl.xaml.cs

@ -3,15 +3,14 @@ @@ -3,15 +3,14 @@
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Debugger;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Bookmarks;
using ICSharpCode.SharpDevelop.Debugging;
@ -20,74 +19,101 @@ using ICSharpCode.SharpDevelop.Gui; @@ -20,74 +19,101 @@ using ICSharpCode.SharpDevelop.Gui;
namespace Services.Debugger.Tooltips
{
public partial class PinDebuggerControl : UserControl
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 const double MINIMUM_OPACITY = 0.3;
private DebuggerPopup childPopup;
private LazyItemsControl<ITreeNode> lazyExpandersGrid;
private LazyItemsControl<ITreeNode> lazyGrid;
private LazyItemsControl<ITreeNode> lazyImagesGrid;
private IEnumerable<ITreeNode> itemsSource;
public PinDebuggerControl()
{
InitializeComponent();
if (!DebuggerService.IsDebuggerRunning)
Opacity = MINIMUM_OPACITY;
PinCloseControl.Opacity = 0;
Loaded += OnLoaded;
this.PinCloseControl.Closed += PinCloseControl_Closed;
this.PinCloseControl.ShowingComment += PinCloseControl_ShowingComment;
this.PinCloseControl.PinningChanged += PinCloseControl_PinningChanged;
BookmarkManager.Removed += BookmarkManager_Removed;
DebuggerService.DebugStarted += delegate { Opacity = 1d; };
if (DebuggerService.DebuggedProcess != null)
DebuggerService.DebuggedProcess.Paused += DebuggerService_CurrentDebugger_DebuggedProcess_Paused;
DebuggerService.ProcessSelected += delegate {
Opacity = 1.0;
DebuggerService.DebuggedProcess.Paused += DebuggerService_CurrentDebugger_DebuggedProcess_Paused;
};
}
#region Properties
public PinBookmark Mark { get; set; }
private LazyItemsControl<ITreeNode> lazyExpandersGrid;
private LazyItemsControl<ITreeNode> lazyGrid;
private LazyItemsControl<ITreeNode> lazyImagesGrid;
private IEnumerable<ITreeNode> itemsSource;
public IEnumerable<ITreeNode> ItemsSource
{
set
{
public IEnumerable<ITreeNode> 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()
{
Unpin();
}
void Pin()
{
var provider = WorkbenchSingleton.Workbench.ActiveContent as ITextEditorProvider;
if (provider != null) {
PinningBinding.GetPinlayer(provider.TextEditor).Pin(this);
}
}
void Unpin()
{
var provider = WorkbenchSingleton.Workbench.ActiveContent as ITextEditorProvider;
if (provider != null) {
PinningBinding.GetPinlayer(provider.TextEditor).Unpin(this);
}
}
#endregion
#region Expand buton
private ToggleButton expandedButton;
/// <summary>
@ -96,14 +122,13 @@ namespace Services.Debugger.Tooltips @@ -96,14 +122,13 @@ namespace Services.Debugger.Tooltips
void CloseChildPopups()
{
if (this.expandedButton != null) {
this.expandedButton.IsChecked = false;
this.expandedButton = null;
// nice simple example of indirect recursion
this.childPopup.CloseSelfAndChildren();
}
}
void btnExpander_Click(object sender, RoutedEventArgs e)
void BtnExpander_Checked(object sender, RoutedEventArgs e)
{
var clickedButton = (ToggleButton)e.OriginalSource;
var clickedNode = (ITreeNode)clickedButton.DataContext;
@ -111,57 +136,90 @@ namespace Services.Debugger.Tooltips @@ -111,57 +136,90 @@ namespace Services.Debugger.Tooltips
Point buttonPos = clickedButton.PointToScreen(new Point(0, 0)).TransformFromDevice(clickedButton);
if (clickedButton.IsChecked.GetValueOrDefault(false)) {
CloseChildPopups();
this.expandedButton = clickedButton;
// open child Popup
if (this.childPopup == null) {
this.childPopup = new DebuggerPopup(null, 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;
this.childPopup.ItemsSource = clickedNode.ChildNodes;
this.childPopup.Open();
} else {
CloseChildPopups();
}
}
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);
CloseChildPopups();
Unpin();
}
void PinCloseControl_PinningChanged(object sender, EventArgs e)
{
if (this.PinCloseControl.IsChecked) {
BookmarkManager.RemoveMark(Mark);
}
else {
if(BookmarkManager.Bookmarks.Contains(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 BookmarkManager_Removed(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) {
@ -174,105 +232,107 @@ namespace Services.Debugger.Tooltips @@ -174,105 +232,107 @@ namespace Services.Debugger.Tooltips
{
this.CommentTextBox.Text = Mark.Comment;
}
void Pin()
{
var provider = WorkbenchSingleton.Workbench.ActiveContent as ITextEditorProvider;
if(provider != null) {
PinningBinding.GetPinlayer(provider.TextEditor).Pin(this);
}
}
void Unpin()
{
var provider = WorkbenchSingleton.Workbench.ActiveContent as ITextEditorProvider;
if(provider != null) {
PinningBinding.GetPinlayer(provider.TextEditor).Unpin(this);
}
}
#region Comment
void ShowComment(bool show)
{
if(show && BorderComment.Height != 0)
if (show && BorderComment.Height != 0)
return;
if(!show && BorderComment.Height != 40)
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
void AnimateCloseControls(bool show)
void DebuggerService_CurrentDebugger_DebuggedProcess_Paused(object sender, ProcessEventArgs e)
{
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);
var observable = new List<ITreeNode>();
foreach (var node in lazyGrid.ItemsSource) {
var resultNode = DebuggerService.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;
}
void RefreshContentImage_MouseDown(object sender, MouseButtonEventArgs e)
{
// refresh content
// refresh content
ITreeNode node = ((Image)sender).DataContext as ITreeNode;
if (!DebuggerService.IsDebuggerRunning)
return;
var resultNode = DebuggerService.CurrentDebugger.GetNode(node.FullName);
// HACK for updating the pins in tooltip
var observable = new List<ITreeNode>();
var source = lazyGrid.ItemsSource;
source.ForEach(item =>
{
if (item.CompareTo(node) == 0)
observable.Add(resultNode);
else
observable.Add(item);
});
// update UI
var newSource = new VirtualizingIEnumerable<ITreeNode>(observable);
lazyGrid.ItemsSource = newSource;
lazyExpandersGrid.ItemsSource = newSource;
}
#region Overrides
protected override void OnMouseEnter(System.Windows.Input.MouseEventArgs e)
{
AnimateCloseControls(true);
Opacity = 1d;
AnimateCloseControl(true);
Opacity = 1.0;
Cursor = Cursors.Arrow;
base.OnMouseEnter(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
Opacity = 1d;
Opacity = 1.0;
Cursor = Cursors.Arrow;
base.OnMouseMove(e);
}
protected override void OnMouseLeave(System.Windows.Input.MouseEventArgs e)
{
if (DebuggerService.IsDebuggerRunning)
if (DebuggerService.IsDebuggerRunning)
Opacity = 1;
else
Opacity = MINIMUM_OPACITY;
AnimateCloseControls(false);
AnimateCloseControl(false);
Cursor = Cursors.IBeam;
base.OnMouseLeave(e);
}
#endregion
}
}
}

BIN
src/Main/StartUp/Project/Resources/BitmapResources.resources

Binary file not shown.
Loading…
Cancel
Save