void Initialize() { _bufferGraph = _factoryService.BufferGraphFactoryService.CreateBufferGraph(this.TextViewModel.VisualBuffer); _editorFormatMap = _factoryService.EditorFormatMapService.GetEditorFormatMap(this); _baseLayer = new ViewStack(_factoryService.OrderedViewLayerDefinitions, this); _overlayLayer = new ViewStack(_factoryService.OrderedOverlayLayerDefinitions, this, isOverlayLayer: true); // Create selection and make sure it's created before the caret as the caret relies on the selection being // available in its constructor _selection = new SkiaTextSelection(this, _editorFormatMap, _factoryService.GuardedOperations); // Create caret _caretElement = new SkiaTextCaret(this, _selection, _factoryService.SmartIndentationService, _editorFormatMap, _factoryService.GuardedOperations); }
/// <summary> /// Calculate the selection rectangles that should be drawn on an ITextViewLine. /// </summary> /// <param name="line">The line on which the selection rectangles are to be calculated.</param> /// <param name="span">The span of the selection on that line.</param> /// <param name="selectionEnd">The end of the entire selection.</param> /// <param name="isBoxSelection">Is this a box selection?</param> /// <param name="isVirtualSpaceEnabled">Is virtual space turned on?</param> /// <remarks>internal for testability</remarks> internal static IList <Tuple <double, double> > CalculateVisualOverlapsForLine(ITextViewLine line, VirtualSnapshotSpan span, SnapshotPoint selectionEnd, bool isBoxSelection, bool isVirtualSpaceEnabled) { VirtualSnapshotPoint start = span.Start; VirtualSnapshotPoint end = span.End; // if the requested start and ending points are the same, then simply return a caret wide bound on the line if (start == end) { double xLeft = SkiaTextCaret.GetXCoordinateFromVirtualBufferPosition(line, start); return(new FrugalList <Tuple <double, double> > () { new Tuple <double, double> (xLeft, xLeft + 2) }); //TODO: SystemParameters.CaretWidth) }; } //If box selection is on, then every line is the "last" line of the selection. bool isLastLineOfSelection = isBoxSelection || (selectionEnd < line.EndIncludingLineBreak) || //Selection ends before the end of line ((line.LineBreakLength == 0) && line.IsLastTextViewLineForSnapshotLine); //Or this is the last line. IList <Tuple <double, double> > leftRightPairs; //Draw the appropriate bits of the selection for virtual space. if (start.Position.Position == line.End.Position) { //The start is at (or beyond) the end of the line (therefore nothing inside the line is selected). double xStart = SkiaTextCaret.GetXCoordinateFromVirtualBufferPosition(line, start); double xEnd; if (isLastLineOfSelection) { //Selection ends on this line as well ... draw a rectangle between them. xEnd = SkiaTextCaret.GetXCoordinateFromVirtualBufferPosition(line, end); } else { //Selection ends on a subsequent line. Show things differently when virtual space is turned on. xEnd = isVirtualSpaceEnabled ? double.MaxValue : (xStart + line.EndOfLineWidth); } leftRightPairs = new FrugalList <Tuple <double, double> > (); if (xEnd > xStart) { leftRightPairs.Add(new Tuple <double, double> (xStart, xEnd)); } } else { //Add the bounds for the text in the line's interior. var bounds = line.GetNormalizedTextBounds(new SnapshotSpan(start.Position, end.Position)); leftRightPairs = new List <Tuple <double, double> > (bounds.Count + 1); foreach (var bound in bounds) { leftRightPairs.Add(new Tuple <double, double> (bound.Left, bound.Right)); } double xEnd = double.MinValue; if (isLastLineOfSelection) { if (end.IsInVirtualSpace) { xEnd = SkiaTextCaret.GetXCoordinateFromVirtualBufferPosition(line, end); } } else if (isVirtualSpaceEnabled) { xEnd = double.MaxValue; } double xStart = line.TextRight; if (xEnd > xStart) { if ((leftRightPairs.Count > 0) && (leftRightPairs [leftRightPairs.Count - 1].Item2 >= xStart)) { xStart = leftRightPairs [leftRightPairs.Count - 1].Item1; leftRightPairs.RemoveAt(leftRightPairs.Count - 1); } leftRightPairs.Add(new Tuple <double, double> (xStart, xEnd)); } } return(leftRightPairs); }