Browse Source

Add tooltips control

pull/191/merge
Eusebiu Marcu 15 years ago
parent
commit
ea9c68acab
  1. 50
      Debugger/ILSpy.Debugger/AvalonEdit/IToolTip.cs
  2. 15
      Debugger/ILSpy.Debugger/ILSpy.Debugger.csproj
  3. 417
      Debugger/ILSpy.Debugger/Services/ExtensionMethods.cs
  4. 98
      Debugger/ILSpy.Debugger/ToolTips/DebuggerPopup.cs
  5. 230
      Debugger/ILSpy.Debugger/ToolTips/DebuggerTooltipControl.xaml
  6. 403
      Debugger/ILSpy.Debugger/ToolTips/DebuggerTooltipControl.xaml.cs
  7. 113
      Debugger/ILSpy.Debugger/ToolTips/LazyItemsControl.cs
  8. 362
      Debugger/ILSpy.Debugger/ToolTips/PinControlsDictionary.xaml
  9. 53
      Debugger/ILSpy.Debugger/ToolTips/VirtualizingIEnumerable.cs
  10. 47
      Debugger/ILSpy.Debugger/ToolTips/VisualizerPicker.cs
  11. 133
      Debugger/ILSpy.Debugger/ToolTips/VisualizerPicker.xaml
  12. 6
      ILSpy.sln

50
Debugger/ILSpy.Debugger/AvalonEdit/IToolTip.cs

@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows;
namespace ILSpy.Debugger.AvalonEdit
{
/// <summary>
/// Content of text editor tooltip (used as <see cref="ToolTipRequestEventArgs.ContentToShow"/>),
/// specifying whether it should be displayed in a WPF Popup.
/// </summary>
public interface ITooltip
{
/// <summary>
/// If true, this ITooltip will be displayed in a WPF Popup.
/// Otherwise it will be displayed in a WPF Tooltip.
/// WPF Popups are (unlike WPF Tooltips) focusable.
/// </summary>
bool ShowAsPopup { get; }
/// <summary>
/// Closes this tooltip.
/// </summary>
/// <param name="mouseClick">True if close request is raised
/// because of mouse click on some SharpDevelop GUI element.</param>
/// <returns>True if Close succeeded (that is, can close). False otherwise.</returns>
bool Close(bool mouseClick);
/// <summary>
/// Occurs when this tooltip decides to close.
/// </summary>
event RoutedEventHandler Closed;
}
}

15
Debugger/ILSpy.Debugger/ILSpy.Debugger.csproj

@ -34,10 +34,14 @@ @@ -34,10 +34,14 @@
<ItemGroup>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="PresentationFramework.Aero">
<RequiredTargetFramework>3.0</RequiredTargetFramework>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
@ -55,6 +59,7 @@ @@ -55,6 +59,7 @@
<Compile Include="AvalonEdit\Editor\ITextBuffer.cs" />
<Compile Include="AvalonEdit\Editor\TextChangeEventArgs.cs" />
<Compile Include="AvalonEdit\IconBarMargin.cs" />
<Compile Include="AvalonEdit\IToolTip.cs" />
<Compile Include="Bookmarks\BookmarkBase.cs" />
<Compile Include="Bookmarks\BookmarkEventHandler.cs" />
<Compile Include="Bookmarks\BookmarkManager.cs" />
@ -82,10 +87,17 @@ @@ -82,10 +87,17 @@
<Compile Include="Services\Debugger\RemotingConfigurationHelpper.cs" />
<Compile Include="Services\Debugger\TypeResolverExtension.cs" />
<Compile Include="Services\Debugger\WindowsDebugger.cs" />
<Compile Include="Services\ExtensionMethods.cs" />
<Compile Include="Services\ImageService\ImageService.cs" />
<Compile Include="Models\RunningProcess.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Services\ParserService\ParserService.cs" />
<Compile Include="ToolTips\DebuggerPopup.cs" />
<Compile Include="ToolTips\DebuggerTooltipControl.xaml.cs">
<DependentUpon>DebuggerTooltipControl.xaml</DependentUpon>
</Compile>
<Compile Include="ToolTips\LazyItemsControl.cs" />
<Compile Include="ToolTips\VirtualizingIEnumerable.cs" />
<Compile Include="UI\AttachToProcessWindow.xaml.cs">
<DependentUpon>AttachToProcessWindow.xaml</DependentUpon>
<SubType>Code</SubType>
@ -93,8 +105,11 @@ @@ -93,8 +105,11 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Models\TreeModel" />
<Folder Include="ToolTips" />
</ItemGroup>
<ItemGroup>
<Page Include="ToolTips\DebuggerTooltipControl.xaml" />
<Page Include="ToolTips\PinControlsDictionary.xaml" />
<Page Include="UI\AttachToProcessWindow.xaml" />
</ItemGroup>
<ItemGroup>

417
Debugger/ILSpy.Debugger/Services/ExtensionMethods.cs

@ -0,0 +1,417 @@ @@ -0,0 +1,417 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Xml;
using System.Xml.Linq;
namespace ILSpy.Debugger.Services
{
/// <summary>
/// Extension methods used in SharpDevelop.
/// </summary>
public static class ExtensionMethods
{
/// <summary>
/// Raises the event.
/// Does nothing if eventHandler is null.
/// Because the event handler is passed as parameter, it is only fetched from the event field one time.
/// This makes
/// <code>MyEvent.RaiseEvent(x,y);</code>
/// thread-safe
/// whereas
/// <code>if (MyEvent != null) MyEvent(x,y);</code>
/// would not be safe.
/// </summary>
/// <remarks>Using this method is only thread-safe under the Microsoft .NET memory model,
/// not under the less strict memory model in the CLI specification.</remarks>
public static void RaiseEvent(this EventHandler eventHandler, object sender, EventArgs e)
{
if (eventHandler != null) {
eventHandler(sender, e);
}
}
/// <summary>
/// Raises the event.
/// Does nothing if eventHandler is null.
/// Because the event handler is passed as parameter, it is only fetched from the event field one time.
/// This makes
/// <code>MyEvent.RaiseEvent(x,y);</code>
/// thread-safe
/// whereas
/// <code>if (MyEvent != null) MyEvent(x,y);</code>
/// would not be safe.
/// </summary>
public static void RaiseEvent<T>(this EventHandler<T> eventHandler, object sender, T e) where T : EventArgs
{
if (eventHandler != null) {
eventHandler(sender, e);
}
}
/// <summary>
/// Runs an action for all elements in the input.
/// </summary>
public static void ForEach<T>(this IEnumerable<T> input, Action<T> action)
{
if (input == null)
throw new ArgumentNullException("input");
foreach (T element in input) {
action(element);
}
}
/// <summary>
/// Adds all <paramref name="elements"/> to <paramref name="list"/>.
/// </summary>
public static void AddRange<T>(this ICollection<T> list, IEnumerable<T> elements)
{
foreach (T o in elements)
list.Add(o);
}
public static ReadOnlyCollection<T> AsReadOnly<T>(this IList<T> arr)
{
return new ReadOnlyCollection<T>(arr);
}
/// <summary>
/// Converts a recursive data structure into a flat list.
/// </summary>
/// <param name="input">The root elements of the recursive data structure.</param>
/// <param name="recursion">The function that gets the children of an element.</param>
/// <returns>Iterator that enumerates the tree structure in preorder.</returns>
public static IEnumerable<T> Flatten<T>(this IEnumerable<T> input, Func<T, IEnumerable<T>> recursion)
{
Stack<IEnumerator<T>> stack = new Stack<IEnumerator<T>>();
try {
stack.Push(input.GetEnumerator());
while (stack.Count > 0) {
while (stack.Peek().MoveNext()) {
T element = stack.Peek().Current;
yield return element;
IEnumerable<T> children = recursion(element);
if (children != null) {
stack.Push(children.GetEnumerator());
}
}
stack.Pop().Dispose();
}
} finally {
while (stack.Count > 0) {
stack.Pop().Dispose();
}
}
}
/// <summary>
/// Creates an array containing a part of the array (similar to string.Substring).
/// </summary>
public static T[] Splice<T>(this T[] array, int startIndex)
{
if (array == null)
throw new ArgumentNullException("array");
return Splice(array, startIndex, array.Length - startIndex);
}
/// <summary>
/// Creates an array containing a part of the array (similar to string.Substring).
/// </summary>
public static T[] Splice<T>(this T[] array, int startIndex, int length)
{
if (array == null)
throw new ArgumentNullException("array");
if (startIndex < 0 || startIndex > array.Length)
throw new ArgumentOutOfRangeException("startIndex", startIndex, "Value must be between 0 and " + array.Length);
if (length < 0 || length > array.Length - startIndex)
throw new ArgumentOutOfRangeException("length", length, "Value must be between 0 and " + (array.Length - startIndex));
T[] result = new T[length];
Array.Copy(array, startIndex, result, 0, length);
return result;
}
#region System.Drawing <-> WPF conversions
public static System.Drawing.Point ToSystemDrawing(this Point p)
{
return new System.Drawing.Point((int)p.X, (int)p.Y);
}
public static System.Drawing.Size ToSystemDrawing(this Size s)
{
return new System.Drawing.Size((int)s.Width, (int)s.Height);
}
public static System.Drawing.Rectangle ToSystemDrawing(this Rect r)
{
return new System.Drawing.Rectangle(r.TopLeft.ToSystemDrawing(), r.Size.ToSystemDrawing());
}
public static System.Drawing.Color ToSystemDrawing(this System.Windows.Media.Color c)
{
return System.Drawing.Color.FromArgb(c.A, c.R, c.G, c.B);
}
public static Point ToWpf(this System.Drawing.Point p)
{
return new Point(p.X, p.Y);
}
public static Size ToWpf(this System.Drawing.Size s)
{
return new Size(s.Width, s.Height);
}
public static Rect ToWpf(this System.Drawing.Rectangle rect)
{
return new Rect(rect.Location.ToWpf(), rect.Size.ToWpf());
}
public static System.Windows.Media.Color ToWpf(this System.Drawing.Color c)
{
return System.Windows.Media.Color.FromArgb(c.A, c.R, c.G, c.B);
}
#endregion
#region DPI independence
public static Rect TransformToDevice(this Rect rect, Visual visual)
{
Matrix matrix = PresentationSource.FromVisual(visual).CompositionTarget.TransformToDevice;
return Rect.Transform(rect, matrix);
}
public static Rect TransformFromDevice(this Rect rect, Visual visual)
{
Matrix matrix = PresentationSource.FromVisual(visual).CompositionTarget.TransformFromDevice;
return Rect.Transform(rect, matrix);
}
public static Size TransformToDevice(this Size size, Visual visual)
{
Matrix matrix = PresentationSource.FromVisual(visual).CompositionTarget.TransformToDevice;
return new Size(size.Width * matrix.M11, size.Height * matrix.M22);
}
public static Size TransformFromDevice(this Size size, Visual visual)
{
Matrix matrix = PresentationSource.FromVisual(visual).CompositionTarget.TransformFromDevice;
return new Size(size.Width * matrix.M11, size.Height * matrix.M22);
}
public static Point TransformToDevice(this Point point, Visual visual)
{
Matrix matrix = PresentationSource.FromVisual(visual).CompositionTarget.TransformToDevice;
return new Point(point.X * matrix.M11, point.Y * matrix.M22);
}
public static Point TransformFromDevice(this Point point, Visual visual)
{
Matrix matrix = PresentationSource.FromVisual(visual).CompositionTarget.TransformFromDevice;
return new Point(point.X * matrix.M11, point.Y * matrix.M22);
}
#endregion
/// <summary>
/// Removes <param name="stringToRemove" /> from the start of this string.
/// Throws ArgumentException if this string does not start with <param name="stringToRemove" />.
/// </summary>
public static string RemoveStart(this string s, string stringToRemove)
{
if (s == null)
return null;
if (string.IsNullOrEmpty(stringToRemove))
return s;
if (!s.StartsWith(stringToRemove))
throw new ArgumentException(string.Format("{0} does not start with {1}", s, stringToRemove));
return s.Substring(stringToRemove.Length);
}
/// <summary>
/// Removes <param name="stringToRemove" /> from the end of this string.
/// Throws ArgumentException if this string does not end with <param name="stringToRemove" />.
/// </summary>
public static string RemoveEnd(this string s, string stringToRemove)
{
if (s == null)
return null;
if (string.IsNullOrEmpty(stringToRemove))
return s;
if (!s.EndsWith(stringToRemove))
throw new ArgumentException(string.Format("{0} does not end with {1}", s, stringToRemove));
return s.Substring(0, s.Length - stringToRemove.Length);
}
/// <summary>
/// Takes at most <param name="length" /> first characters from string.
/// String can be null.
/// </summary>
public static string TakeStart(this string s, int length)
{
if (string.IsNullOrEmpty(s) || length >= s.Length)
return s;
return s.Substring(0, length);
}
/// <summary>
/// Takes at most <param name="length" /> first characters from string, and appends '...' if string is longer.
/// String can be null.
/// </summary>
public static string TakeStartEllipsis(this string s, int length)
{
if (string.IsNullOrEmpty(s) || length >= s.Length)
return s;
return s.Substring(0, length) + "...";
}
public static string Replace(this string original, string pattern, string replacement, StringComparison comparisonType)
{
if (original == null)
throw new ArgumentNullException("original");
if (pattern == null)
throw new ArgumentNullException("pattern");
if (pattern.Length == 0)
throw new ArgumentException("String cannot be of zero length.", "pattern");
if (comparisonType != StringComparison.Ordinal && comparisonType != StringComparison.OrdinalIgnoreCase)
throw new NotSupportedException("Currently only ordinal comparisons are implemented.");
StringBuilder result = new StringBuilder(original.Length);
int currentPos = 0;
int nextMatch = original.IndexOf(pattern, comparisonType);
while (nextMatch >= 0) {
result.Append(original, currentPos, nextMatch - currentPos);
// The following line restricts this method to ordinal comparisons:
// for non-ordinal comparisons, the match length might be different than the pattern length.
currentPos = nextMatch + pattern.Length;
result.Append(replacement);
nextMatch = original.IndexOf(pattern, currentPos, comparisonType);
}
result.Append(original, currentPos, original.Length - currentPos);
return result.ToString();
}
public static byte[] GetBytesWithPreamble(this Encoding encoding, string text)
{
byte[] encodedText = encoding.GetBytes(text);
byte[] bom = encoding.GetPreamble();
if (bom != null && bom.Length > 0) {
byte[] result = new byte[bom.Length + encodedText.Length];
bom.CopyTo(result, 0);
encodedText.CopyTo(result, bom.Length);
return result;
} else {
return encodedText;
}
}
/// <summary>
/// Returns the index of the first element for which <paramref name="predicate"/> returns true.
/// If none of the items in the list fits the <paramref name="predicate"/>, -1 is returned.
/// </summary>
public static int FindIndex<T>(this IList<T> list, Func<T, bool> predicate)
{
for (int i = 0; i < list.Count; i++) {
if (predicate(list[i]))
return i;
}
return -1;
}
/// <summary>
/// Adds item to the list if the item is not null.
/// </summary>
public static void AddIfNotNull<T>(this IList<T> list, T itemToAdd)
{
if (itemToAdd != null)
list.Add(itemToAdd);
}
public static void WriteTo(this Stream sourceStream, Stream targetStream)
{
byte[] buffer = new byte[4096];
int bytes;
while ((bytes = sourceStream.Read(buffer, 0, buffer.Length)) > 0)
targetStream.Write(buffer, 0, bytes);
}
}
/// <summary>
/// Scrolling related helpers.
/// </summary>
public static class ScrollUtils
{
/// <summary>
/// Searches VisualTree of given object for a ScrollViewer.
/// </summary>
public static ScrollViewer GetScrollViewer(this DependencyObject o)
{
var scrollViewer = o as ScrollViewer;
if (scrollViewer != null) {
return scrollViewer;
}
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++)
{
var child = VisualTreeHelper.GetChild(o, i);
var result = GetScrollViewer(child);
if (result != null) {
return result;
}
}
return null;
}
/// <summary>
/// Scrolls ScrollViewer up by given offset.
/// </summary>
/// <param name="offset">Offset by which to scroll up. Should be positive.</param>
public static void ScrollUp(this ScrollViewer scrollViewer, double offset)
{
ScrollUtils.ScrollByVerticalOffset(scrollViewer, -offset);
}
/// <summary>
/// Scrolls ScrollViewer down by given offset.
/// </summary>
/// <param name="offset">Offset by which to scroll down. Should be positive.</param>
public static void ScrollDown(this ScrollViewer scrollViewer, double offset)
{
ScrollUtils.ScrollByVerticalOffset(scrollViewer, offset);
}
/// <summary>
/// Scrolls ScrollViewer by given vertical offset.
/// </summary>
public static void ScrollByVerticalOffset(this ScrollViewer scrollViewer, double offset)
{
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + offset);
}
}
}

98
Debugger/ILSpy.Debugger/ToolTips/DebuggerPopup.cs

@ -0,0 +1,98 @@ @@ -0,0 +1,98 @@
// 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.Primitives;
using ICSharpCode.NRefactory.CSharp;
using ILSpy.Debugger.Models.TreeModel;
namespace ILSpy.Debugger.Tooltips
{
/// <summary>
/// Popup containing <see cref="DebuggerTooltipControl"></see>.
/// </summary>
public class DebuggerPopup : Popup
{
internal DebuggerTooltipControl contentControl;
public DebuggerPopup(DebuggerTooltipControl parentControl, AstLocation logicalPosition, bool showPins = true)
{
this.contentControl = new DebuggerTooltipControl(parentControl, logicalPosition, 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;
}
}
}

230
Debugger/ILSpy.Debugger/ToolTips/DebuggerTooltipControl.xaml

@ -0,0 +1,230 @@ @@ -0,0 +1,230 @@
<?xml version="1.0" encoding="utf-8"?>
<UserControl
x:Class="ILSpy.Debugger.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:ILSpy.Debugger.Tooltips"
xmlns:localControls="clr-namespace:ILSpy.Debugger.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>

403
Debugger/ILSpy.Debugger/ToolTips/DebuggerTooltipControl.xaml.cs

@ -0,0 +1,403 @@ @@ -0,0 +1,403 @@
// 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.NRefactory.CSharp;
using ILSpy.Debugger.AvalonEdit;
using ILSpy.Debugger.Models.TreeModel;
using ILSpy.Debugger.Services;
namespace ILSpy.Debugger.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;
readonly AstLocation logicalPosition;
public DebuggerTooltipControl(AstLocation logicalPosition)
{
this.logicalPosition = logicalPosition;
InitializeComponent();
Loaded += new RoutedEventHandler(OnLoaded);
}
public DebuggerTooltipControl(AstLocation logicalPosition, ITreeNode node)
: this(logicalPosition, new ITreeNode[] { node })
{
}
public DebuggerTooltipControl(AstLocation logicalPosition, IEnumerable<ITreeNode> nodes)
: this(logicalPosition)
{
this.itemsSource = nodes;
}
public DebuggerTooltipControl(DebuggerTooltipControl parentControl, AstLocation logicalPosition, bool showPins = true)
: this(logicalPosition)
{
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>(value);
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, logicalPosition, false);
this.childPopup.Placement = PlacementMode.Absolute;
}
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("Saved",
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
Debugger/ILSpy.Debugger/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 ILSpy.Debugger.Services;
namespace ILSpy.Debugger.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);
}
}
}
}
}

362
Debugger/ILSpy.Debugger/ToolTips/PinControlsDictionary.xaml

@ -0,0 +1,362 @@ @@ -0,0 +1,362 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ILSpy.Debugger.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>
<ControlTemplate x:Key="RefreshButton" TargetType="Button">
<Border
Name="ImageBorder"
CornerRadius="7"
BorderBrush="Transparent"
BorderThickness="1"
Height="14"
Width="14">
<Image Width="9" Height="9" Margin="2 2"
x:Name="RefreshContentImage"
Tag="{Binding}"
Source="pack://application:,,,/ILSpy;component/Images/Refresh.png"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsMouseOver" Value="true">
<Setter TargetName="ImageBorder" Property="Background" Value="{StaticResource SilverBrushKey}"/>
<Setter TargetName="ImageBorder" Property="BorderBrush" Value="Gray"/>
</Trigger>
<Trigger Property="ButtonBase.IsPressed" Value="True">
<Setter TargetName="ImageBorder" Property="Background" Value="{StaticResource SilverPressedBrushKey}"/>
<Setter TargetName="ImageBorder" Property="BorderBrush" Value="Gray"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ResourceDictionary>

53
Debugger/ILSpy.Debugger/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 ILSpy.Debugger.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);
}
}
}
}

47
Debugger/ILSpy.Debugger/ToolTips/VisualizerPicker.cs

@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
// 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 ILSpy.Debugger.Models.TreeModel;
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; }
}
}
}

133
Debugger/ILSpy.Debugger/ToolTips/VisualizerPicker.xaml

@ -0,0 +1,133 @@ @@ -0,0 +1,133 @@
<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:ILSpy.Debugger.Tooltips"
xmlns:core="http://icsharpcode.net/sharpdevelop/core">
<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="{core:GetBitmap Icons.Magnifier}" />-->
<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>

6
ILSpy.sln

@ -6,10 +6,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Debugger", "Debugger", "{1D @@ -6,10 +6,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Debugger", "Debugger", "{1D
ProjectSection(SolutionItems) = postProject
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpy.Debugger", "Debugger\ILSpy.Debugger\ILSpy.Debugger.csproj", "{6D3D0F0D-348D-456A-A6ED-E9BD5EFABB6A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Debugger.Core", "Debugger\Debugger.Core\Debugger.Core.csproj", "{1D18D788-F7EE-4585-A23B-34DC8EC63CB8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpy.Debugger", "Debugger\ILSpy.Debugger\ILSpy.Debugger.csproj", "{6D3D0F0D-348D-456A-A6ED-E9BD5EFABB6A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpy", "ILSpy\ILSpy.csproj", "{1E85EFF9-E370-4683-83E4-8A3D063FF791}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.TreeView", "SharpTreeView\ICSharpCode.TreeView.csproj", "{DDE2A481-8271-4EAC-A330-8FA6A38D13D1}"
@ -96,7 +96,7 @@ Global @@ -96,7 +96,7 @@ Global
{6D3D0F0D-348D-456A-A6ED-E9BD5EFABB6A}.Release|Any CPU.ActiveCfg = Release|x86
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{1D18D788-F7EE-4585-A23B-34DC8EC63CB8} = {1DEB3B4E-03AC-437C-821D-B09FBFCC3E5B}
{6D3D0F0D-348D-456A-A6ED-E9BD5EFABB6A} = {1DEB3B4E-03AC-437C-821D-B09FBFCC3E5B}
{1D18D788-F7EE-4585-A23B-34DC8EC63CB8} = {1DEB3B4E-03AC-437C-821D-B09FBFCC3E5B}
EndGlobalSection
EndGlobal

Loading…
Cancel
Save