Merge #280 - ClipboardRing, CurrentLineHighlighting, SelectionLength, OverstrikeMode, HideMouseCursorWhileTyping
This commit is contained in:
Коммит
ecb1c7a0b3
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче