diff options
| author | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2019-04-09 01:47:48 +0300 |
|---|---|---|
| committer | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2019-04-09 01:47:48 +0300 |
| commit | 080f1697e97e13461ec6df4d31c8924d01257a1b (patch) | |
| tree | b1fe0285de7bc9bc52e9e2195e66fe022bf8f5b3 /Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Editing/LineNumberMargin.cs | |
| parent | 1608e69a417bc5e40a607c3958c4a60f19f66f1a (diff) | |
| download | Tango-080f1697e97e13461ec6df4d31c8924d01257a1b.tar.gz Tango-080f1697e97e13461ec6df4d31c8924d01257a1b.zip | |
MERGE
Diffstat (limited to 'Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Editing/LineNumberMargin.cs')
| -rw-r--r-- | Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Editing/LineNumberMargin.cs | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Editing/LineNumberMargin.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Editing/LineNumberMargin.cs new file mode 100644 index 000000000..3da96b08c --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Editing/LineNumberMargin.cs @@ -0,0 +1,243 @@ +// 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.ComponentModel; +using System.Globalization; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.TextFormatting; + +using Tango.Scripting.Editors.Document; +using Tango.Scripting.Editors.Rendering; +using Tango.Scripting.Editors.Utils; + +namespace Tango.Scripting.Editors.Editing +{ + /// <summary> + /// Margin showing line numbers. + /// </summary> + public class LineNumberMargin : AbstractMargin, IWeakEventListener + { + public Brush Foreground + { + get { return (Brush)GetValue(ForegroundProperty); } + set { SetValue(ForegroundProperty, value); } + } + public static readonly DependencyProperty ForegroundProperty = + DependencyProperty.Register("Foreground", typeof(Brush), typeof(LineNumberMargin), new PropertyMetadata(Brushes.Gray)); + + + + static LineNumberMargin() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(LineNumberMargin), + new FrameworkPropertyMetadata(typeof(LineNumberMargin))); + } + + TextArea textArea; + + Typeface typeface; + double emSize; + + /// <inheritdoc/> + protected override Size MeasureOverride(Size availableSize) + { + typeface = this.CreateTypeface(); + emSize = (double)GetValue(TextBlock.FontSizeProperty); + + FormattedText text = TextFormatterFactory.CreateFormattedText( + this, + new string('9', maxLineNumberLength), + typeface, + emSize, + Foreground + ); + return new Size(text.Width, 0); + } + + /// <inheritdoc/> + protected override void OnRender(DrawingContext drawingContext) + { + TextView textView = this.TextView; + Size renderSize = this.RenderSize; + if (textView != null && textView.VisualLinesValid) { + var foreground = Foreground; + foreach (VisualLine line in textView.VisualLines) { + int lineNumber = line.FirstDocumentLine.LineNumber; + FormattedText text = TextFormatterFactory.CreateFormattedText( + this, + lineNumber.ToString(CultureInfo.CurrentCulture), + typeface, emSize, foreground + ); + double y = line.GetTextLineVisualYPosition(line.TextLines[0], VisualYPosition.TextTop); + drawingContext.DrawText(text, new Point((renderSize.Width / 2) - text.Width + 5, y - textView.VerticalOffset)); + } + } + } + + /// <inheritdoc/> + protected override void OnTextViewChanged(TextView oldTextView, TextView newTextView) + { + if (oldTextView != null) { + oldTextView.VisualLinesChanged -= TextViewVisualLinesChanged; + } + base.OnTextViewChanged(oldTextView, newTextView); + if (newTextView != null) { + newTextView.VisualLinesChanged += TextViewVisualLinesChanged; + + // find the text area belonging to the new text view + textArea = newTextView.Services.GetService(typeof(TextArea)) as TextArea; + } else { + textArea = null; + } + InvalidateVisual(); + } + + /// <inheritdoc/> + protected override void OnDocumentChanged(TextDocument oldDocument, TextDocument newDocument) + { + if (oldDocument != null) { + PropertyChangedEventManager.RemoveListener(oldDocument, this, "LineCount"); + } + base.OnDocumentChanged(oldDocument, newDocument); + if (newDocument != null) { + PropertyChangedEventManager.AddListener(newDocument, this, "LineCount"); + } + OnDocumentLineCountChanged(); + } + + /// <inheritdoc cref="IWeakEventListener.ReceiveWeakEvent"/> + protected virtual bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e) + { + if (managerType == typeof(PropertyChangedEventManager)) { + OnDocumentLineCountChanged(); + return true; + } + return false; + } + + bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e) + { + return ReceiveWeakEvent(managerType, sender, e); + } + + int maxLineNumberLength = 1; + + void OnDocumentLineCountChanged() + { + int documentLineCount = Document != null ? Document.LineCount : 1; + int newLength = documentLineCount.ToString(CultureInfo.CurrentCulture).Length; + + // The margin looks too small when there is only one digit, so always reserve space for + // at least two digits + if (newLength < 2) + newLength = 2; + + if (newLength != maxLineNumberLength) { + maxLineNumberLength = newLength; + InvalidateMeasure(); + } + } + + void TextViewVisualLinesChanged(object sender, EventArgs e) + { + InvalidateVisual(); + } + + AnchorSegment selectionStart; + bool selecting; + + /// <inheritdoc/> + protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) + { + base.OnMouseLeftButtonDown(e); + if (!e.Handled && TextView != null && textArea != null) { + e.Handled = true; + textArea.Focus(); + + SimpleSegment currentSeg = GetTextLineSegment(e); + if (currentSeg == SimpleSegment.Invalid) + return; + textArea.Caret.Offset = currentSeg.Offset + currentSeg.Length; + if (CaptureMouse()) { + selecting = true; + selectionStart = new AnchorSegment(Document, currentSeg.Offset, currentSeg.Length); + if ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift) { + SimpleSelection simpleSelection = textArea.Selection as SimpleSelection; + if (simpleSelection != null) + selectionStart = new AnchorSegment(Document, simpleSelection.SurroundingSegment); + } + textArea.Selection = Selection.Create(textArea, selectionStart); + if ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift) { + ExtendSelection(currentSeg); + } + } + } + } + + SimpleSegment GetTextLineSegment(MouseEventArgs e) + { + Point pos = e.GetPosition(TextView); + pos.X = 0; + pos.Y += TextView.VerticalOffset; + VisualLine vl = TextView.GetVisualLineFromVisualTop(pos.Y); + if (vl == null) + return SimpleSegment.Invalid; + TextLine tl = vl.GetTextLineByVisualYPosition(pos.Y); + int visualStartColumn = vl.GetTextLineVisualStartColumn(tl); + int visualEndColumn = visualStartColumn + tl.Length; + int relStart = vl.FirstDocumentLine.Offset; + int startOffset = vl.GetRelativeOffset(visualStartColumn) + relStart; + int endOffset = vl.GetRelativeOffset(visualEndColumn) + relStart; + if (endOffset == vl.LastDocumentLine.Offset + vl.LastDocumentLine.Length) + endOffset += vl.LastDocumentLine.DelimiterLength; + return new SimpleSegment(startOffset, endOffset - startOffset); + } + + void ExtendSelection(SimpleSegment currentSeg) + { + if (currentSeg.Offset < selectionStart.Offset) { + textArea.Caret.Offset = currentSeg.Offset; + textArea.Selection = Selection.Create(textArea, currentSeg.Offset, selectionStart.Offset + selectionStart.Length); + } else { + textArea.Caret.Offset = currentSeg.Offset + currentSeg.Length; + textArea.Selection = Selection.Create(textArea, selectionStart.Offset, currentSeg.Offset + currentSeg.Length); + } + } + + /// <inheritdoc/> + protected override void OnMouseMove(MouseEventArgs e) + { + if (selecting && textArea != null && TextView != null) { + e.Handled = true; + SimpleSegment currentSeg = GetTextLineSegment(e); + if (currentSeg == SimpleSegment.Invalid) + return; + ExtendSelection(currentSeg); + } + base.OnMouseMove(e); + } + + /// <inheritdoc/> + protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) + { + if (selecting) { + selecting = false; + selectionStart = null; + ReleaseMouseCapture(); + e.Handled = true; + } + base.OnMouseLeftButtonUp(e); + } + + /// <inheritdoc/> + protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters) + { + // accept clicks even when clicking on the background + return new PointHitTestResult(this, hitTestParameters.HitPoint); + } + } +} |
