Ejemplo n.º 1
0
        // Helper for GetPositionAtWordBoundary.
        // Returns true when passed TextPointer is next to a wordBreak in requested direction.
        private static bool IsPositionNextToWordBreak(TextPointer position, LogicalDirection wordBreakDirection)
        {
            bool isAtWordBoundary = false;

            // Skip over any formatting.
            if (position.GetPointerContext(wordBreakDirection) != TextPointerContext.Text)
            {
                position = position.GetInsertionPosition(wordBreakDirection);
            }

            if (position.GetPointerContext(wordBreakDirection) == TextPointerContext.Text)
            {
                LogicalDirection oppositeDirection = (wordBreakDirection == LogicalDirection.Forward) ?
                    LogicalDirection.Backward : LogicalDirection.Forward;

                char[] runBuffer = new char[1];
                char[] oppositeRunBuffer = new char[1];

                position.GetTextInRun(wordBreakDirection, runBuffer, /*startIndex*/0, /*count*/1);
                position.GetTextInRun(oppositeDirection, oppositeRunBuffer, /*startIndex*/0, /*count*/1);

                if (runBuffer[0] == ' ' && !(oppositeRunBuffer[0] == ' '))
                {
                    isAtWordBoundary = true;
                }
            }
            else
            {
                // If we're not adjacent to text then we always want to consider this position a "word break".
                // In practice, we're most likely next to an embedded object or a block boundary.
                isAtWordBoundary = true;
            }

            return isAtWordBoundary;
        }
        public static int GetColumnForTextPointer(this RichTextBox rtb, TextPointer tp)
        {
            TextPointer tpColumn = tp.GetInsertionPosition(LogicalDirection.Backward);
            int columnNr = 1;

            for (TextPointer linePointer = tpColumn.GetLineStartPosition(0).GetNextInsertionPosition(LogicalDirection.Forward);
                linePointer.CompareTo(tpColumn) < 0; linePointer = linePointer.GetNextInsertionPosition(LogicalDirection.Forward))
            {
                columnNr++;
            }

            return columnNr;
        }
Ejemplo n.º 3
0
        /// <summary>
        /// 1.  When wordBreakDirection = Forward, returns a position at the end of the word,
        ///     i.e. a position with a wordBreak character (space) following it.
        /// 2.  When wordBreakDirection = Backward, returns a position at the start of the word,
        ///     i.e. a position with a wordBreak character (space) preceeding it.
        /// 3.  Returns null when there is no workbreak in the requested direction.
        /// </summary>
        private static TextPointer GetPositionAtWordBoundary(TextPointer position, LogicalDirection wordBreakDirection)
        {
            if (!position.IsAtInsertionPosition)
            {
                position = position.GetInsertionPosition(wordBreakDirection);
            }

            TextPointer navigator = position;
            while (navigator != null && !IsPositionNextToWordBreak(navigator, wordBreakDirection))
            {
                navigator = navigator.GetNextInsertionPosition(wordBreakDirection);
            }

            return navigator;
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Select the text in the given position and length.
        /// </summary>
        public void Select(int start, int length)
        {
            if (start < 0)
            {
                throw new ArgumentOutOfRangeException("start", SR.Get(SRID.ParameterCannotBeNegative));
            }

            if (length < 0)
            {
                throw new ArgumentOutOfRangeException("length", SR.Get(SRID.ParameterCannotBeNegative));
            }

            // Identify new position for selection Start
            int maxStart = TextContainer.SymbolCount;
            if (start > maxStart)
            {
                start = maxStart;
            }
            TextPointer newStart = this.TextContainer.CreatePointerAtOffset(start, LogicalDirection.Forward);

            // Normalize new start in some particular direction, to exclude ambiguity on surrogates bounndaries
            // and to start counting length from appropriate position.
            newStart = newStart.GetInsertionPosition(LogicalDirection.Forward);

            // Identify new position for selection End
            int maxLength = newStart.GetOffsetToPosition(TextContainer.End);
            if (length > maxLength)
            {
                length = maxLength;
            }
            TextPointer newEnd = new TextPointer(newStart, length, LogicalDirection.Forward);

            // Normalize end in some particular direction to exclude ambiguity on surrogate boundaries
            newEnd = newEnd.GetInsertionPosition(LogicalDirection.Forward);

            // Set new selection
            TextSelectionInternal.Select(newStart, newEnd);
        }
Ejemplo n.º 5
0
        public void SetCell(BufferCell cell, TextPointer position, LogicalDirection direction)
        {
            TextRange range = null;

            TextPointer positionPlus = position.GetNextInsertionPosition(LogicalDirection.Forward);
            if (positionPlus != null)
            {
                range = new TextRange(position, positionPlus);
            }

            if (null == range || range.IsEmpty)
            {
                position = position.GetInsertionPosition(LogicalDirection.Forward);
                if (position != null)
                {
                    Run r = position.GetAdjacentElement(LogicalDirection.Forward) as Run;

                    if (null != r)
                    {
                        if (r.Text.Length > 0)
                        {
                            char[] chr = r.Text.ToCharArray();
                            chr[0] = cell.Character;
                            r.Text = chr.ToString();
                        }
                        else
                        {
                            r.Text = cell.Character.ToString();
                        }
                    }
                    else
                    {
                        r = position.GetAdjacentElement(LogicalDirection.Backward) as Run;
                        if (null != r
                            && r.Background == BrushFromConsoleColor(cell.BackgroundColor)
                            && r.Foreground == BrushFromConsoleColor(cell.ForegroundColor)
                        )
                        {
                            if (r.Text.Length > 0)
                            {
                                r.Text = r.Text + cell.Character;
                            }
                            else
                            {
                                r.Text = cell.Character.ToString();
                            }
                        }
                        else
                        {
                            r = new Run(cell.Character.ToString(), position);
                        }
                    }
                    r.Background = BrushFromConsoleColor(cell.BackgroundColor);
                    r.Foreground = BrushFromConsoleColor(cell.ForegroundColor);
                    //position = r.ElementStart;
                }

            }
            else
            {

                range.Text = cell.Character.ToString();
                range.ApplyPropertyValue(TextElement.BackgroundProperty, BrushFromConsoleColor(cell.BackgroundColor));
                range.ApplyPropertyValue(TextElement.ForegroundProperty, BrushFromConsoleColor(cell.ForegroundColor));
            }
        }
Ejemplo n.º 6
0
        // ....................................................................
        // 
        // Row editing 
        //
        // .................................................................... 

        #region Row Editing

        /// <summary> 
        /// Checks whether the given TextPointer is at row end position, where text insertion is impossible
        /// and returns a following position where text insertion or pasting is valid. 
        /// New paragraphs is creeated at the end of TextContainer if necessary. 
        /// </summary>
        internal static TextPointer EnsureInsertionPosition(TextPointer position) 
        {
            Invariant.Assert(position != null, "null check: position");

            // Normalize the pointer 
            position = position.GetInsertionPosition(position.LogicalDirection);
 
            if (!TextPointerBase.IsAtInsertionPosition(position)) 
            {
                // There is no insertion positions in the whole document at all. 
                // Generate minimally necessary content to ensure at least one insertion position.
                position = CreateInsertionPositionInIncompleteContent(position);
            }
            else 
            {
                // Check if position is at one of special structural boundary positions, where we can potentially have an 
                // insertion position and create one. 

                if (position.IsAtRowEnd) 
                {
                    // Find a next insertion position within the scope of the parent table.
                    Table currentTable = TextRangeEditTables.GetTableFromPosition(position);
                    position = GetAdjustedRowEndPosition(currentTable, position); 

                    if (position.CompareTo(currentTable.ElementEnd) == 0) 
                    { 
                        // The range is at the end of table which is the last block of text container OR
                        // next insertion position crossed table boundary. 
                        // In both cases, we want to insert a paragraph after table end and move our insertion position there.
                        position = CreateImplicitParagraph(currentTable.ElementEnd);
                    }
                } 
                Invariant.Assert(!position.IsAtRowEnd, "position is not expected to be at RowEnd anymore");
 
                // Note that this is not an else if, because our next insertion position (if it is within the same table), 
                // can fall into one of the following cases. We need to handle it.
                if (TextPointerBase.IsInBlockUIContainer(position)) 
                {
                    BlockUIContainer blockUIContainer = (BlockUIContainer)position.Parent;
                    bool insertBefore = position.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.ElementStart;
                    position = insertBefore 
                        ? CreateImplicitParagraph(blockUIContainer.ElementStart)
                        : CreateImplicitParagraph(blockUIContainer.ElementEnd); 
 
                    // Clean potentialy incomplete content
                    if (blockUIContainer.IsEmpty) 
                    {
                        blockUIContainer.RepositionWithContent(null);
                    }
                } 
                else if (TextPointerBase.IsBeforeFirstTable(position) || TextPointerBase.IsAtPotentialParagraphPosition(position))
                { 
                    position = CreateImplicitParagraph(position); 
                }
                else if (TextPointerBase.IsAtPotentialRunPosition(position)) 
                {
                    position = CreateImplicitRun(position);
                }
            } 

            Invariant.Assert(TextSchema.IsInTextContent(position), "position must be in text content now"); 
            return position; 
        }
Ejemplo n.º 7
0
        /// <summary> 
        /// From two text positions finds out table elements involved
        /// into building potential table range.
        /// </summary>
        /// <param name="anchorPosition"> 
        /// Position where selection starts. The cell at this position (if any)
        /// must be included into a range unconditionally. 
        /// </param> 
        /// <param name="movingPosition">
        /// A position opposite to an anchorPosition. 
        /// </param>
        /// <param name="includeCellAtMovingPosition">
        /// <see ref="TextRangeEditTables.BuildTableRange"/>
        /// </param> 
        /// <param name="anchorCell">
        /// The cell at anchor position. Returns not null only if a range is not crossing table 
        /// boundary. Returns null if the range does not cross any TableCell boundary at all 
        /// or if cells crossed belong to a table whose boundary is crossed by a range.
        /// In other words, anchorCell and movingCell are either both nulls or both non-nulls. 
        /// </param>
        /// <param name="movingCell">
        /// The cell at the movingPosition.  Returns not null only if a range is not crossing table
        /// boundary. Returns null if the range does not cross any TableCell boundary at all 
        /// or if cells crossed belong to a table whose boundary is crossed by a range.
        /// In other words, anchorCell and movingCell are either both nulls or both non-nulls. 
        /// </param> 
        /// <param name="anchorRow"></param>
        /// <param name="movingRow"></param> 
        /// <param name="anchorRowGroup"></param>
        /// <param name="movingRowGroup"></param>
        /// <param name="anchorTable"></param>
        /// <param name="movingTable"></param> 
        /// <returns>
        /// True if at least one structural unit was found. 
        /// False if no structural units were crossed by either startPosition or endPosition 
        /// (up to their commin ancestor element).
        /// </returns> 
        private static bool IdentifyTableElements(
            TextPointer anchorPosition, TextPointer movingPosition,
            bool includeCellAtMovingPosition,
            out TableCell anchorCell, out TableCell movingCell, 
            out TableRow anchorRow, out TableRow movingRow,
            out TableRowGroup anchorRowGroup, out TableRowGroup movingRowGroup, 
            out Table anchorTable, out Table movingTable) 
        {
            // We need to normalize pointers to make sure that we do not stay above TableCell level 
            anchorPosition = anchorPosition.GetInsertionPosition(LogicalDirection.Forward);
            if (!TextPointerBase.IsAfterLastParagraph(movingPosition))
            {
                movingPosition = movingPosition.GetInsertionPosition(LogicalDirection.Backward); 
            }
 
            if (!FindTableElements( 
                anchorPosition, movingPosition,
                out anchorCell, out movingCell, 
                out anchorRow, out movingRow,
                out anchorRowGroup, out movingRowGroup,
                out anchorTable, out movingTable))
            { 
                //Invariant.Assert(
                //    anchorCell == null && movingCell == null && 
                //    anchorRow == null && movingRow == null && 
                //    anchorRowGroup == null && movingRowGroup == null &&
                //    anchorTable == null && movingTable == null); 
                return false;
            }

            if (anchorTable != null || movingTable != null) 
            {
                // We crossed table boundary, so need to clear anchor/movingCells 
                //Invariant.Assert(anchorTable == null || movingTable == null || anchorTable != movingTable); 

                anchorCell = null; 
                movingCell = null;
            }
            else
            { 
                // We did not cross table boundary. Make sure that anchor/movingCells set consistently
 
                if (anchorCell != null && movingCell != null) 
                {
                    // Both ends cross cell boundaries. 
                    // The cell at movingPosition may require a correction - excluding it from
                    // a range - if its column index is greater than the anchor's one
                    // and if the movingPosition is at the very beginning of the cell,
                    // and if includeCellAtMovingPosition is set to false. 
                    if (!includeCellAtMovingPosition &&
                        movingPosition.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.ElementStart && 
                        movingCell.ColumnIndex > anchorCell.ColumnIndex + anchorCell.ColumnSpan - 1 && 
                        movingCell.Index > 0)
                    { 
                        // Moving cell is in forward direction relative to anchor and the position at its very beginning.
                        // This cell should not be included into selection. Take the previous one as the moving cell.
                        movingCell = movingCell.Row.Cells[movingCell.Index - 1];
                    } 
                }
                else if (anchorCell != null && movingCell == null && movingPosition.IsAtRowEnd) 
                { 
                    // Special case when movingPosition is after the very last cell in row
                    TableRow movingCellRow = movingPosition.Parent as TableRow; 

                    // Take the last cell from this row
                    movingCell = movingCellRow.Cells[movingCellRow.Cells.Count - 1];
                } 
                else
                { 
                    // This is not a valid TableCellRange 
                    anchorCell = null;
                    movingCell = null; 
                }
            }

            // Null anchor/movingCells indicate that the range IsTableCellRange, 
            // so they must be non-null only if they both belong to the same table.
            //Invariant.Assert(anchorCell == null && movingCell == null || anchorCell != null && movingCell != null && anchorCell.Table == movingCell.Table); 
 
            return
                anchorCell != null || movingCell != null || 
                anchorRow != null || movingRow != null ||
                anchorRowGroup != null || movingRowGroup != null ||
                anchorTable != null || movingTable != null;
        } 
Ejemplo n.º 8
0
        // -------------------------------------------------------------------- 
        //
        // Private Methods 
        // 
        // -------------------------------------------------------------------
 
        #region Table Selection

        // ....................................................................
        // 
        // Table selection
        // 
        // .................................................................... 

        private static TextSegment NewNormalizedTextSegment(TextPointer startPosition, TextPointer endPosition) 
        {
            startPosition = startPosition.GetInsertionPosition(LogicalDirection.Forward);
            if (!TextPointerBase.IsAfterLastParagraph(endPosition))
            { 
                endPosition = endPosition.GetInsertionPosition(LogicalDirection.Backward);
            } 
 
            if (startPosition.CompareTo(endPosition) < 0)
            { 
                return new TextSegment(startPosition, endPosition);
            }
            else
            { 
                return new TextSegment(startPosition, startPosition);
            } 
        } 
Ejemplo n.º 9
0
        private void SetPrompt()
        {
            BeginChange();
            // this is the run that the user will type their command into...
            Run command = new Run("", _currentParagraph.ContentEnd.GetInsertionPosition(LogicalDirection.Backward)); // , Document.ContentEnd
            // it's VITAL that this Run "look" different than the previous one
            // otherwise if you backspace the last character it merges into the previous output
            command.Background = Background; 
            command.Foreground = Foreground;
            EndChange();
            _promptInlines = _currentParagraph.Inlines.Count;

            // toggle undo to prevent "undo"ing past this point.
            IsUndoEnabled = false;
            IsUndoEnabled = true;

            _commandStart = Document.ContentEnd.GetInsertionPosition(LogicalDirection.Backward);
            CaretPosition = _commandStart.GetInsertionPosition(LogicalDirection.Forward);
        }