Merge #280 - ClipboardRing, CurrentLineHighlighting, SelectionLength, OverstrikeMode, HideMouseCursorWhileTyping

This commit is contained in:
Daniel Grunwald 2014-01-31 18:25:27 +01:00
Родитель 93388d106b f0ddf3c3a0
Коммит ecb1c7a0b3
7 изменённых файлов: 308 добавлений и 5 удалений

Просмотреть файл

@ -47,7 +47,7 @@ namespace ICSharpCode.AvalonEdit.Editing
this.textView = textArea.TextView;
position = new TextViewPosition(1, 1, 0);
caretAdorner = new CaretLayer(textView);
caretAdorner = new CaretLayer(textArea);
textView.InsertLayer(caretAdorner, KnownLayer.Caret, LayerInsertionPosition.Replace);
textView.VisualLinesChanged += TextView_VisualLinesChanged;
textView.ScrollOffsetChanged += TextView_ScrollOffsetChanged;
@ -382,6 +382,29 @@ namespace ICSharpCode.AvalonEdit.Editing
lineBottom - lineTop);
}
Rect CalcCaretOverstrikeRectangle(VisualLine visualLine)
{
if (!visualColumnValid) {
RevalidateVisualColumn(visualLine);
}
TextLine textLine = visualLine.GetTextLine(position.VisualColumn, position.IsAtEndOfLine);
double xPos = visualLine.GetTextLineVisualXPosition(textLine, position.VisualColumn);
double lineTop = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.TextTop);
double lineBottom = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.TextBottom);
int currentPos = position.VisualColumn;
int nextPos = visualLine.GetNextCaretPosition(currentPos, LogicalDirection.Forward, CaretPositioningMode.Normal, true);
double charSize = Math.Abs(
visualLine.GetTextLineVisualXPosition(textLine, currentPos) -
visualLine.GetTextLineVisualXPosition(textLine, nextPos) );
return new Rect(xPos,
lineTop,
charSize,
lineBottom - lineTop);
}
/// <summary>
/// Returns the caret rectangle. The coordinate system is in device-independent pixels from the top of the document.
/// </summary>
@ -389,7 +412,8 @@ namespace ICSharpCode.AvalonEdit.Editing
{
if (textView != null && textView.Document != null) {
VisualLine visualLine = textView.GetOrConstructVisualLine(textView.Document.GetLineByNumber(position.Line));
return CalcCaretRectangle(visualLine);
return (this.textView.Options.AllowOverstrikeMode && this.textArea.OverstrikeMode)
? CalcCaretOverstrikeRectangle(visualLine) : CalcCaretRectangle(visualLine);
} else {
return Rect.Empty;
}
@ -444,7 +468,12 @@ namespace ICSharpCode.AvalonEdit.Editing
if (caretAdorner != null && textView != null) {
VisualLine visualLine = textView.GetVisualLine(position.Line);
if (visualLine != null) {
Rect caretRect = CalcCaretRectangle(visualLine);
Rect caretRect;
if (this.textView.Options.AllowOverstrikeMode && this.textArea.OverstrikeMode) {
caretRect = CalcCaretOverstrikeRectangle(visualLine);
} else {
caretRect = CalcCaretRectangle(visualLine);
}
// Create Win32 caret so that Windows knows where our managed caret is. This is necessary for
// features like 'Follow text editing' in the Windows Magnifier.
if (!hasWin32Caret) {

Просмотреть файл

@ -30,14 +30,17 @@ namespace ICSharpCode.AvalonEdit.Editing
{
sealed class CaretLayer : Layer
{
TextArea textArea;
bool isVisible;
Rect caretRectangle;
DispatcherTimer caretBlinkTimer = new DispatcherTimer();
bool blink;
public CaretLayer(TextView textView) : base(textView, KnownLayer.Caret)
public CaretLayer(TextArea textArea) : base(textArea.TextView, KnownLayer.Caret)
{
this.textArea = textArea;
this.IsHitTestVisible = false;
caretBlinkTimer.Tick += new EventHandler(caretBlinkTimer_Tick);
}
@ -90,6 +93,16 @@ namespace ICSharpCode.AvalonEdit.Editing
Brush caretBrush = this.CaretBrush;
if (caretBrush == null)
caretBrush = (Brush)textView.GetValue(TextBlock.ForegroundProperty);
if (this.textArea.Options.AllowOverstrikeMode && this.textArea.OverstrikeMode) {
SolidColorBrush scBrush = caretBrush as SolidColorBrush;
if (scBrush != null) {
Color brushColor = scBrush.Color;
Color newColor = Color.FromArgb(100, brushColor.R, brushColor.G, brushColor.B);
caretBrush = new SolidColorBrush(newColor);
}
}
Rect r = new Rect(caretRectangle.X - textView.HorizontalOffset,
caretRectangle.Y - textView.VerticalOffset,
caretRectangle.Width,

Просмотреть файл

@ -84,6 +84,8 @@ namespace ICSharpCode.AvalonEdit.Editing
caret = new Caret(this);
caret.PositionChanged += (sender, e) => RequestSelectionValidation();
caret.PositionChanged += CaretPositionChanged;
AttachTypingEvents();
ime = new ImeSupport(this);
leftMargins.CollectionChanged += leftMargins_CollectionChanged;
@ -574,6 +576,14 @@ namespace ICSharpCode.AvalonEdit.Editing
get { return caret; }
}
void CaretPositionChanged(object sender, EventArgs e)
{
if (textView == null)
return;
this.textView.HighlightedLine = this.Caret.Line;
}
ObservableCollection<UIElement> leftMargins = new ObservableCollection<UIElement>();
/// <summary>
@ -871,8 +881,11 @@ namespace ICSharpCode.AvalonEdit.Editing
if (!e.Handled) {
if (e.Text == "\n" || e.Text == "\r" || e.Text == "\r\n")
ReplaceSelectionWithNewLine();
else
else {
if (overstrikeMode && Selection.IsEmpty && Document.GetLineByNumber(Caret.Line).EndOffset > Caret.Offset)
Selection = Selection.Create(this, Caret.Offset, Caret.Offset+e.Text.Length);
ReplaceSelectionWithText(e.Text);
}
OnTextEntered(e);
caret.BringCaretToView();
}
@ -957,6 +970,17 @@ namespace ICSharpCode.AvalonEdit.Editing
protected override void OnPreviewKeyDown(KeyEventArgs e)
{
base.OnPreviewKeyDown(e);
if (!this.Options.AllowOverstrikeMode) {
this.overstrikeMode = false;
} else if (!e.Handled && e.Key == Key.Insert) {
this.overstrikeMode = !this.overstrikeMode;
this.caret.Show();
e.Handled = true;
return;
}
HideMouseCursor();
foreach (TextAreaStackedInputHandler h in stackedInputHandlers) {
if (e.Handled)
break;
@ -980,6 +1004,7 @@ namespace ICSharpCode.AvalonEdit.Editing
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
HideMouseCursor();
TextView.InvalidateCursorIfMouseWithinTextView();
}
@ -991,6 +1016,46 @@ namespace ICSharpCode.AvalonEdit.Editing
}
#endregion
#region Hide Mouse Cursor While Typing
bool isMouseCursorHidden;
void AttachTypingEvents() {
this.MouseEnter += delegate { ShowMouseCursor(); };
this.MouseLeave += delegate { ShowMouseCursor(); };
this.MouseMove += delegate { ShowMouseCursor(); };
this.TouchEnter += delegate { ShowMouseCursor(); };
this.TouchLeave += delegate { ShowMouseCursor(); };
this.TouchMove += delegate { ShowMouseCursor(); };
}
void ShowMouseCursor() {
if (this.isMouseCursorHidden) {
System.Windows.Forms.Cursor.Show();
this.isMouseCursorHidden = false;
}
}
void HideMouseCursor() {
if (Options.HideCursorWhileTyping && !this.isMouseCursorHidden && this.IsMouseOver) {
this.isMouseCursorHidden = true;
System.Windows.Forms.Cursor.Hide();
}
}
#endregion
#region Overstrike mode
bool overstrikeMode = false;
public bool OverstrikeMode
{
get { return this.overstrikeMode; }
}
#endregion
/// <inheritdoc/>
protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
{

Просмотреть файл

@ -245,6 +245,7 @@
<DependentUpon>IVisualLineTransformer.cs</DependentUpon>
</Compile>
<Compile Include="Rendering\ColumnRulerRenderer.cs" />
<Compile Include="Rendering\CurrentLineHighlightRenderer.cs" />
<Compile Include="Rendering\DefaultTextRunTypographyProperties.cs" />
<Compile Include="Rendering\DocumentColorizingTransformer.cs">
<DependentUpon>IVisualLineTransformer.cs</DependentUpon>

Просмотреть файл

@ -0,0 +1,103 @@
// 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.Diagnostics;
using System.Windows;
using System.Windows.Media;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Rendering;
namespace ICSharpCode.AvalonEdit.Rendering
{
sealed class CurrentLineHighlightRenderer : IBackgroundRenderer
{
#region Fields
int line;
TextView textView;
public static readonly Color DefaultBackground = Color.FromArgb(22, 20, 220, 224);
public static readonly Color DefaultBorder = Color.FromArgb(52, 0, 255, 110);
#endregion
#region Properties
public int Line {
get { return this.Line; }
set {
if (this.line != value) {
this.line = value;
this.textView.InvalidateLayer(this.Layer);
}
}
}
public KnownLayer Layer
{
get { return KnownLayer.Selection; }
}
public Brush BackgroundBrush {
get; set;
}
public Pen BorderPen {
get; set;
}
#endregion
public CurrentLineHighlightRenderer(TextView textView)
{
if (textView == null)
throw new ArgumentNullException("textView");
this.BorderPen = new Pen(new SolidColorBrush(DefaultBorder), 1);
this.BorderPen.Freeze();
this.BackgroundBrush = new SolidColorBrush(DefaultBackground);
this.BackgroundBrush.Freeze();
this.textView = textView;
this.textView.BackgroundRenderers.Add(this);
this.line = 0;
}
public void Draw(TextView textView, DrawingContext drawingContext)
{
if(!this.textView.Options.HighlightCurrentLine)
return;
BackgroundGeometryBuilder builder = new BackgroundGeometryBuilder();
builder.CornerRadius = 1;
builder.AlignToMiddleOfPixels = true;
var visualLine = this.textView.GetVisualLine(line);
if(visualLine == null) return;
var textViewPos = visualLine.GetTextViewPosition(0);
if(textViewPos == null) return;
var position = this.textView.GetVisualPosition(textViewPos, VisualYPosition.LineTop);
if(position == null) return;
var lineWidth = this.textView.ActualWidth;
var lineHeigth = visualLine.Height;
var linePosX = position.X;
var linePosY = position.Y - this.textView.ScrollOffset.Y;
builder.AddRectangle(textView, new Rect(linePosX, linePosY, lineWidth, lineHeigth));
Geometry geometry = builder.CreateGeometry();
if (geometry != null) {
drawingContext.DrawGeometry(this.BackgroundBrush, this.BorderPen, geometry);
}
}
}
}

Просмотреть файл

@ -57,6 +57,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
}
ColumnRulerRenderer columnRulerRenderer;
CurrentLineHighlightRenderer currentLineHighlighRenderer;
/// <summary>
/// Creates a new TextView instance.
@ -69,6 +70,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
lineTransformers = new ObserveAddRemoveCollection<IVisualLineTransformer>(LineTransformer_Added, LineTransformer_Removed);
backgroundRenderers = new ObserveAddRemoveCollection<IBackgroundRenderer>(BackgroundRenderer_Added, BackgroundRenderer_Removed);
columnRulerRenderer = new ColumnRulerRenderer(this);
currentLineHighlighRenderer = new CurrentLineHighlightRenderer(this);
this.Options = new TextEditorOptions();
Debug.Assert(singleCharacterElementGenerator != null); // assert that the option change created the builtin element generators
@ -2009,6 +2011,12 @@ namespace ICSharpCode.AvalonEdit.Rendering
if (e.Property == ColumnRulerPenProperty) {
columnRulerRenderer.SetRuler(this.Options.ColumnRulerPosition, this.ColumnRulerPen);
}
if (e.Property == CurrentLineBorderProperty) {
currentLineHighlighRenderer.BorderPen = this.CurrentLineBorder;
}
if (e.Property == CurrentLineBackgroundProperty) {
currentLineHighlighRenderer.BackgroundBrush = this.CurrentLineBackground;
}
}
/// <summary>
@ -2034,5 +2042,41 @@ namespace ICSharpCode.AvalonEdit.Rendering
get { return (Pen)GetValue(ColumnRulerPenProperty); }
set { SetValue(ColumnRulerPenProperty, value); }
}
/// <summary>
/// The <see cref="CurrentLineBackground"/> property.
/// </summary>
public static readonly DependencyProperty CurrentLineBackgroundProperty =
DependencyProperty.Register("CurrentLineBackground", typeof(Brush), typeof(TextView));
/// <summary>
/// Gets/Sets the background brush used by current line highlighter.
/// </summary>
public Brush CurrentLineBackground {
get { return (Brush)GetValue(CurrentLineBackgroundProperty); }
set { SetValue(CurrentLineBackgroundProperty, value); }
}
/// <summary>
/// The <see cref="CurrentLineBorder"/> property.
/// </summary>
public static readonly DependencyProperty CurrentLineBorderProperty =
DependencyProperty.Register("CurrentLineBorder", typeof(Pen), typeof(TextView));
/// <summary>
/// Gets/Sets the background brush used for the current line.
/// </summary>
public Pen CurrentLineBorder {
get { return (Pen)GetValue(CurrentLineBorderProperty); }
set { SetValue(CurrentLineBorderProperty, value); }
}
/// <summary>
/// Gets/Sets highlighted line number.
/// </summary>
public int HighlightedLine {
get { return this.currentLineHighlighRenderer.Line; }
set { this.currentLineHighlighRenderer.Line = value; }
}
}
}

Просмотреть файл

@ -445,5 +445,53 @@ namespace ICSharpCode.AvalonEdit
}
}
}
bool highlightCurrentLine = false;
/// <summary>
/// Gets/Sets if current line should be shown.
/// </summary>
[DefaultValue(false)]
public virtual bool HighlightCurrentLine {
get { return highlightCurrentLine; }
set {
if (highlightCurrentLine != value) {
highlightCurrentLine = value;
OnPropertyChanged("HighlightCurrentLine");
}
}
}
bool hideCursorWhileTyping = true;
[DefaultValue(true)]
/// <summary>
/// Gets/Sets if mouse cursor should be shown when user is typing
/// </summary>
public bool HideCursorWhileTyping {
get { return hideCursorWhileTyping; }
set {
if (hideCursorWhileTyping != value) {
hideCursorWhileTyping = value;
OnPropertyChanged("HideCursorWhileTyping");
}
}
}
bool allowOverstrikeMode = false;
[DefaultValue(false)]
/// <summary>
/// Gets/Sets if overstrike mode is enabled to use
/// </summary>
public bool AllowOverstrikeMode {
get { return allowOverstrikeMode; }
set {
if (allowOverstrikeMode != value) {
allowOverstrikeMode = value;
OnPropertyChanged("AllowOverstrikeMode");
}
}
}
}
}