/// <summary> /// Gets the wrapped line associated with this buffer position. /// </summary> /// <param name="bufferPosition">The buffer position.</param> /// <param name="displayContext">The display context.</param> /// <param name="layout">The layout.</param> /// <param name="wrappedLineIndex">Index of the wrapped line.</param> /// <returns></returns> public static LayoutLine GetWrappedLine( this TextPosition bufferPosition, IDisplayContext displayContext, out Layout layout, out int wrappedLineIndex) { // Get the layout and text associated with the line. LineBuffer lineBuffer = displayContext.LineBuffer; int lineIndex = bufferPosition.LinePosition.GetLineIndex(lineBuffer); string text = lineBuffer.GetLineText(lineIndex); layout = displayContext.Renderer.GetLineLayout( lineIndex, LineContexts.Unformatted); // Get the wrapped line associated with this character position. int characterIndex = bufferPosition.GetCharacterIndex(lineBuffer); int unicodeIndex = PangoUtility.TranslateStringToPangoIndex( text, characterIndex); int x; layout.IndexToLineX(unicodeIndex, false, out wrappedLineIndex, out x); // Return the resulting line. return(layout.Lines[wrappedLineIndex]); }
/// <summary> /// Gets the line X coordinates from either the state if we have one /// or calculate it from the buffer position's X coordinate. /// </summary> /// <param name="controller">The action context.</param> /// <param name="wrappedLine">The wrapped line.</param> /// <param name="position">The position.</param> /// <returns></returns> private static int GetLineX( EditorViewController controller, LayoutLine wrappedLine, TextPosition position) { int lineX; var state = controller.States.Get <VerticalMovementActionState>(); if (state == null) { // Calculate the line state from the caret position. The cursor // is always to the left of the character unless we're at the // end, and then it's considered trailing of the previous // character. LineBuffer lineBuffer = controller.DisplayContext.LineBuffer; int lineIndex = position.LinePosition.GetLineIndex(lineBuffer.LineCount); string lineText = lineBuffer.GetLineText(lineIndex); int characterIndex = position.CharacterPosition.GetCharacterIndex(lineText); bool trailing = false; if (characterIndex == lineText.Length && lineText.Length > 0) { characterIndex--; trailing = true; } // Because Pango works with UTF-8-based indexes, we need to // convert the C# character index into that index to properly // identify the character. characterIndex = NormalizeEmptyStrings(lineText, characterIndex); int unicodeIndex = PangoUtility.TranslateStringToPangoIndex( lineText, characterIndex); lineX = wrappedLine.IndexToX(unicodeIndex, trailing); // We need the line's style since it may have left passing // which will change our columns. LineBlockStyle style = controller.DisplayContext.Renderer.GetLineStyle( lineIndex, LineContexts.CurrentLine); var pixelPadding = (int)style.Padding.Left.GetValueOrDefault(0); lineX += Units.FromPixels(pixelPadding); // Save a new state into the states. state = new VerticalMovementActionState(lineX); controller.States.Add(state); } else { // Get the line coordinate from the state. lineX = state.LayoutLineX; } return(lineX); }
/// <summary> /// Get the rectangle position of the given index. /// </summary> /// <param name="layout">The layout.</param> /// <param name="stringIndex">Index of the string.</param> /// <returns></returns> public static Rectangle TranslatedIndexToPos( this Layout layout, int stringIndex) { int pangoIndex = PangoUtility.TranslateStringToPangoIndex( layout.Text, stringIndex); Rectangle translatedIndexToPos = layout.IndexToPos(pangoIndex); return(translatedIndexToPos); }
/// <summary> /// Gets the string index for an X coordinate. /// </summary> /// <param name="layoutLine">The layout line.</param> /// <param name="stringIndex">Index of the string.</param> /// <param name="trailing">if set to <c>true</c> [trailing].</param> /// <returns></returns> public static int TranslatedIndexToX( this LayoutLine layoutLine, int stringIndex, bool trailing) { int pangoIndex = PangoUtility.TranslateStringToPangoIndex( layoutLine.Layout.Text, stringIndex); return(layoutLine.IndexToX(pangoIndex, trailing)); }
/// <summary> /// Gets the cursor position inside the layout. /// </summary> /// <param name="layout">The layout.</param> /// <param name="stringIndex">The string index into the layout text.</param> /// <param name="strongPosition">The resulting strong position.</param> /// <param name="weakPosition">The resulting weak position.</param> public static void GetTranslatedCursorPos( this Layout layout, int stringIndex, out Rectangle strongPosition, out Rectangle weakPosition) { int pangoIndex = PangoUtility.TranslateStringToPangoIndex( layout.Text, stringIndex); layout.GetCursorPos(pangoIndex, out strongPosition, out weakPosition); }
public void ToPangoOnEndOfSimpleString() { // Arrange const int stringIndex = 6; const string text = "simple"; // Act int pangoIndex = PangoUtility.TranslateStringToPangoIndex(text, stringIndex); // Assert Assert.AreEqual(6, pangoIndex); }
public void ToPangoOnEmptyString() { // Arrange const int stringIndex = 0; const string text = ""; // Act int pangoIndex = PangoUtility.TranslateStringToPangoIndex(text, stringIndex); // Assert Assert.AreEqual(0, pangoIndex); }
public void ToPangoOnBeginningOfTwoByteString() { // Arrange const int stringIndex = 0; const string text = "éâäàçê"; // Act int pangoIndex = PangoUtility.TranslateStringToPangoIndex(text, stringIndex); // Assert Assert.AreEqual(0, pangoIndex); }
/// <summary> /// Gets the line X coordinate for a given index. /// </summary> /// <param name="layout">The layout.</param> /// <param name="stringIndex">The string index of the string.</param> /// <param name="trailing">if set to <c>true</c> the position is trailing the glyph.</param> /// <param name="line">The resulting logical line in the layout.</param> /// <param name="x">The resulting x coordinate (in Pango units) in the layout.</param> public static void TranslatedIndexToLineX( this Layout layout, int stringIndex, bool trailing, out int line, out int x) { int pangoIndex = PangoUtility.TranslateStringToPangoIndex( layout.Text, stringIndex); layout.IndexToLineX(pangoIndex, trailing, out line, out x); }
/// <summary> /// Gets the X ranges from the given string indexes. /// </summary> /// <param name="layoutLine">The layout line.</param> /// <param name="startStringIndex">Start index of the string.</param> /// <param name="endStringIndex">End index of the string.</param> /// <param name="ranges">The ranges.</param> public static void GetTranslatedXRanges( this LayoutLine layoutLine, int startStringIndex, int endStringIndex, out int[][] ranges) { int startPangoIndex = PangoUtility.TranslateStringToPangoIndex( layoutLine.Layout.Text, startStringIndex); int endPangoIndex = PangoUtility.TranslateStringToPangoIndex( layoutLine.Layout.Text, endStringIndex); layoutLine.GetXRanges(startPangoIndex, endPangoIndex, out ranges); }
public void ToPangoOnBeyondTwoByteString() { // Arrange const int stringIndex = 7; const string text = "éâäàçê"; // Act var exception = Assert.Throws <ArgumentOutOfRangeException>( () => PangoUtility.TranslateStringToPangoIndex(text, stringIndex)); // Assert Assert.AreEqual( "Provided index (7) cannot be greater than the length of the text (6).\r\nParameter name: stringIndex", exception.Message); }
public static void Up(EditorViewController controller) { // Extract a number of useful variable for this method. IDisplayContext displayContext = controller.DisplayContext; TextPosition position = displayContext.Caret.Position; EditorViewRenderer buffer = displayContext.Renderer; // Figure out the layout and wrapped line we are currently on. Layout layout; int wrappedLineIndex; LayoutLine wrappedLine = position.GetWrappedLine( displayContext, out layout, out wrappedLineIndex); // Figure out the X coordinate of the line. If there is an action context, // use that. Otherwise, calculate it from the character index of the position. int lineX = GetLineX(controller, wrappedLine, position); // Figure out which wrapped line we'll be moving the caret to. LinePosition linePosition = position.LinePosition; int lineIndex = linePosition.GetLineIndex(buffer.LineBuffer); if (wrappedLineIndex == 0) { // If we are the last line in the buffer, just do nothing. if (linePosition == 0) { return; } // Move to the next line. lineIndex--; layout = buffer.GetLineLayout(lineIndex, LineContexts.None); wrappedLineIndex = layout.LineCount - 1; wrappedLine = layout.Lines[wrappedLineIndex]; } else { // Just move down in the layout. wrappedLineIndex--; wrappedLine = layout.Lines[wrappedLineIndex]; } // Adjust the X coordinate for the current line. lineX -= GetLeftStylePaddingPango(controller, lineIndex); // The wrapped line has the current wrapped line, so use the lineX // to figure out which character to use. int trailing; int unicodeIndex; wrappedLine.XToIndex(lineX, out unicodeIndex, out trailing); // Calculate the character position, but we have to map UTF-8 // characters because Pango uses that instead of C# strings. string lineText = controller.DisplayContext.LineBuffer.GetLineText(lineIndex); unicodeIndex = NormalizeEmptyStrings(lineText, unicodeIndex); int characterIndex = PangoUtility.TranslateStringToPangoIndex( lineText, unicodeIndex); if (lineText.Length > 0 && trailing > 0) { characterIndex++; } // Draw the new location of the caret. var caretPosition = new TextPosition(lineIndex, characterIndex); displayContext.ScrollToCaret(caretPosition); }
/// <summary> /// Converts the given line and character coordinates into pixel coordinates /// on the display. /// </summary> /// <param name="bufferPosition">The buffer position.</param> /// <param name="displayContext">The display context.</param> /// <param name="lineHeight">Will contains the height of the current line.</param> /// <returns></returns> public static PointD ToScreenCoordinates( this TextPosition bufferPosition, IDisplayContext displayContext, out int lineHeight) { // Get the line index, which needs to be a number in range. EditorViewRenderer buffer = displayContext.Renderer; int lineIndex = bufferPosition.LinePosition.GetLineIndex(displayContext.LineBuffer); // Pull out some of the common things we'll be using in this method. int bufferLineIndex = buffer.LineBuffer.NormalizeLineIndex(lineIndex); Layout layout = buffer.GetLineLayout( bufferLineIndex, LineContexts.Unformatted); LineBlockStyle style = buffer.GetLineStyle( bufferLineIndex, LineContexts.Unformatted); // Figure out the top of the current line in relation to the entire // buffer and view. For lines beyond the first, we use // GetLineLayoutHeight because it also takes into account the line // spacing and borders which we would have to calculate otherwise. double y = bufferLineIndex == 0 ? 0 : buffer.GetLineLayoutHeight(0, bufferLineIndex - 1); // Add the style offset for the top-padding. y += style.Top; // The cursor position code uses Unicode instead of C# character // positions. This means we have to advance more than just one // value to calculate it. This actually uses UTF-8 encoding to // calculate the indexes. string lineText = displayContext.LineBuffer.GetLineText(lineIndex); int characterIndex = bufferPosition.GetCharacterIndex(displayContext.LineBuffer); int unicodeCharacter = PangoUtility.TranslateStringToPangoIndex( lineText, characterIndex); // We need to figure out the relative position. If the position equals // the length of the string, we want to put the caret at the end of the // character. Otherwise, we put it on the front of the character to // indicate insert point. bool trailing = false; int lineLength = buffer.LineBuffer.GetLineLength( bufferLineIndex, LineContexts.Unformatted); if (unicodeCharacter == lineLength) { // Shift back one character to calculate the position and put // the cursor at the end of the character. unicodeCharacter--; trailing = true; } // Figure out which wrapped line we are actually on and the position // inside that line. If the character equals the length of the string, // then we want to move to the end of it. int wrappedLineIndex; int layoutX; layout.IndexToLineX( unicodeCharacter, trailing, out wrappedLineIndex, out layoutX); // Get the relative offset into the wrapped lines. Rectangle layoutPoint = layout.IndexToPos(unicodeCharacter); y += Units.ToPixels(layoutPoint.Y); // Get the height of the wrapped line. Rectangle ink = Rectangle.Zero; Rectangle logical = Rectangle.Zero; layout.Lines[wrappedLineIndex].GetPixelExtents(ref ink, ref logical); lineHeight = logical.Height; // Return the results. return(new PointD(Units.ToPixels(layoutX), y)); }