diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs
new file mode 100644
index 0000000000..121cc6d4f7
--- /dev/null
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs
@@ -0,0 +1,20 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Windows.Controls;
+
+namespace ICSharpCode.AvalonEdit.CodeCompletion
+{
+ ///
+ /// The listbox used inside the CompletionWindow.
+ ///
+ public class CompletionList : ListBox
+ {
+
+ }
+}
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.xaml b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.xaml
new file mode 100644
index 0000000000..4ff6a769a2
--- /dev/null
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.xaml
@@ -0,0 +1,9 @@
+
+
+
\ No newline at end of file
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.xaml.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.xaml.cs
new file mode 100644
index 0000000000..267f9c2b20
--- /dev/null
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.xaml.cs
@@ -0,0 +1,75 @@
+using ICSharpCode.AvalonEdit.Document;
+using System;
+
+namespace ICSharpCode.AvalonEdit.CodeCompletion
+{
+ ///
+ /// The code completion window.
+ ///
+ public partial class CompletionWindow : CompletionWindowBase
+ {
+ TextDocument document;
+ int startOffset;
+ int endOffset;
+
+ ///
+ /// Creates a new code completion window.
+ ///
+ public CompletionWindow(TextArea textArea) : base(textArea)
+ {
+ InitializeComponent();
+
+ document = textArea.TextView.Document;
+ startOffset = endOffset = textArea.Caret.Offset;
+ }
+
+ ///
+ protected override void AttachEvents()
+ {
+ base.AttachEvents();
+ document.Changing += textArea_Document_Changing;
+ this.TextArea.Caret.PositionChanged += CaretPositionChanged;
+ }
+
+ ///
+ protected override void DetachEvents()
+ {
+ document.Changing -= textArea_Document_Changing;
+ this.TextArea.Caret.PositionChanged -= CaretPositionChanged;
+ base.DetachEvents();
+ }
+
+ void textArea_Document_Changing(object sender, DocumentChangeEventArgs e)
+ {
+ // => startOffset test required so that this startOffset/endOffset are not incremented again
+ // for BeforeStartKey characters
+ if (e.Offset >= startOffset && e.Offset <= endOffset) {
+ endOffset += e.InsertionLength - e.RemovalLength;
+ } else {
+ Close();
+ }
+ }
+
+ ///
+ /// When this flag is set, code completion closes if the caret moves to the
+ /// beginning of the allowed range. This is useful in Ctrl+Space and "complete when typing",
+ /// but not in dot-completion.
+ ///
+ public bool CloseWhenCaretAtBeginning { get; set; }
+
+ void CaretPositionChanged(object sender, EventArgs e)
+ {
+ int offset = this.TextArea.Caret.Offset;
+ if (offset == startOffset) {
+ if (CloseWhenCaretAtBeginning)
+ Close();
+ return;
+ }
+ if (offset < startOffset || offset > endOffset) {
+ Close();
+ } else {
+ //codeCompletionListView.SelectItemWithStart(document.GetText(startOffset, offset - startOffset));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindowBase.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindowBase.cs
new file mode 100644
index 0000000000..d1f27380de
--- /dev/null
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindowBase.cs
@@ -0,0 +1,178 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Diagnostics;
+using System.Windows;
+using System.Windows.Input;
+using System.Windows.Threading;
+
+using ICSharpCode.AvalonEdit.Gui;
+using ICSharpCode.AvalonEdit.Utils;
+
+namespace ICSharpCode.AvalonEdit.CodeCompletion
+{
+ ///
+ /// Base class for completion windows. Handles positioning the window at the caret.
+ ///
+ public class CompletionWindowBase : Window
+ {
+ static CompletionWindowBase()
+ {
+ WindowStyleProperty.OverrideMetadata(typeof(CompletionWindowBase), new FrameworkPropertyMetadata(WindowStyle.None));
+ ShowActivatedProperty.OverrideMetadata(typeof(CompletionWindowBase), new FrameworkPropertyMetadata(Boxes.False));
+ ShowInTaskbarProperty.OverrideMetadata(typeof(CompletionWindowBase), new FrameworkPropertyMetadata(Boxes.False));
+ }
+
+ ///
+ /// Gets the parent TextArea.
+ ///
+ public TextArea TextArea { get; private set; }
+
+ Window parentWindow;
+
+ ///
+ /// Creates a new CompletionWindowBase.
+ ///
+ public CompletionWindowBase(TextArea textArea)
+ {
+ if (textArea == null)
+ throw new ArgumentNullException("textArea");
+ this.TextArea = textArea;
+ parentWindow = Window.GetWindow(textArea);
+ }
+
+ #region Event Handlers
+ ///
+ /// Attaches events to the text area.
+ ///
+ protected virtual void AttachEvents()
+ {
+ this.TextArea.LostFocus += TextAreaLostFocus;
+ this.TextArea.TextView.ScrollOffsetChanged += TextViewScrollOffsetChanged;
+ this.TextArea.TextView.DocumentChanged += TextViewDocumentChanged;
+ if (parentWindow != null) {
+ parentWindow.LocationChanged += parentWindow_LocationChanged;
+ parentWindow.Deactivated += parentWindowDeactivated;
+ }
+ }
+
+ ///
+ /// Detaches events from the text area.
+ ///
+ protected virtual void DetachEvents()
+ {
+ this.TextArea.LostFocus -= TextAreaLostFocus;
+ this.TextArea.TextView.ScrollOffsetChanged -= TextViewScrollOffsetChanged;
+ this.TextArea.TextView.DocumentChanged -= TextViewDocumentChanged;
+ if (parentWindow != null) {
+ parentWindow.LocationChanged -= parentWindow_LocationChanged;
+ parentWindow.Deactivated -= parentWindowDeactivated;
+ }
+ }
+
+ void TextViewScrollOffsetChanged(object sender, EventArgs e)
+ {
+ UpdatePosition();
+ }
+
+ void TextViewDocumentChanged(object sender, EventArgs e)
+ {
+ Close();
+ }
+
+ void TextAreaLostFocus(object sender, RoutedEventArgs e)
+ {
+ Dispatcher.BeginInvoke(new Action(CloseIfFocusLost), DispatcherPriority.Background);
+ }
+
+ void parentWindow_LocationChanged(object sender, EventArgs e)
+ {
+ UpdatePosition();
+ }
+
+ void parentWindowDeactivated(object sender, EventArgs e)
+ {
+ Dispatcher.BeginInvoke(new Action(CloseIfFocusLost), DispatcherPriority.Background);
+ }
+
+ ///
+ protected override void OnDeactivated(EventArgs e)
+ {
+ base.OnDeactivated(e);
+ Dispatcher.BeginInvoke(new Action(CloseIfFocusLost), DispatcherPriority.Background);
+ }
+ #endregion
+
+ void CloseIfFocusLost()
+ {
+ Debug.WriteLine("CloseIfFocusLost");
+ if (!this.IsActive && parentWindow != null && !parentWindow.IsActive) {
+ // close if parent window looses focus
+ Close();
+ }
+ if (!this.TextArea.IsFocused) {
+ Close();
+ }
+ }
+
+ ///
+ protected override void OnSourceInitialized(EventArgs e)
+ {
+ base.OnSourceInitialized(e);
+ SetPosition();
+ AttachEvents();
+ }
+
+ ///
+ protected override void OnClosed(EventArgs e)
+ {
+ base.OnClosed(e);
+ DetachEvents();
+ }
+
+ Point visualLocation, visualLocationTop;
+
+ ///
+ /// Positions the completion window at the caret position.
+ ///
+ void SetPosition()
+ {
+ TextView textView = this.TextArea.TextView;
+
+ visualLocation = textView.GetVisualPosition(this.TextArea.Caret.Position, VisualYPosition.LineBottom);
+ visualLocationTop = textView.GetVisualPosition(this.TextArea.Caret.Position, VisualYPosition.LineTop);
+ UpdatePosition();
+ }
+
+ void UpdatePosition()
+ {
+ TextView textView = this.TextArea.TextView;
+ Point location = textView.PointToScreen(visualLocation - textView.ScrollOffset);
+ Point locationTop = textView.PointToScreen(visualLocationTop - textView.ScrollOffset);
+
+ Size completionWindowSize = new Size(this.ActualWidth, this.ActualHeight);
+ Rect bounds = new Rect(location, completionWindowSize);
+ Rect workingScreen = System.Windows.Forms.Screen.GetWorkingArea(location.ToSystemDrawing()).ToWpf();
+ if (!workingScreen.Contains(bounds)) {
+ if (bounds.Left < workingScreen.Left) {
+ bounds.X = workingScreen.Left;
+ } else if (bounds.Right > workingScreen.Right) {
+ bounds.X = workingScreen.Right - bounds.Width;
+ }
+ if (bounds.Bottom > workingScreen.Bottom) {
+ bounds.Y = locationTop.Y - bounds.Height;
+ }
+ if (bounds.Y < workingScreen.Top) {
+ bounds.Y = workingScreen.Top;
+ }
+ }
+ this.Left = bounds.X;
+ this.Top = bounds.Y;
+ }
+ }
+}
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/BackgroundGeometryBuilder.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/BackgroundGeometryBuilder.cs
index 764ed60c5a..6e6cee95fa 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/BackgroundGeometryBuilder.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/BackgroundGeometryBuilder.cs
@@ -76,7 +76,7 @@ namespace ICSharpCode.AvalonEdit.Gui
TextLine lastTextLine = vl.TextLines.Last();
foreach (TextLine line in vl.TextLines) {
- double y = vl.GetTextLineVisualTop(line);
+ double y = vl.GetTextLineVisualYPosition(line, VisualYPosition.LineTop);
int visualStartCol = vl.GetTextLineVisualStartColumn(line);
int visualEndCol = visualStartCol + line.Length;
if (line != lastTextLine)
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/Caret.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/Caret.cs
index ddf0ce63f5..4644fd4807 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/Caret.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/Caret.cs
@@ -213,14 +213,13 @@ namespace ICSharpCode.AvalonEdit.Gui
TextLine textLine = visualLine.GetTextLine(position.VisualColumn);
double xPos = textLine.GetDistanceFromCharacterHit(new CharacterHit(position.VisualColumn, 0));
- double lineTop = visualLine.GetTextLineVisualTop(textLine);
- double lineBottom = lineTop + textLine.Height;
- double fontSize = (double)textArea.GetValue(TextBlock.FontSizeProperty);
+ double lineTop = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.TextTop);
+ double lineBottom = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.LineBottom);
return new Rect(xPos,
- lineBottom - fontSize,
+ lineTop,
SystemParameters.CaretWidth,
- fontSize);
+ lineBottom - lineTop);
}
///
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/CaretNavigationCommandHandler.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/CaretNavigationCommandHandler.cs
index d162f6aae9..1e4861d01a 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/CaretNavigationCommandHandler.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/CaretNavigationCommandHandler.cs
@@ -280,14 +280,14 @@ namespace ICSharpCode.AvalonEdit.Gui
case CaretMovementType.PageDown:
{
// Page up/down: find the target line using its visual position
- double yPos = visualLine.GetTextLineVisualTop(textLine) + textLine.Height / 2;
+ double yPos = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.LineMiddle);
if (direction == CaretMovementType.PageUp)
yPos -= textArea.TextView.RenderSize.Height;
else
yPos += textArea.TextView.RenderSize.Height;
DocumentLine newLine = textArea.TextView.GetDocumentLineByVisualTop(yPos);
targetVisualLine = textArea.TextView.GetOrConstructVisualLine(newLine);
- targetLine = targetVisualLine.GetTextLineByVisualTop(yPos);
+ targetLine = targetVisualLine.GetTextLineByVisualYPosition(yPos);
break;
}
default:
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/FoldingMargin.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/FoldingMargin.cs
index 98832cbcde..e2ecbdd665 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/FoldingMargin.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/FoldingMargin.cs
@@ -45,7 +45,7 @@ namespace ICSharpCode.AvalonEdit.Gui
foreach (FoldingMarginMarker m in markers) {
int visualColumn = m.VisualLine.GetVisualColumn(m.FoldingSection.StartOffset - m.VisualLine.FirstDocumentLine.Offset);
TextLine textLine = m.VisualLine.GetTextLine(visualColumn);
- double yPos = m.VisualLine.GetTextLineVisualTop(textLine) - TextView.VerticalOffset;
+ double yPos = m.VisualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.LineTop) - TextView.VerticalOffset;
yPos += (textLine.Height - m.DesiredSize.Height) / 2;
double xPos = (finalSize.Width - m.DesiredSize.Width) / 2;
m.Arrange(new Rect(new Point(xPos, yPos), m.DesiredSize));
@@ -213,7 +213,7 @@ namespace ICSharpCode.AvalonEdit.Gui
double GetVisualPos(VisualLine vl, TextLine tl)
{
- double pos = vl.GetTextLineVisualTop(tl) + tl.Height / 2 - TextView.VerticalOffset;
+ double pos = vl.GetTextLineVisualYPosition(tl, VisualYPosition.LineTop) + tl.Height / 2 - TextView.VerticalOffset;
return Math.Round(pos) + 0.5;
}
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/ITextViewConnect.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/ITextViewConnect.cs
index 0bd36ed0c6..d248488c1d 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/ITextViewConnect.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/ITextViewConnect.cs
@@ -11,7 +11,7 @@ namespace ICSharpCode.AvalonEdit.Gui
{
///
/// Allows s, s and
- /// to be notified when they are added or removed from a text view.
+ /// s to be notified when they are added or removed from a text view.
///
public interface ITextViewConnect
{
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/LineNumberMargin.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/LineNumberMargin.cs
index 100d50f72b..a8e95a1256 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/LineNumberMargin.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/LineNumberMargin.cs
@@ -175,7 +175,7 @@ namespace ICSharpCode.AvalonEdit.Gui
VisualLine vl = TextView.GetVisualLineFromVisualTop(pos.Y);
if (vl == null)
return SimpleSegment.Invalid;
- TextLine tl = vl.GetTextLineByVisualTop(pos.Y);
+ TextLine tl = vl.GetTextLineByVisualYPosition(pos.Y);
int visualStartColumn = vl.GetTextLineVisualStartColumn(tl);
int visualEndColumn = visualStartColumn + tl.Length;
int relStart = vl.FirstDocumentLine.Offset;
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextEditor.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextEditor.cs
index 1bad9f264d..ffcff93e7f 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextEditor.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextEditor.cs
@@ -625,6 +625,7 @@ namespace ICSharpCode.AvalonEdit
///
/// Gets/sets the encoding used when the file is saved.
///
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Encoding Encoding { get; set; }
///
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextView.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextView.cs
index 0d8f6bdd20..5f0cdebf6f 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextView.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextView.cs
@@ -82,7 +82,7 @@ namespace ICSharpCode.AvalonEdit.Gui
((TextView)dp).OnDocumentChanged((TextDocument)e.OldValue, (TextDocument)e.NewValue);
}
- double LineHeight {
+ internal double FontSize {
get {
return (double)GetValue(TextBlock.FontSizeProperty);
}
@@ -107,7 +107,7 @@ namespace ICSharpCode.AvalonEdit.Gui
ClearVisualLines();
if (newValue != null) {
TextDocumentWeakEventManager.Changing.AddListener(newValue, this);
- heightTree = new HeightTree(newValue, LineHeight + 3);
+ heightTree = new HeightTree(newValue, FontSize + 3);
formatter = TextFormatter.Create();
}
InvalidateMeasure(DispatcherPriority.Normal);
@@ -579,7 +579,7 @@ namespace ICSharpCode.AvalonEdit.Gui
{
return new GlobalTextRunProperties {
typeface = this.CreateTypeface(),
- fontRenderingEmSize = LineHeight,
+ fontRenderingEmSize = FontSize,
foregroundBrush = (Brush)GetValue(Control.ForegroundProperty),
cultureInfo = CultureInfo.CurrentCulture
};
@@ -606,7 +606,7 @@ namespace ICSharpCode.AvalonEdit.Gui
Debug.WriteLine("Building line " + documentLine.LineNumber);
- VisualLine visualLine = new VisualLine(documentLine);
+ VisualLine visualLine = new VisualLine(this, documentLine);
VisualLineTextSource textSource = new VisualLineTextSource(visualLine) {
Document = document,
GlobalTextRunProperties = globalTextRunProperties,
@@ -868,12 +868,12 @@ namespace ICSharpCode.AvalonEdit.Gui
void IScrollInfo.LineUp()
{
- ((IScrollInfo)this).SetVerticalOffset(scrollOffset.Y - LineHeight);
+ ((IScrollInfo)this).SetVerticalOffset(scrollOffset.Y - FontSize);
}
void IScrollInfo.LineDown()
{
- ((IScrollInfo)this).SetVerticalOffset(scrollOffset.Y + LineHeight);
+ ((IScrollInfo)this).SetVerticalOffset(scrollOffset.Y + FontSize);
}
void IScrollInfo.LineLeft()
@@ -909,14 +909,14 @@ namespace ICSharpCode.AvalonEdit.Gui
void IScrollInfo.MouseWheelUp()
{
((IScrollInfo)this).SetVerticalOffset(
- scrollOffset.Y - (SystemParameters.WheelScrollLines * LineHeight));
+ scrollOffset.Y - (SystemParameters.WheelScrollLines * FontSize));
OnScrollChange();
}
void IScrollInfo.MouseWheelDown()
{
((IScrollInfo)this).SetVerticalOffset(
- scrollOffset.Y + (SystemParameters.WheelScrollLines * LineHeight));
+ scrollOffset.Y + (SystemParameters.WheelScrollLines * FontSize));
OnScrollChange();
}
@@ -936,7 +936,7 @@ namespace ICSharpCode.AvalonEdit.Gui
double WideSpaceWidth {
get {
- return LineHeight / 2;
+ return FontSize / 2;
}
}
@@ -1116,6 +1116,30 @@ namespace ICSharpCode.AvalonEdit.Gui
}
#endregion
+ #region Visual Position <-> TextViewPosition
+ ///
+ /// Gets the visual position from a text view position.
+ ///
+ /// The text view position.
+ /// The mode how to retrieve the Y position.
+ /// The position in WPF device-independent pixels relative
+ /// to the top left corner of the document.
+ public Point GetVisualPosition(TextViewPosition position, VisualYPosition yPositionMode)
+ {
+ VerifyAccess();
+ if (this.Document == null)
+ throw new InvalidOperationException("There is no document assigned to the TextView");
+ DocumentLine documentLine = this.Document.GetLineByNumber(position.Line);
+ VisualLine visualLine = GetOrConstructVisualLine(documentLine);
+ int visualColumn = position.VisualColumn;
+ if (visualColumn < 0) {
+ int offset = documentLine.Offset + position.Column - 1;
+ visualColumn = visualLine.GetVisualColumn(offset - visualLine.FirstDocumentLine.Offset);
+ }
+ return visualLine.GetVisualPosition(visualColumn, yPositionMode);
+ }
+ #endregion
+
#region Service Provider
readonly ServiceContainer services = new ServiceContainer();
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/VisualLine.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/VisualLine.cs
index c718463efb..7b5e706583 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/VisualLine.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/VisualLine.cs
@@ -23,6 +23,7 @@ namespace ICSharpCode.AvalonEdit.Gui
///
public sealed class VisualLine
{
+ TextView textView;
List elements;
///
@@ -60,9 +61,11 @@ namespace ICSharpCode.AvalonEdit.Gui
///
public double VisualTop { get; internal set; }
- internal VisualLine(DocumentLine firstDocumentLine)
+ internal VisualLine(TextView textView, DocumentLine firstDocumentLine)
{
+ Debug.Assert(textView != null);
Debug.Assert(firstDocumentLine != null);
+ this.textView = textView;
this.FirstDocumentLine = firstDocumentLine;
}
@@ -223,18 +226,30 @@ namespace ICSharpCode.AvalonEdit.Gui
///
/// Distance in device-independent pixels
/// from the top of the document to the top of the specified text line.
- public double GetTextLineVisualTop(TextLine textLine)
+ public double GetTextLineVisualYPosition(TextLine textLine, VisualYPosition yPositionMode)
{
- if (!TextLines.Contains(textLine))
- throw new ArgumentException("textLine is not a line in this VisualLine");
+ if (textLine == null)
+ throw new ArgumentNullException("textLine");
double pos = VisualTop;
foreach (TextLine tl in TextLines) {
- if (tl == textLine)
- break;
- else
+ if (tl == textLine) {
+ switch (yPositionMode) {
+ case VisualYPosition.LineTop:
+ return pos;
+ case VisualYPosition.LineMiddle:
+ return pos + tl.Height / 2;
+ case VisualYPosition.LineBottom:
+ return pos + tl.Height;
+ case VisualYPosition.TextTop:
+ return pos + tl.Height - textView.FontSize;
+ default:
+ throw new ArgumentException("Invalid yPositionMode:" + yPositionMode);
+ }
+ } else {
pos += tl.Height;
+ }
}
- return pos;
+ throw new ArgumentException("textLine is not a line in this VisualLine");
}
///
@@ -257,7 +272,7 @@ namespace ICSharpCode.AvalonEdit.Gui
///
/// Gets a TextLine by the visual position.
///
- public TextLine GetTextLineByVisualTop(double visualTop)
+ public TextLine GetTextLineByVisualYPosition(double visualTop)
{
const double epsilon = 0.0001;
double pos = this.VisualTop;
@@ -274,11 +289,11 @@ namespace ICSharpCode.AvalonEdit.Gui
///
/// Position in device-independent pixels
/// relative to the top left of the document.
- public Point GetVisualPosition(int visualColumn)
+ public Point GetVisualPosition(int visualColumn, VisualYPosition yPositionMode)
{
TextLine textLine = GetTextLine(visualColumn);
double xPos = textLine.GetDistanceFromCharacterHit(new CharacterHit(visualColumn, 0));
- double yPos = GetTextLineVisualTop(textLine);
+ double yPos = GetTextLineVisualYPosition(textLine, yPositionMode);
return new Point(xPos, yPos);
}
@@ -287,7 +302,7 @@ namespace ICSharpCode.AvalonEdit.Gui
///
public int GetVisualColumn(Point point)
{
- TextLine textLine = GetTextLineByVisualTop(point.Y);
+ TextLine textLine = GetTextLineByVisualYPosition(point.Y);
CharacterHit ch = textLine.GetCharacterHitFromDistance(point.X);
return ch.FirstCharacterIndex + ch.TrailingLength;
}
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/VisualYPosition.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/VisualYPosition.cs
new file mode 100644
index 0000000000..ef20f53532
--- /dev/null
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/VisualYPosition.cs
@@ -0,0 +1,36 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+
+namespace ICSharpCode.AvalonEdit.Gui
+{
+ ///
+ /// An enum that specifies the possible Y positions that can be returned by VisualLine.GetVisualPosition.
+ ///
+ public enum VisualYPosition
+ {
+ ///
+ /// Returns the top of the TextLine.
+ ///
+ LineTop,
+ ///
+ /// Returns the top of the text. If the line contains inline UI elements larger than the text, TextTop
+ /// will be below LineTop.
+ ///
+ TextTop,
+ ///
+ /// Returns the bottom of the TextLine. This is the same as the bottom of the text (the text is always
+ /// aligned at the bottom border).
+ ///
+ LineBottom,
+ ///
+ /// The middle between LineTop and LineBottom.
+ ///
+ LineMiddle
+ }
+}
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs
index 9fdf3680f4..2039fcc516 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs
@@ -24,6 +24,7 @@ namespace ICSharpCode.AvalonEdit.Highlighting
readonly TextView textView;
readonly HighlightingRuleSet ruleSet;
DocumentHighlighter highlighter;
+ bool isInTextView;
///
/// Creates a new HighlightingColorizer instance.
@@ -53,25 +54,39 @@ namespace ICSharpCode.AvalonEdit.Highlighting
void OnDocumentChanged()
{
+ if (highlighter != null && isInTextView) {
+ textView.Services.RemoveService(typeof(DocumentHighlighter));
+ }
+
TextDocument document = textView.Document;
if (document != null)
highlighter = new TextViewDocumentHighlighter(this, document, ruleSet);
else
highlighter = null;
+
+ if (highlighter != null && isInTextView) {
+ textView.Services.AddService(typeof(DocumentHighlighter), highlighter);
+ }
}
///
protected override void OnAddToTextView(TextView textView)
{
base.OnAddToTextView(textView);
- textView.Services.AddService(typeof(DocumentHighlighter), highlighter);
+ isInTextView = true;
+ if (highlighter != null) {
+ textView.Services.AddService(typeof(DocumentHighlighter), highlighter);
+ }
}
///
protected override void OnRemoveFromTextView(TextView textView)
{
base.OnRemoveFromTextView(textView);
- textView.Services.RemoveService(typeof(DocumentHighlighter));
+ isInTextView = false;
+ if (highlighter != null) {
+ textView.Services.RemoveService(typeof(DocumentHighlighter));
+ }
}
int currentLineEndOffset;
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj
index 3b6994f759..367d7f2560 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj
@@ -59,6 +59,8 @@
3.5
+
+
3.5
@@ -71,6 +73,12 @@
Properties\GlobalAssemblyInfo.cs
+
+
+
+ CompletionWindow.xaml
+ Code
+
UndoStack.cs
@@ -209,6 +217,9 @@
+
+ VisualLine.cs
+
@@ -303,8 +314,10 @@
+
+
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Properties/CodeAnalysisDictionary.xml b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Properties/CodeAnalysisDictionary.xml
index da48eea79e..00a740e894 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Properties/CodeAnalysisDictionary.xml
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Properties/CodeAnalysisDictionary.xml
@@ -10,6 +10,8 @@
Colorizer
Renderer
Deletable
+
+ y
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/ExtensionMethods.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/ExtensionMethods.cs
index b52b151fd1..563efde47a 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/ExtensionMethods.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/ExtensionMethods.cs
@@ -19,6 +19,7 @@ namespace ICSharpCode.AvalonEdit.Utils
{
static class ExtensionMethods
{
+ #region Epsilon / IsClose
public const double Epsilon = 1e-8;
///
@@ -46,7 +47,9 @@ namespace ICSharpCode.AvalonEdit.Utils
{
return IsClose(d1.X, d2.X) && IsClose(d1.Y, d2.Y);
}
+ #endregion
+ #region CreateTypeface
///
/// Creates typeface from the framework element.
///
@@ -57,7 +60,9 @@ namespace ICSharpCode.AvalonEdit.Utils
(FontWeight)fe.GetValue(TextBlock.FontWeightProperty),
(FontStretch)fe.GetValue(TextBlock.FontStretchProperty));
}
+ #endregion
+ #region AddRange / Sequence
public static void AddRange(this ICollection collection, IEnumerable elements)
{
foreach (T e in elements)
@@ -71,7 +76,9 @@ namespace ICSharpCode.AvalonEdit.Utils
{
yield return value;
}
+ #endregion
+ #region XML reading
///
/// Gets the value of the attribute, or null if the attribute does not exist.
///
@@ -101,7 +108,9 @@ namespace ICSharpCode.AvalonEdit.Utils
else
return XmlConvert.ToBoolean(attributeValue);
}
+ #endregion
+ #region ISegment extensions
///
/// Gets the end offset of the segment.
///
@@ -141,5 +150,28 @@ namespace ICSharpCode.AvalonEdit.Utils
else
return new SimpleSegment(start, end - start);
}
+ #endregion
+
+ #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 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());
+ }
+ #endregion
}
}