Esempio n. 1
0
        /// <summary>
        /// Moves the position to the end of wrapped line.
        /// </summary>
        /// <param name="displayContext">The display context.</param>
        public static TextPosition ToEndOfWrappedLine(
            this TextPosition bufferPosition,
            IDisplayContext displayContext)
        {
            // Get the wrapped line and layout.
            Layout     layout;
            int        wrappedLineIndex;
            LayoutLine wrappedLine = bufferPosition.GetWrappedLine(
                displayContext, out layout, out wrappedLineIndex);

            // Move to the end of the wrapped line. If this isn't the last, we
            // need to shift back one character.
            int unicodeIndex = wrappedLine.StartIndex + wrappedLine.Length;

            if (wrappedLineIndex != layout.LineCount - 1)
            {
                unicodeIndex--;
            }

            // Because the wrappedLine works with UTF-8 encoding, we need to
            // convert it back to a C# string.
            string lineText =
                displayContext.LineBuffer.GetLineText(bufferPosition.LinePosition);
            int characterIndex = PangoUtility.TranslatePangoToStringIndex(
                lineText, unicodeIndex);

            // Create a new buffer position from the elements and return it.
            return(new TextPosition(bufferPosition.LinePosition, characterIndex));
        }
Esempio n. 2
0
        /// <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 Pango markup for a given line.
        /// </summary>
        /// <param name="lineIndex">The line index in the buffer or Int32.MaxValue for
        /// the last line.</param>
        /// <param name="lineContexts">The line contexts.</param>
        /// <returns></returns>
        public virtual string GetLineMarkup(
            int lineIndex,
            LineContexts lineContexts)
        {
            string text = GetLineText(lineIndex, LineContexts.None);

            return(PangoUtility.Escape(text));
        }
Esempio n. 4
0
        /// <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);
        }
Esempio n. 5
0
        /// <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));
        }
Esempio n. 7
0
        /// <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 ToStringOnMiddleOfTwoByteString()
        {
            // Arrange
            const int    stringIndex = 8;
            const string text        = "éâäàçê";

            // Act
            int pangoIndex = PangoUtility.TranslatePangoToStringIndex(text, stringIndex);

            // Assert
            Assert.AreEqual(4, pangoIndex);
        }
        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 ToStringOnMiddleOfSimpleString()
        {
            // Arrange
            const int    stringIndex = 4;
            const string text        = "simple";

            // Act
            int pangoIndex = PangoUtility.TranslatePangoToStringIndex(text, stringIndex);

            // Assert
            Assert.AreEqual(4, 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);
        }
Esempio n. 13
0
        /// <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 string index for a given X coordinate (in Pango units).
        /// </summary>
        /// <param name="layoutLine">The layout line.</param>
        /// <param name="x">The x.</param>
        /// <param name="stringIndex">Index of the string.</param>
        /// <param name="trailing">The trailing.</param>
        /// <returns></returns>
        public static bool XToTranslatedIndex(
            this LayoutLine layoutLine,
            int x,
            out int stringIndex,
            out int trailing)
        {
            int  pangoIndex;
            bool results = layoutLine.XToIndex(x, out pangoIndex, out trailing);

            stringIndex = PangoUtility.TranslatePangoToStringIndex(
                layoutLine.Layout.Text, pangoIndex);
            return(results);
        }
Esempio n. 15
0
        /// <summary>
        /// Gets the buffer position from a given point.
        /// </summary>
        /// <param name="widgetPoint">The widget point.</param>
        /// <param name="displayContext">The display context.</param>
        /// <returns></returns>
        public static TextPosition GetTextPosition(
            PointD widgetPoint,
            EditorViewController controller)
        {
            IDisplayContext displayContext = controller.DisplayContext;
            double          y         = widgetPoint.Y + displayContext.BufferOffsetY;
            int             lineIndex = displayContext.Renderer.GetLineLayoutRange(y);
            Layout          layout    = displayContext.Renderer.GetLineLayout(
                lineIndex, LineContexts.None);

            // Shift the buffer-relative coordinates to layout-relative coordinates.
            double layoutY = y;

            if (lineIndex > 0)
            {
                layoutY -= displayContext.Renderer.GetLineLayoutHeight(0, lineIndex - 1);
            }

            int pangoLayoutY = Units.FromPixels((int)layoutY);

            // Shift the buffer-relative coordinates to handle padding.
            LineBlockStyle style = displayContext.Renderer.GetLineStyle(
                lineIndex, LineContexts.None);
            double layoutX = widgetPoint.X - style.Left;

            // Determines where in the layout is the point.
            int pangoLayoutX = Units.FromPixels((int)layoutX);
            int unicodeIndex;
            int trailing;

            layout.XyToIndex(pangoLayoutX, pangoLayoutY, out unicodeIndex, out trailing);

            // When dealing with UTF-8 characters, we have to convert the
            // Unicode index into a C# index.
            string lineText = displayContext.LineBuffer.GetLineText(lineIndex);

            unicodeIndex = NormalizeEmptyStrings(lineText, unicodeIndex);
            int characterIndex = PangoUtility.TranslatePangoToStringIndex(
                lineText, unicodeIndex);

            // If the source text is empty, then we disable the trailing.
            if (lineText.Length == 0)
            {
                trailing = 0;
            }

            // Return the buffer position.
            return(new TextPosition(lineIndex, characterIndex + trailing));
        }
        /// <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);
        }
Esempio n. 18
0
        /// <summary>
        /// Translates the X, Y coordinates to a character index.
        /// </summary>
        /// <param name="layout">The layout.</param>
        /// <param name="x">The x.</param>
        /// <param name="y">The y.</param>
        /// <param name="stringIndex">The resulting index into the string.</param>
        /// <param name="trailing">The trailing.</param>
        /// <returns></returns>
        public static bool XyToTranslatedIndex(
            this Layout layout,
            int x,
            int y,
            out int stringIndex,
            out int trailing)
        {
            // Grab the results fromt he Pango index.
            int  pangoIndex;
            bool results = layout.XyToIndex(x, y, out pangoIndex, out trailing);

            // Translate the Pango index.
            stringIndex = PangoUtility.TranslatePangoToStringIndex(
                layout.Text, pangoIndex);

            // Return the results.
            return(results);
        }
Esempio n. 19
0
        /// <summary>
        /// Moves the position to the beginning of wrapped line.
        /// </summary>
        /// <param name="displayContext">The display context.</param>
        public static TextPosition ToBeginningOfWrappedLine(
            this TextPosition bufferPosition,
            IDisplayContext displayContext)
        {
            // Wrapped lines (via Pango) work with UTF-8 encoding, not the
            // normal C# string indexes. We need to get the index and convert
            // it to a character string since that is what this library uses.
            LayoutLine wrappedLine  = bufferPosition.GetWrappedLine(displayContext);
            int        unicodeIndex = wrappedLine.StartIndex;

            // Because the wrappedLine works with UTF-8 encoding, we need to
            // convert it back to a C# string.
            string lineText =
                displayContext.LineBuffer.GetLineText(bufferPosition.LinePosition);
            int characterIndex = PangoUtility.TranslatePangoToStringIndex(
                lineText, unicodeIndex);

            // Create a new buffer position from the elements and return it.
            return(new TextPosition(bufferPosition.LinePosition, characterIndex));
        }
        public override string GetLineMarkup(
            int lineIndex,
            LineContexts lineContexts)
        {
            // We need to get a read-only lock on the block.
            Block block;

            using (blocks.AcquireBlockLock(RequestLock.Read, lineIndex, out block))
            {
                // Now that we have a block, grab the text and text spans and
                // format them. If we don't have any text spans, we can return
                // a simple formatted string.
                string             text   = block.Text;
                TextSpanCollection spans  = block.TextSpans;
                string             markup = spans.Count == 0
                                        ? PangoUtility.Escape(text)
                                        : FormatText(text, spans);

                // Return the resulting markup.
                return(markup);
            }
        }
Esempio n. 21
0
        /// <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));
        }
Esempio n. 22
0
        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);
        }