protected override void OnRender(DrawingContext drawingContext) { Debug.Print("DiffControl OnRender"); #if DEBUG MeasureRendeTime(); #endif // Fill background drawingContext.DrawRectangle(AppSettings.FullMatchBackground, null, new Rect(0, 0, this.ActualWidth, this.ActualHeight)); if (Lines.Count == 0) { return; } typeface = new Typeface(this.FontFamily, this.FontStyle, this.FontWeight, this.FontStretch); Matrix m = PresentationSource.FromVisual(this).CompositionTarget.TransformToDevice; dpiScale = 1 / m.M11; TextUtils.CreateGlyphRun("W", typeface, this.FontSize, dpiScale, out characterWidth); characterHeight = Math.Ceiling(TextUtils.FontHeight(typeface, this.FontSize, dpiScale) / dpiScale) * dpiScale; Brush activeDiffBrush = new SolidColorBrush(Color.FromRgb(220, 220, 220)); activeDiffBrush.Freeze(); Pen borderPen = new Pen(SystemColors.ScrollBarBrush, RoundToWholePixels(1)); borderPen.Freeze(); GuidelineSet borderGuide = CreateGuidelineSet(borderPen); textMargin = RoundToWholePixels(4); lineNumberMargin = RoundToWholePixels(characterWidth * Lines.Count.ToString().Length) + (2 * textMargin) + borderPen.Thickness; VisibleLines = (int)(ActualHeight / characterHeight + 1); MaxVerialcalScroll = Lines.Count - VisibleLines + 1; drawingContext.DrawRectangle(SystemColors.ControlBrush, null, new Rect(0, 0, lineNumberMargin, this.ActualHeight)); for (int i = 0; i < VisibleLines; i++) { int lineIndex = i + VerticalOffset; if (lineIndex >= Lines.Count) { break; } Line line = Lines[lineIndex]; // Line Y offset drawingContext.PushTransform(new TranslateTransform(0, characterHeight * i)); { // Draw line number SolidColorBrush lineNumberColor = SystemColors.ControlDarkBrush; if (lineIndex >= CurrentDiff && lineIndex < CurrentDiff + CurrentDiffLength && !Edited) { lineNumberColor = SystemColors.ControlDarkDarkBrush; drawingContext.DrawRectangle(activeDiffBrush, null, new Rect(0, 0, lineNumberMargin, characterHeight)); } // Draw line background if (line.Type != TextState.FullMatch) { drawingContext.DrawRectangle(line.BackgroundBrush, null, new Rect(lineNumberMargin, 0, Math.Max(this.ActualWidth - lineNumberMargin, 0), characterHeight)); } if (line.LineIndex != null) { GlyphRun rowNumberRun = line.GetRenderedLineIndexText(typeface, this.FontSize, dpiScale, out double rowNumberWidth); drawingContext.PushTransform(new TranslateTransform(lineNumberMargin - rowNumberWidth - textMargin - borderPen.Thickness, 0)); drawingContext.DrawGlyphRun(lineNumberColor, rowNumberRun); drawingContext.Pop(); } // Text clipping rect drawingContext.PushClip(new RectangleGeometry(new Rect(lineNumberMargin + textMargin, 0, Math.Max(ActualWidth - lineNumberMargin - textMargin * 2, 0), ActualHeight))); { // Line X offset drawingContext.PushTransform(new TranslateTransform(lineNumberMargin + textMargin - HorizontalOffset, 0)); { // Draw line if (line.Text != "") { double nextPosition = 0; foreach (TextSegment textSegment in line.TextSegments) { drawingContext.PushTransform(new TranslateTransform(nextPosition, 0)); GlyphRun segmentRun = textSegment.GetRenderedText(typeface, this.FontSize, dpiScale, AppSettings.ShowWhiteSpaceCharacters, AppSettings.TabSize, out double runWidth); if (nextPosition - HorizontalOffset < ActualWidth && nextPosition + runWidth - HorizontalOffset > 0) { if (line.Type != textSegment.Type && AppSettings.ShowLineChanges) { drawingContext.DrawRectangle(textSegment.BackgroundBrush, null, new Rect(nextPosition == 0 ? -textMargin : 0, 0, runWidth + (nextPosition == 0 ? textMargin : 0), characterHeight)); } drawingContext.DrawGlyphRun(AppSettings.ShowLineChanges ? textSegment.ForegroundBrush : line.ForegroundBrush, segmentRun); } nextPosition += runWidth; drawingContext.Pop(); } maxTextwidth = Math.Max(maxTextwidth, nextPosition); } // Draw cursor if (EditMode && this.IsFocused && cursorLine == lineIndex && cursorBlink) { drawingContext.DrawRectangle(Brushes.Black, null, new Rect(CharacterPosition(lineIndex, cursorCharacter), 0, RoundToWholePixels(1), characterHeight)); } } drawingContext.Pop(); // Line X offset } drawingContext.Pop(); // Text clipping rect // Text area clipping rect drawingContext.PushClip(new RectangleGeometry(new Rect(lineNumberMargin, 0, Math.Max(ActualWidth - lineNumberMargin, 0), ActualHeight))); { // Line X offset 2 drawingContext.PushTransform(new TranslateTransform(lineNumberMargin + textMargin - HorizontalOffset, 0)); { // Draw selection if (Selection != null && lineIndex >= Selection.TopLine && lineIndex <= Selection.BottomLine) { Rect selectionRect = new Rect(0 - textMargin + HorizontalOffset, 0, this.ActualWidth + HorizontalOffset, characterHeight); if (Selection.TopLine == lineIndex && Selection.TopCharacter > 0) { selectionRect.X = Math.Max(0, CharacterPosition(lineIndex, Selection.TopCharacter)); } if (Selection.BottomLine == lineIndex) { selectionRect.Width = Math.Max(0, CharacterPosition(lineIndex, Selection.BottomCharacter) - selectionRect.X); } drawingContext.DrawRectangle(AppSettings.SelectionBackground, null, selectionRect); } } drawingContext.Pop(); // Line X offset 2 } drawingContext.Pop(); // Text area clipping rect } drawingContext.Pop(); // Line Y offset } // Draw line number border drawingContext.PushGuidelineSet(borderGuide); { drawingContext.DrawLine(borderPen, new Point(lineNumberMargin, -1), new Point(lineNumberMargin, this.ActualHeight)); } drawingContext.Pop(); TextAreaWidth = (int)(ActualWidth - lineNumberMargin - (textMargin * 2)); MaxHorizontalScroll = (int)(maxTextwidth - TextAreaWidth + textMargin); #if DEBUG ReportRenderTime(); #endif }