Browse Source

AvalonEdit: tooltips.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@3913 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 16 years ago
parent
commit
71993014c9
  1. 41
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs
  2. 4
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/SharpDevelopCompletionWindow.cs
  3. 24
      src/AddIns/Misc/ResourceToolkit/Project/Src/ToolTips/ResourceToolTipProvider.cs
  4. 9
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs
  5. 46
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.cs
  6. 3
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/LineNode.cs
  7. 2
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextAnchor.cs
  8. 1
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/CaretNavigationCommandHandler.cs
  9. 24
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextAreaDefaultInputHandlers.cs
  10. 72
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextEditor.cs
  11. 153
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextView.cs
  12. 6
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/documentation/Introduction.xml
  13. 4
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/documentation/SyntaxHighlighting.xml
  14. 18
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/documentation/TextRendering.xml
  15. 1
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  16. 120
      src/Main/Base/Project/Src/Services/Debugger/DebuggerService.cs
  17. 48
      src/Main/Base/Project/Src/TextEditor/Gui/Editor/ITextAreaToolTipProvider.cs
  18. 103
      src/Main/Base/Project/Src/TextEditor/ToolTipService.cs

41
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs

@ -5,12 +5,16 @@ @@ -5,12 +5,16 @@
// <version>$Revision$</version>
// </file>
using ICSharpCode.AvalonEdit.CodeCompletion;
using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using ICSharpCode.AvalonEdit.CodeCompletion;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor;
namespace ICSharpCode.AvalonEdit.AddIn
@ -30,6 +34,41 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -30,6 +34,41 @@ namespace ICSharpCode.AvalonEdit.AddIn
this.FontFamily = new FontFamily("Consolas");
this.FontSize = 13;
this.TextArea.TextEntered += TextArea_TextInput;
this.MouseHover += CodeEditor_MouseHover;
this.MouseHoverStopped += CodeEditor_MouseHoverStopped;
}
ToolTip toolTip;
void CodeEditor_MouseHover(object sender, MouseEventArgs e)
{
ToolTipRequestEventArgs args = new ToolTipRequestEventArgs(textEditorAdapter);
var pos = GetPositionFromPoint(e.GetPosition(this));
args.InDocument = pos.HasValue;
if (pos.HasValue) {
args.LogicalPosition = AvalonEditDocumentAdapter.ToLocation(pos.Value);
}
ToolTipRequestService.RequestToolTip(args);
if (args.ContentToShow != null) {
if (toolTip == null) {
toolTip = new ToolTip();
toolTip.Closed += toolTip_Closed;
}
toolTip.Content = args.ContentToShow;
toolTip.IsOpen = true;
}
}
void CodeEditor_MouseHoverStopped(object sender, MouseEventArgs e)
{
if (toolTip != null) {
toolTip.IsOpen = false;
}
}
void toolTip_Closed(object sender, RoutedEventArgs e)
{
toolTip = null;
}
volatile static ReadOnlyCollection<ICodeCompletionBinding> codeCompletionBindings;

4
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/SharpDevelopCompletionWindow.cs

@ -71,7 +71,9 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -71,7 +71,9 @@ namespace ICSharpCode.AvalonEdit.AddIn
}
public object Description {
get { return item.Description; }
get {
return item.Description;
}
}
public ImageSource Image {

24
src/AddIns/Misc/ResourceToolkit/Project/Src/ToolTips/ResourceToolTipProvider.cs

@ -5,13 +5,14 @@ @@ -5,13 +5,14 @@
// <version>$Revision$</version>
// </file>
using ICSharpCode.SharpDevelop.Refactoring;
using ICSharpCode.SharpDevelop.Dom.Refactoring;
using System;
using System.Drawing;
using Hornung.ResourceToolkit.Resolver;
using ICSharpCode.NRefactory;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Document;
using ICSharpCode.SharpDevelop.Refactoring;
namespace Hornung.ResourceToolkit.ToolTips
{
@ -20,22 +21,19 @@ namespace Hornung.ResourceToolkit.ToolTips @@ -20,22 +21,19 @@ namespace Hornung.ResourceToolkit.ToolTips
/// </summary>
public class ResourceToolTipProvider : ITextAreaToolTipProvider
{
public ToolTipInfo GetToolTipInfo(TextArea textArea, ToolTipRequestEventArgs e)
public void HandleToolTipRequest(ToolTipRequestEventArgs e)
{
TextLocation logicPos = e.LogicalPosition;
IDocument doc = textArea.Document;
if (logicPos.X > doc.GetLineSegment(logicPos.Y).Length - 1) {
return null;
Location logicPos = e.LogicalPosition;
IDocument doc = e.Editor.Document;
if (logicPos.X > doc.GetLine(logicPos.Y).Length) {
return;
}
ResourceResolveResult result = ResourceResolverService.Resolve(textArea.MotherTextEditorControl.FileName, new TextEditorDocument(doc), logicPos.Y, logicPos.X, null);
ResourceResolveResult result = ResourceResolverService.Resolve(e.Editor.FileName, doc, logicPos.Y - 1, logicPos.X - 1, null);
if (result != null && result.ResourceFileContent != null) {
return new ToolTipInfo(ResourceResolverService.FormatResourceDescription(result.ResourceFileContent, result.Key));
e.ShowToolTip(ResourceResolverService.FormatResourceDescription(result.ResourceFileContent, result.Key));
}
return null;
}
}

9
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs

@ -10,6 +10,7 @@ using System.Collections.Generic; @@ -10,6 +10,7 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;
@ -140,6 +141,14 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -140,6 +141,14 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
}
}
/// <summary>
/// Occurs when the SelectedItem property changes.
/// </summary>
public event SelectionChangedEventHandler SelectionChanged {
add { AddHandler(Selector.SelectionChangedEvent, value); }
remove { RemoveHandler(Selector.SelectionChangedEvent, value); }
}
/// <summary>
/// Selects the item that starts with the specified text.
/// </summary>

46
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.cs

@ -9,6 +9,7 @@ using System; @@ -9,6 +9,7 @@ using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
@ -27,6 +28,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -27,6 +28,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
int startOffset;
int endOffset;
readonly CompletionList completionList = new CompletionList();
ToolTip toolTip = new ToolTip();
/// <summary>
/// Creates a new code completion window.
@ -38,11 +40,41 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -38,11 +40,41 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
this.Width = 200;
this.Content = completionList;
toolTip.PlacementTarget = this;
toolTip.Placement = PlacementMode.Right;
toolTip.Closed += toolTip_Closed;
startOffset = endOffset = this.TextArea.Caret.Offset;
document = textArea.TextView.Document;
completionList.InsertionRequested += completionList_InsertionRequested;
completionList.SelectionChanged += completionList_SelectionChanged;
}
#region ToolTip handling
void toolTip_Closed(object sender, RoutedEventArgs e)
{
// Clear content after tooltip is closed.
// We cannot clear is immediately when setting IsOpen=false
// because the tooltip uses an animation for closing.
if (toolTip != null)
toolTip.Content = null;
}
void completionList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var item = completionList.SelectedItem;
if (item == null)
return;
object description = item.Description;
if (description != null) {
toolTip.Content = description;
toolTip.IsOpen = true;
} else {
toolTip.IsOpen = false;
}
}
#endregion
void completionList_InsertionRequested(object sender, EventArgs e)
{
var item = completionList.SelectedItem;
@ -134,6 +166,16 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -134,6 +166,16 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
}
#endregion
/// <inheritdoc/>
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
if (toolTip != null) {
toolTip.IsOpen = false;
toolTip = null;
}
}
/// <inheritdoc/>
protected override void OnKeyDown(KeyEventArgs e)
{
@ -167,6 +209,8 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -167,6 +209,8 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
/// Gets/sets whether the completion window should expect text insertion at the start offset,
/// which not go into the completion region, but before it.
/// </summary>
/// <remarks>This property allows only a single insertion, it is reset to false
/// when that insertion has occurred.</remarks>
public bool ExpectInsertionBeforeStart { get; set; }
void textArea_Document_Changing(object sender, DocumentChangeEventArgs e)

3
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/LineNode.cs

@ -31,6 +31,9 @@ namespace ICSharpCode.AvalonEdit.Document @@ -31,6 +31,9 @@ namespace ICSharpCode.AvalonEdit.Document
// apparently the JIT only optimizes for memory when there are at least three small fields.
// Currently, DocumentLine takes 40 bytes on x86 (8 byte object overhead, 4 pointers, 3 ints, and another DWORD
// for the small fields).
// TODO: a possible optimization would be to combine 'totalLength' and the small fields into a single uint.
// delimiterSize takes only two bits, the two bools take another two bits; so there's still
// 28 bits left for totalLength. 268435455 characters per line should be enough for everyone :)
/// <summary>
/// Resets the line to enable its reuse after a document rebuild.

2
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextAnchor.cs

@ -115,7 +115,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -115,7 +115,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// </summary>
public TextLocation Location {
get {
return new TextLocation(Line, Column);
return document.GetLocation(this.Offset);
}
}

1
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/CaretNavigationCommandHandler.cs

@ -108,6 +108,7 @@ namespace ICSharpCode.AvalonEdit.Gui @@ -108,6 +108,7 @@ namespace ICSharpCode.AvalonEdit.Gui
{
TextArea textArea = GetTextArea(target);
if (textArea != null && textArea.Document != null) {
args.Handled = true;
textArea.Caret.Offset = textArea.Document.TextLength;
textArea.Selection = new SimpleSelection(0, textArea.Document.TextLength);
textArea.Caret.BringCaretToView();

24
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextAreaDefaultInputHandlers.cs

@ -57,27 +57,39 @@ namespace ICSharpCode.AvalonEdit.Gui @@ -57,27 +57,39 @@ namespace ICSharpCode.AvalonEdit.Gui
void ExecuteUndo(object sender, ExecutedRoutedEventArgs e)
{
var undoStack = GetUndoStack();
if (undoStack != null && undoStack.CanUndo)
undoStack.Undo();
if (undoStack != null) {
if (undoStack.CanUndo)
undoStack.Undo();
e.Handled = true;
}
}
void CanExecuteUndo(object sender, CanExecuteRoutedEventArgs e)
{
var undoStack = GetUndoStack();
e.CanExecute = undoStack != null && undoStack.CanUndo;
if (undoStack != null) {
e.Handled = true;
e.CanExecute = undoStack.CanUndo;
}
}
void ExecuteRedo(object sender, ExecutedRoutedEventArgs e)
{
var undoStack = GetUndoStack();
if (undoStack != null && undoStack.CanRedo)
undoStack.Redo();
if (undoStack != null) {
if (undoStack.CanRedo)
undoStack.Redo();
e.Handled = true;
}
}
void CanExecuteRedo(object sender, CanExecuteRoutedEventArgs e)
{
var undoStack = GetUndoStack();
e.CanExecute = undoStack != null && undoStack.CanRedo;
if (undoStack != null) {
e.Handled = true;
e.CanExecute = undoStack.CanRedo;
}
}
#endregion
}

72
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextEditor.cs

@ -731,5 +731,77 @@ namespace ICSharpCode.AvalonEdit @@ -731,5 +731,77 @@ namespace ICSharpCode.AvalonEdit
}
}
#endregion
/// <summary>
/// Gets the text view position from a point inside the editor.
/// </summary>
/// <param name="p">The position, relative to top left
/// corner of TextEditor control</param>
/// <returns>The text view position, or null if the point is outside the document.</returns>
public TextViewPosition? GetPositionFromPoint(Point p)
{
if (this.Document == null)
return null;
TextView textView = this.TextArea.TextView;
return textView.GetPosition(TranslatePoint(p, textView) + textView.ScrollOffset);
}
/// <summary>
/// The PreviewMouseHover event.
/// </summary>
public static readonly RoutedEvent PreviewMouseHoverEvent =
TextView.PreviewMouseHoverEvent.AddOwner(typeof(TextEditor));
/// <summary>
/// The MouseHover event.
/// </summary>
public static readonly RoutedEvent MouseHoverEvent =
TextView.MouseHoverEvent.AddOwner(typeof(TextEditor));
/// <summary>
/// The PreviewMouseHoverStopped event.
/// </summary>
public static readonly RoutedEvent PreviewMouseHoverStoppedEvent =
TextView.PreviewMouseHoverStoppedEvent.AddOwner(typeof(TextEditor));
/// <summary>
/// The MouseHoverStopped event.
/// </summary>
public static readonly RoutedEvent MouseHoverStoppedEvent =
TextView.MouseHoverStoppedEvent.AddOwner(typeof(TextEditor));
/// <summary>
/// Occurs when the mouse has hovered over a fixed location for some time.
/// </summary>
public event MouseEventHandler PreviewMouseHover {
add { AddHandler(PreviewMouseHoverEvent, value); }
remove { RemoveHandler(PreviewMouseHoverEvent, value); }
}
/// <summary>
/// Occurs when the mouse has hovered over a fixed location for some time.
/// </summary>
public event MouseEventHandler MouseHover {
add { AddHandler(MouseHoverEvent, value); }
remove { RemoveHandler(MouseHoverEvent, value); }
}
/// <summary>
/// Occurs when the mouse had previously hovered but now started moving again.
/// </summary>
public event MouseEventHandler PreviewMouseHoverStopped {
add { AddHandler(PreviewMouseHoverStoppedEvent, value); }
remove { RemoveHandler(PreviewMouseHoverStoppedEvent, value); }
}
/// <summary>
/// Occurs when the mouse had previously hovered but now started moving again.
/// </summary>
public event MouseEventHandler MouseHoverStopped {
add { AddHandler(MouseHoverStoppedEvent, value); }
remove { RemoveHandler(MouseHoverStoppedEvent, value); }
}
}
}

153
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextView.cs

@ -1176,6 +1176,8 @@ namespace ICSharpCode.AvalonEdit.Gui @@ -1176,6 +1176,8 @@ namespace ICSharpCode.AvalonEdit.Gui
/// </summary>
public VisualLine GetVisualLineFromVisualTop(double visualTop)
{
// TODO: change this method to also work outside the visible range -
// required to make GetPosition work as expected!
EnsureVisualLines();
foreach (VisualLine vl in this.VisualLines) {
if (visualTop < vl.VisualTop)
@ -1224,6 +1226,25 @@ namespace ICSharpCode.AvalonEdit.Gui @@ -1224,6 +1226,25 @@ namespace ICSharpCode.AvalonEdit.Gui
}
return visualLine.GetVisualPosition(visualColumn, yPositionMode);
}
/// <summary>
/// Gets the text view position from the specified visual position.
/// </summary>
/// <param name="visualPosition">The position in WPF device-independent pixels relative
/// to the top left corner of the document.</param>
/// <returns>The logical position, or null if the position is outside the document.</returns>
public TextViewPosition? GetPosition(Point visualPosition)
{
VerifyAccess();
if (this.Document == null)
throw new InvalidOperationException("There is no document assigned to the TextView");
VisualLine line = GetVisualLineFromVisualTop(visualPosition.Y);
if (line == null)
return null;
int visualColumn = line.GetVisualColumn(visualPosition);
int documentOffset = line.GetRelativeOffset(visualColumn) + line.FirstDocumentLine.Offset;
return new TextViewPosition(document.GetLocation(documentOffset), visualColumn);
}
#endregion
#region Service Provider
@ -1256,6 +1277,138 @@ namespace ICSharpCode.AvalonEdit.Gui @@ -1256,6 +1277,138 @@ namespace ICSharpCode.AvalonEdit.Gui
}
#endregion
#region MouseHover
/// <summary>
/// The PreviewMouseHover event.
/// </summary>
public static readonly RoutedEvent PreviewMouseHoverEvent =
EventManager.RegisterRoutedEvent("PreviewMouseHover", RoutingStrategy.Tunnel,
typeof(MouseEventHandler), typeof(TextView));
/// <summary>
/// The MouseHover event.
/// </summary>
public static readonly RoutedEvent MouseHoverEvent =
EventManager.RegisterRoutedEvent("MouseHover", RoutingStrategy.Bubble,
typeof(MouseEventHandler), typeof(TextView));
/// <summary>
/// The PreviewMouseHoverStopped event.
/// </summary>
public static readonly RoutedEvent PreviewMouseHoverStoppedEvent =
EventManager.RegisterRoutedEvent("PreviewMouseHoverStopped", RoutingStrategy.Tunnel,
typeof(MouseEventHandler), typeof(TextView));
/// <summary>
/// The MouseHoverStopped event.
/// </summary>
public static readonly RoutedEvent MouseHoverStoppedEvent =
EventManager.RegisterRoutedEvent("MouseHoverStopped", RoutingStrategy.Bubble,
typeof(MouseEventHandler), typeof(TextView));
/// <summary>
/// Occurs when the mouse has hovered over a fixed location for some time.
/// </summary>
public event MouseEventHandler PreviewMouseHover {
add { AddHandler(PreviewMouseHoverEvent, value); }
remove { RemoveHandler(PreviewMouseHoverEvent, value); }
}
/// <summary>
/// Occurs when the mouse has hovered over a fixed location for some time.
/// </summary>
public event MouseEventHandler MouseHover {
add { AddHandler(MouseHoverEvent, value); }
remove { RemoveHandler(MouseHoverEvent, value); }
}
/// <summary>
/// Occurs when the mouse had previously hovered but now started moving again.
/// </summary>
public event MouseEventHandler PreviewMouseHoverStopped {
add { AddHandler(PreviewMouseHoverStoppedEvent, value); }
remove { RemoveHandler(PreviewMouseHoverStoppedEvent, value); }
}
/// <summary>
/// Occurs when the mouse had previously hovered but now started moving again.
/// </summary>
public event MouseEventHandler MouseHoverStopped {
add { AddHandler(MouseHoverStoppedEvent, value); }
remove { RemoveHandler(MouseHoverStoppedEvent, value); }
}
DispatcherTimer mouseHoverTimer;
Point mouseHoverStartPoint;
MouseEventArgs mouseHoverLastEventArgs;
bool mouseHovering;
/// <inheritdoc/>
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
Point newPosition = e.GetPosition(this);
Vector mouseMovement = mouseHoverStartPoint - newPosition;
if (Math.Abs(mouseMovement.X) > SystemParameters.MouseHoverWidth
|| Math.Abs(mouseMovement.Y) > SystemParameters.MouseHoverHeight)
{
StopHovering();
mouseHoverStartPoint = newPosition;
mouseHoverLastEventArgs = e;
mouseHoverTimer = new DispatcherTimer(SystemParameters.MouseHoverTime, DispatcherPriority.Background,
OnMouseHoverTimerElapsed, this.Dispatcher);
mouseHoverTimer.Start();
}
// do not set e.Handled - allow others to also handle MouseMove
}
/// <inheritdoc/>
protected override void OnMouseLeave(MouseEventArgs e)
{
base.OnMouseLeave(e);
StopHovering();
// do not set e.Handled - allow others to also handle MouseLeave
}
void StopHovering()
{
if (mouseHoverTimer != null) {
mouseHoverTimer.Stop();
mouseHoverTimer = null;
}
if (mouseHovering) {
mouseHovering = false;
RaiseHoverEventPair(PreviewMouseHoverStoppedEvent, MouseHoverStoppedEvent);
}
}
void OnMouseHoverTimerElapsed(object sender, EventArgs e)
{
mouseHoverTimer.Stop();
mouseHoverTimer = null;
mouseHovering = true;
RaiseHoverEventPair(PreviewMouseHoverEvent, MouseHoverEvent);
}
void RaiseHoverEventPair(RoutedEvent tunnelingEvent, RoutedEvent bubblingEvent)
{
var mouseDevice = mouseHoverLastEventArgs.MouseDevice;
var stylusDevice = mouseHoverLastEventArgs.StylusDevice;
int inputTime = Environment.TickCount;
var args1 = new MouseEventArgs(mouseDevice, inputTime, stylusDevice) {
RoutedEvent = tunnelingEvent,
Source = this
};
RaiseEvent(args1);
var args2 = new MouseEventArgs(mouseDevice, inputTime, stylusDevice) {
RoutedEvent = bubblingEvent,
Source = this,
Handled = args1.Handled
};
RaiseEvent(args2);
}
#endregion
/// <summary>
/// Collapses lines for the purpose of scrolling. This method is meant for
/// <see cref="VisualLineElementGenerator"/>s that cause <see cref="VisualLine"/>s to span

6
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/documentation/Introduction.xml

@ -11,10 +11,10 @@ @@ -11,10 +11,10 @@
<para>While the WPF RichTextBox is quite powerful, you quickly run into its limits
when trying to use it as a code editor: it's hard to write efficient syntax highlighting for it,
and you cannot really implement features like code folding with the standard RichTextBox.</para>
<para>The issue is that in the RichTextBox edits a rich document. In contrast, AvalonEdit
just edits text. However, AvalonEdit offers lots of possibilities on how the text document is
<para>The issue is simple: the RichTextBox edits a rich document. In contrast, AvalonEdit
simply edits text. However, AvalonEdit offers lots of possibilities on how the text document is
displayed - so it is much more suitable for a code editor where things like the text color
are not controlled by the user, but simply depend on the text (syntax highlighting).</para>
are not controlled by the user, but instead depend on the text (syntax highlighting).</para>
</introduction>
<!-- TODO: screenshot-->

4
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/documentation/SyntaxHighlighting.xml

@ -9,8 +9,8 @@ @@ -9,8 +9,8 @@
Text Rendering extension points is the support for "visual line transformers" that
can change the display of a visual line after it has been constructed by the "visual element generators".
A useful base class implementing IVisualLineTransformer for the purpose of syntax highlighting
is DocumentColorizingTransformer. But please take a look at that class' documentation to see
how to write fully custom syntax highlighters. This article discusses the XML-driven built-in
is DocumentColorizingTransformer. Take a look at that class' documentation to see
how to write fully custom syntax highlighters. This article only discusses the XML-driven built-in
highlighting engine.
</para>
</introduction>

18
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/documentation/TextRendering.xml

@ -22,8 +22,9 @@ @@ -22,8 +22,9 @@
<content>
<para>
VisualLines are only created for the visible part of the document.
This usually happens in the MeasureOverride of TextView:
when the TextView is measured, it uses the height tree to determine the first
Lots of actions can trigger their creation, but most commonly the creation will be
caused by the MeasureOverride method of TextView.
When the TextView is measured, it uses the height tree to determine the first
document line in the visible region. Then, it constructs and measures a VisualLine
for that first line, and repeats that with the following lines
until the visible region is filled.
@ -52,10 +53,10 @@ @@ -52,10 +53,10 @@
one redraw for multiple input actions.
</para>
<para>
ALERT: this means you need to ensure that if you access VisualLine, you can cope
with the case that the VisualLines you're interested in are not available.
ALERT: this means that if you access VisualLine, you must be able to handle
the case that your requested VisualLines are not available.
You can use GetOrConstructVisualLine to make the text editor re-build the visual line
if it does not exist anymore; or you can call EnsureVisualLines() to make the text
if it does not exist anymore; or you can call EnsureVisualLines() to make the text view
create all VisualLines in the visible region.
</para>
</content>
@ -68,6 +69,13 @@ @@ -68,6 +69,13 @@
room in between the elements returned from the generators is filled with text elements.
Then, the VisualLine assigns the VisualColumn and RelativeTextOffset properties of the line elements.
</para>
<para>
For example, a line contains the text "Hello, World".
The user has enabled "ShowSpaces", so the text editor should show a little dot instead of the space.
In this case, the SingleCharacterElementGenerator, which is responsible for ShowSpaces, will produce
a "SpaceTextElement" for the space character. Because no other generators are interested in the line,
the remaining strings "Hello," and "World" will be represented by VisualLineText elements.
</para>
</content>
</section>
<section>

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

@ -558,6 +558,7 @@ @@ -558,6 +558,7 @@
<Compile Include="Src\TextEditor\ICompletionItem.cs" />
<Compile Include="Src\TextEditor\ICompletionItemList.cs" />
<Compile Include="Src\TextEditor\ITextEditor.cs" />
<Compile Include="Src\TextEditor\ToolTipService.cs" />
<Compile Include="Src\TextEditor\XmlFormattingStrategy.cs" />
<Compile Include="Src\Services\Tasks\TaskEventHandler.cs" />
<Compile Include="Src\TextEditor\Commands\NavigationCommands.cs" />

120
src/Main/Base/Project/Src/Services/Debugger/DebuggerService.cs

@ -5,13 +5,13 @@ @@ -5,13 +5,13 @@
// <version>$Revision$</version>
// </file>
using ICSharpCode.NRefactory;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Gui;
@ -21,7 +21,6 @@ using ICSharpCode.TextEditor.Document; @@ -21,7 +21,6 @@ using ICSharpCode.TextEditor.Document;
using BM = ICSharpCode.SharpDevelop.Bookmarks;
using ITextAreaToolTipProvider = ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor.ITextAreaToolTipProvider;
using ITextEditorControlProvider = ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor.ITextEditorControlProvider;
using ToolTipInfo = ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor.ToolTipInfo;
namespace ICSharpCode.SharpDevelop.Debugging
{
@ -37,7 +36,6 @@ namespace ICSharpCode.SharpDevelop.Debugging @@ -37,7 +36,6 @@ namespace ICSharpCode.SharpDevelop.Debugging
ClearDebugMessages();
};
WorkbenchSingleton.WorkbenchCreated += new EventHandler(WorkspaceCreated);
BM.BookmarkManager.Added += BookmarkAdded;
BM.BookmarkManager.Removed += BookmarkRemoved;
}
@ -240,33 +238,13 @@ namespace ICSharpCode.SharpDevelop.Debugging @@ -240,33 +238,13 @@ namespace ICSharpCode.SharpDevelop.Debugging
}
}
static void WorkspaceCreated(object sender, EventArgs args)
{
WorkbenchSingleton.Workbench.ViewOpened += new ViewContentEventHandler(ViewContentOpened);
WorkbenchSingleton.Workbench.ViewClosed += new ViewContentEventHandler(ViewContentClosed);
}
/* TODO: reimplement this stuff
static void ViewContentOpened(object sender, ViewContentEventArgs e)
{
if (e.Content is ITextEditorControlProvider) {
TextArea textArea = ((ITextEditorControlProvider)e.Content).TextEditorControl.ActiveTextAreaControl.TextArea;
textArea.IconBarMargin.MouseDown += IconBarMouseDown;
textArea.ToolTipRequest += TextAreaToolTipRequest;
textArea.MouseLeave += TextAreaMouseLeave;
}
}
static void ViewContentClosed(object sender, ViewContentEventArgs e)
{
if (e.Content is ITextEditorControlProvider) {
TextArea textArea = ((ITextEditorControlProvider)e.Content).TextEditorControl.ActiveTextAreaControl.TextArea;
textArea.IconBarMargin.MouseDown -= IconBarMouseDown;
textArea.ToolTipRequest -= TextAreaToolTipRequest;
textArea.MouseLeave -= TextAreaMouseLeave;
}
}
}*/
public static void RemoveCurrentLineMarker()
{
@ -292,59 +270,8 @@ namespace ICSharpCode.SharpDevelop.Debugging @@ -292,59 +270,8 @@ namespace ICSharpCode.SharpDevelop.Debugging
}
#region Tool tips
const string ToolTipProviderAddInTreePath = "/SharpDevelop/ViewContent/DefaultTextEditor/ToolTips";
static DebuggerGridControl oldToolTipControl;
/// <summary>
/// This function shows variable values as tooltips
/// </summary>
static void TextAreaToolTipRequest(object sender, ToolTipRequestEventArgs e)
{
DebuggerGridControl toolTipControl = null;
try {
TextArea textArea = (TextArea)sender;
if (e.ToolTipShown) return;
if (oldToolTipControl != null && !oldToolTipControl.AllowClose) return;
if (!CodeCompletionOptions.EnableCodeCompletion) return;
if (!CodeCompletionOptions.TooltipsEnabled) return;
if (CodeCompletionOptions.TooltipsOnlyWhenDebugging) {
if (currentDebugger == null) return;
if (!currentDebugger.IsDebugging) return;
}
if (e.InDocument) {
// Query all registered tooltip providers using the AddInTree.
// The first one that does not return null will be used.
ToolTipInfo ti = null;
foreach (ITextAreaToolTipProvider toolTipProvider in AddInTree.BuildItems<ITextAreaToolTipProvider>(ToolTipProviderAddInTreePath, null, false)) {
if ((ti = toolTipProvider.GetToolTipInfo(textArea, e)) != null) {
break;
}
}
if (ti != null) {
toolTipControl = ti.ToolTipControl as DebuggerGridControl;
if (ti.ToolTipText != null) {
e.ShowToolTip(ti.ToolTipText);
}
}
CloseOldToolTip();
if (toolTipControl != null) {
toolTipControl.ShowForm(textArea, e.LogicalPosition);
}
oldToolTipControl = toolTipControl;
}
} catch (Exception ex) {
ICSharpCode.Core.MessageService.ShowError(ex, "Error while requesting tooltip for location " + e.LogicalPosition);
} finally {
if (toolTipControl == null && CanCloseOldToolTip)
CloseOldToolTip();
}
}
static bool CanCloseOldToolTip {
get {
return oldToolTipControl != null && oldToolTipControl.AllowClose;
@ -360,35 +287,28 @@ namespace ICSharpCode.SharpDevelop.Debugging @@ -360,35 +287,28 @@ namespace ICSharpCode.SharpDevelop.Debugging
}
}
static void TextAreaMouseLeave(object source, EventArgs e)
{
if (CanCloseOldToolTip && !oldToolTipControl.IsMouseOver)
CloseOldToolTip();
}
/// <summary>
/// Gets debugger tooltip information for the specified position.
/// A descriptive text for the element or a DebuggerGridControl
/// showing its current value (when in debugging mode) can be returned
/// through the ToolTipInfo object.
/// Returns <c>null</c>, if no tooltip information is available.
/// </summary>
internal static ToolTipInfo GetToolTipInfo(TextArea textArea, ToolTipRequestEventArgs e)
internal static void HandleToolTipRequest(ToolTipRequestEventArgs e)
{
TextLocation logicPos = e.LogicalPosition;
IDocument doc = textArea.Document;
IExpressionFinder expressionFinder = ParserService.GetExpressionFinder(textArea.MotherTextEditorControl.FileName);
Location logicPos = e.LogicalPosition;
var doc = e.Editor.Document;
IExpressionFinder expressionFinder = ParserService.GetExpressionFinder(e.Editor.FileName);
if (expressionFinder == null)
return null;
LineSegment seg = doc.GetLineSegment(logicPos.Y);
if (logicPos.X > seg.Length - 1)
return null;
string textContent = doc.TextContent;
ExpressionResult expressionResult = expressionFinder.FindFullExpression(textContent, seg.Offset + logicPos.X);
return;
var currentLine = doc.GetLine(logicPos.Y);
if (logicPos.X > currentLine.Length)
return;
string textContent = doc.Text;
ExpressionResult expressionResult = expressionFinder.FindFullExpression(textContent, doc.PositionToOffset(logicPos.Line, logicPos.Column));
string expression = (expressionResult.Expression ?? "").Trim();
if (expression.Length > 0) {
// Look if it is variable
ResolveResult result = ParserService.Resolve(expressionResult, logicPos.Y + 1, logicPos.X + 1, textArea.MotherTextEditorControl.FileName, textContent);
ResolveResult result = ParserService.Resolve(expressionResult, logicPos.Y, logicPos.X, e.Editor.FileName, textContent);
bool debuggerCanShowValue;
string toolTipText = GetText(result, expression, out debuggerCanShowValue);
if (Control.ModifierKeys == Keys.Control) {
@ -397,18 +317,18 @@ namespace ICSharpCode.SharpDevelop.Debugging @@ -397,18 +317,18 @@ namespace ICSharpCode.SharpDevelop.Debugging
}
if (toolTipText != null) {
if (debuggerCanShowValue && currentDebugger != null) {
return new ToolTipInfo(currentDebugger.GetTooltipControl(expressionResult.Expression));
e.ShowToolTip(currentDebugger.GetTooltipControl(expressionResult.Expression));
} else {
e.ShowToolTip(toolTipText);
}
return new ToolTipInfo(toolTipText);
}
} else {
#if DEBUG
if (Control.ModifierKeys == Keys.Control) {
return new ToolTipInfo("no expr: " + expressionResult.ToString());
e.ShowToolTip("no expr: " + expressionResult.ToString());
}
#endif
}
return null;
}
static string GetText(ResolveResult result, string expression, out bool debuggerCanShowValue)
@ -523,9 +443,9 @@ namespace ICSharpCode.SharpDevelop.Debugging @@ -523,9 +443,9 @@ namespace ICSharpCode.SharpDevelop.Debugging
/// </remarks>
public class DebuggerTextAreaToolTipProvider : ITextAreaToolTipProvider
{
public ToolTipInfo GetToolTipInfo(TextArea textArea, ToolTipRequestEventArgs e)
public void HandleToolTipRequest(ToolTipRequestEventArgs e)
{
return DebuggerService.GetToolTipInfo(textArea, e);
DebuggerService.HandleToolTipRequest(e);
}
}
}

48
src/Main/Base/Project/Src/TextEditor/Gui/Editor/ITextAreaToolTipProvider.cs

@ -22,52 +22,6 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor @@ -22,52 +22,6 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
/// if available.
/// </summary>
/// <returns><c>null</c>, if no tooltip information is available at this position, otherwise a ToolTipInfo object containing the tooltip information to be displayed.</returns>
ToolTipInfo GetToolTipInfo(TextArea textArea, ToolTipRequestEventArgs e);
}
/// <summary>
/// Contains information about a tooltip to be shown on the text area.
/// </summary>
public class ToolTipInfo
{
object toolTipObject;
/// <summary>
/// Gets the tool tip text to be displayed.
/// May be <c>null</c>.
/// </summary>
public string ToolTipText {
get {
return this.toolTipObject as string;
}
}
/// <summary>
/// Gets the DebuggerGridControl to be shown as tooltip.
/// May be <c>null</c>.
/// </summary>
public Control ToolTipControl {
get {
return this.toolTipObject as Control;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="ToolTipInfo"/> class.
/// </summary>
/// <param name="toolTipText">The tooltip text to be displayed.</param>
public ToolTipInfo(string toolTipText)
{
this.toolTipObject = toolTipText;
}
/// <summary>
/// Initializes a new instance of the <see cref="ToolTipInfo"/> class.
/// </summary>
/// <param name="toolTipControl">The DebuggerGridControl to be shown as tooltip.</param>
public ToolTipInfo(Control toolTipControl)
{
this.toolTipObject = toolTipControl;
}
void HandleToolTipRequest(ToolTipRequestEventArgs e);
}
}

103
src/Main/Base/Project/Src/TextEditor/ToolTipService.cs

@ -0,0 +1,103 @@ @@ -0,0 +1,103 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <author name="Daniel Grunwald"/>
// <version>$Revision$</version>
// </file>
using ICSharpCode.SharpDevelop.Debugging;
using System;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor;
namespace ICSharpCode.SharpDevelop
{
/// <summary>
/// Static class for the ToolTipRequested event.
/// </summary>
public static class ToolTipRequestService
{
const string ToolTipProviderAddInTreePath = "/SharpDevelop/ViewContent/DefaultTextEditor/ToolTips";
/// <summary>
/// This event occurs on a tool tip request,
/// after any <see cref="ITextAreaToolTipProvider"/> registered in the addintree have run.
/// This event is still raised if AddIns handled it, so please check the Handled property.
/// </summary>
public static event EventHandler<ToolTipRequestEventArgs> ToolTipRequested;
public static void RequestToolTip(ToolTipRequestEventArgs e)
{
if (e == null)
throw new ArgumentNullException("e");
if (!CodeCompletionOptions.EnableCodeCompletion) return;
if (!CodeCompletionOptions.TooltipsEnabled) return;
if (CodeCompletionOptions.TooltipsOnlyWhenDebugging) {
if (!DebuggerService.IsDebuggerLoaded) return;
if (!DebuggerService.CurrentDebugger.IsDebugging) return;
}
// Query all registered tooltip providers using the AddInTree.
// The first one that does not return null will be used.
foreach (ITextAreaToolTipProvider toolTipProvider in AddInTree.BuildItems<ITextAreaToolTipProvider>(ToolTipProviderAddInTreePath, null, false)) {
toolTipProvider.HandleToolTipRequest(e);
if (e.Handled)
break;
}
EventHandler<ToolTipRequestEventArgs> eh = ToolTipRequested;
if (eh != null)
eh(null, e);
}
}
public class ToolTipRequestEventArgs : EventArgs
{
/// <summary>
/// Gets whether the tool tip request was handled.
/// </summary>
public bool Handled { get; set; }
/// <summary>
/// Gets the editor causing the request.
/// </summary>
public ITextEditor Editor { get; private set; }
/// <summary>
/// Gets whether the mouse was inside the document bounds.
/// </summary>
public bool InDocument { get; set; }
/// <summary>
/// The mouse position, in document coordinates.
/// </summary>
public Location LogicalPosition { get; set; }
/// <summary>
/// Gets/Sets the content to show as a tooltip.
/// </summary>
public object ContentToShow { get; set; }
/// <summary>
/// Shows the tool tip.
/// </summary>
public void ShowToolTip(object content)
{
if (content == null)
throw new ArgumentNullException("content");
this.Handled = true;
this.ContentToShow = content;
}
public ToolTipRequestEventArgs(ITextEditor editor)
{
if (editor == null)
throw new ArgumentNullException("editor");
this.Editor = editor;
this.InDocument = true;
}
}
}
Loading…
Cancel
Save