Пример #1
0
        public Rectangle GetCaretPosition(IGraphics gr, SelectionPoint sp, CaretDirection d)
        {
            if (rootBlock == null)
            {
                return(Rectangle.Empty);
            }

            CaretPositionInfo cpi = new CaretPositionInfo();

            rootBlock.GetCaretPosition(gr, 0, 0, sp, ref cpi);
            if (d == CaretDirection.LTR)
            {
                cpi.UseSecondary = true;
            }

            return(cpi.ToRectangle());
        }
Пример #2
0
        public Rectangle GetCaretPosition(IGraphics gr, SelectionPoint sp, CaretDirection d)
        {
            if ( rootBlock == null )
                return Rectangle.Empty;

            CaretPositionInfo cpi=new CaretPositionInfo();
            rootBlock.GetCaretPosition(gr, 0, 0, sp, ref cpi);
            if ( d == CaretDirection.LTR )
                cpi.UseSecondary=true;

            return cpi.ToRectangle();
        }
Пример #3
0
            /// <summary>
            /// Search from the given lscp (inclusive) towards the specified direction for the
            /// closest navigable cp. Return true is one such cp is found, false otherwise.
            /// </summary>
            private bool FindNextOrPreviousVisibleCp(
                int             lscp,
                CaretDirection  direction,
                out int         lscpVisisble
                )
            {
                lscpVisisble = lscp;

                SpanRider plsrunSpanRider = new SpanRider(_plsrunVector);

                if (direction == CaretDirection.Forward)
                {
                    while (lscpVisisble < _metrics._lscpLim)
                    {
                        plsrunSpanRider.At(lscpVisisble - _cpFirst);
                        LSRun run = GetRun((Plsrun) plsrunSpanRider.CurrentElement);

                        // When scanning forward, only trailine edges of visiable content are navigable.
                        if (run.IsVisible)
                        {
                            return true;
                        }

                        lscpVisisble += plsrunSpanRider.Length; // move to start of next span
                    }
                }
                else
                {
                    Debug.Assert(direction == CaretDirection.Backward || direction == CaretDirection.Backspace);

                    // lscpCurrent can be right after the end of the line, we snap it back to be at the end of the line.
                    lscpVisisble = Math.Min(lscpVisisble, _metrics._lscpLim - 1);
                    while (lscpVisisble >= _cpFirst)
                    {
                        plsrunSpanRider.At(lscpVisisble - _cpFirst);
                        LSRun run = GetRun((Plsrun) plsrunSpanRider.CurrentElement);

                        // When scanning backward, visiable content has caret stop at its leading edge.
                        if (run.IsVisible)
                        {
                            return true;
                        }

                        // When scanning backward, the newline sequence has caret stop at its leading edge.
                        if (run.IsNewline)
                        {
                            // set navigable cp at the start of newline sequence.
                            lscpVisisble = _cpFirst + plsrunSpanRider.CurrentSpanStart;
                            return true;
                        }

                        lscpVisisble = _cpFirst + plsrunSpanRider.CurrentSpanStart - 1; // move to the end of previous span
                    }
                }

                lscpVisisble = lscp;
                return false;
            }
Пример #4
0
            /// <summary>
            /// Given a specified current character index, calculate the character index
            /// to the closest caret stop before or at the current index; and the number
            /// of codepoints from the closest caret stop to the next caret stop.
            /// </summary>
            private bool GetNextOrPreviousCaretStop(
                int                      currentIndex,
                CaretDirection           direction,
                out int                  caretStopIndex,
                out int                  offsetToNextCaretStopIndex
                )
            {
                caretStopIndex = currentIndex;
                offsetToNextCaretStopIndex = 0;

                if (    HasCollapsed
                    &&  _collapsedRange != null
                    &&  currentIndex >= _collapsedRange.TextSourceCharacterIndex
                    )
                {
                    // current index is within collapsed range,
                    caretStopIndex = _collapsedRange.TextSourceCharacterIndex;

                    if (currentIndex < _collapsedRange.TextSourceCharacterIndex + _collapsedRange.Length)
                        offsetToNextCaretStopIndex = _collapsedRange.Length;

                    return true;
                }

                LsQSubInfo[] sublineInfo = new LsQSubInfo[_depthQueryMax];
                LsTextCell lsTextCell = new LsTextCell();

                int lscpVisisble = GetInternalCp(currentIndex);
                bool found = FindNextOrPreviousVisibleCp(lscpVisisble, direction, out lscpVisisble);

                if (!found)
                {
                    return false; // there is no caret stop anymore in the given direction.
                }

                int actualSublineCount;

                QueryLineCpPpoint(
                    lscpVisisble,
                    sublineInfo,
                    out actualSublineCount,
                    out lsTextCell
                    );

                // Locate the current caret stop
                caretStopIndex = GetExternalCp(lsTextCell.lscpStartCell);

                if (    actualSublineCount > 0
                    &&  lscpVisisble >= lsTextCell.lscpStartCell
                    &&  lscpVisisble <= lsTextCell.lscpEndCell
                    )
                {
                    // the last subline contains the run that owns the querying lscp
                    LSRun lsrun = GetRun((Plsrun)sublineInfo[actualSublineCount - 1].plsrun);

                    if (lsrun.IsHitTestable)
                    {
                        if (    lsrun.HasExtendedCharacter
                            ||  (direction != CaretDirection.Backspace && lsrun.NeedsCaretInfo)
                            )
                        {
                            // LsTextCell.lscpEndCell is the index to the last lscp still in the cell.
                            // The number of LSCP within the text cell is equal to the number of CP.
                            offsetToNextCaretStopIndex = lsTextCell.lscpEndCell + 1 - lsTextCell.lscpStartCell;
                        }
                        else
                        {
                            // caret stops before every codepoint
                            caretStopIndex = GetExternalCp(lscpVisisble);
                            offsetToNextCaretStopIndex = 1;
                        }
                    }
                    else
                    {
                        // run is not hit-testable, caret navigation is not allowed in the run,
                        // the next caret stop is therefore either at the end of the run or the end of the line whichever reached first.
                        offsetToNextCaretStopIndex = Math.Min(Length, lsrun.Length - caretStopIndex + lsrun.OffsetToFirstCp + _cpFirst);
                    }
                }

                return true;
            }
Пример #5
0
            /// <summary>
            /// Calculate previous caret character hit based on the caret action
            /// </summary>
            private CharacterHit GetPreviousCaretCharacterHitByBehavior(
                CharacterHit    characterHit,
                CaretDirection  direction
                )
            {
                Debug.Assert(direction == CaretDirection.Backward || direction == CaretDirection.Backspace);

                if ((_statusFlags & StatusFlags.IsDisposed) != 0)
                {
                    throw new ObjectDisposedException(SR.Get(SRID.TextLineHasBeenDisposed));
                }

                TextFormatterImp.VerifyCaretCharacterHit(characterHit, _cpFirst, _metrics._cchLength);

                if (_ploline.Value == IntPtr.Zero)
                {
                    return characterHit;
                }

                if (    characterHit.FirstCharacterIndex == _cpFirst
                    &&  characterHit.TrailingLength == 0)
                {
                    // We are already at the beginning of the line
                    return characterHit;
                }

                int caretStopIndex;
                int offsetToNextCaretStopIndex;

                bool found = GetNextOrPreviousCaretStop(
                    characterHit.FirstCharacterIndex,
                    direction,
                    out caretStopIndex,
                    out offsetToNextCaretStopIndex
                    );

                if (!found)
                {
                    // The current index is before the 1st caret stop.
                    return characterHit;
                }

                if (    offsetToNextCaretStopIndex != 0
                    &&  characterHit.TrailingLength == 0
                    &&  caretStopIndex != _cpFirst
                    &&  caretStopIndex >= characterHit.FirstCharacterIndex
                    )
                {
                    // If the current character hit is at the leading edge and it is not at the first caret stop,
                    // move it to leading edge of the previous caret stop. At this point, the current character stop
                    // fully encloses the input index and the input is at the leading edge.
                    found = GetNextOrPreviousCaretStop(
                        caretStopIndex - 1, // position at the character immediately preceding the current caret stop
                        direction,
                        out caretStopIndex,
                        out offsetToNextCaretStopIndex
                        );

                    if (!found)
                    {
                        // The current index is before the 1st caret stop.
                        return characterHit;
                    }
                }

                // The current chracter hit is either beyond the last caret stop,
                // or it's at the trailing edge of the current caret stop,
                // or the current index is at the leading edge of the first caret stop.
                //
                // In such cases, move to the leading edge of the closest caret stop.
                return new CharacterHit(caretStopIndex, 0);
            }
Пример #6
0
 protected override void MoveCaret(CaretDirection dir, bool extend)
 {
 }
Пример #7
0
 protected override void DeleteTextOp(CaretDirection dir)
 {
 }
Пример #8
0
	// Deletes text (i.e. backspace, delete keys)
	protected abstract void DeleteTextOp(CaretDirection dir);
Пример #9
0
		internal void MoveCaret(CaretDirection direction) {
			// FIXME should we use IsWordSeparator to detect whitespace, instead 
			// of looking for actual spaces in the Word move cases?

			bool nowrap = false;
			switch(direction) {
				case CaretDirection.CharForwardNoWrap:
					nowrap = true;
					goto case CaretDirection.CharForward;
				case CaretDirection.CharForward: {
					caret.pos++;
					if (caret.pos > caret.line.TextLengthWithoutEnding ()) {
						if (!nowrap) {
							// Go into next line
							if (caret.line.line_no < this.lines) {
								caret.line = GetLine(caret.line.line_no+1);
								caret.pos = 0;
								caret.tag = caret.line.tags;
							} else {
								caret.pos--;
							}
						} else {
							// Single line; we stay where we are
							caret.pos--;
						}
					} else {
						if ((caret.tag.Start - 1 + caret.tag.Length) < caret.pos) {
							caret.tag = caret.tag.Next;
						}
					}
					UpdateCaret();
					return;
				}

				case CaretDirection.CharBackNoWrap:
					nowrap = true;
					goto case CaretDirection.CharBack;
				case CaretDirection.CharBack: {
					if (caret.pos > 0) {
						// caret.pos--; // folded into the if below
						
						if (--caret.pos > 0) {
							if (caret.tag.Start > caret.pos) {
								caret.tag = caret.tag.Previous;
							}
						}
					} else {
						if (caret.line.line_no > 1 && !nowrap) {
							caret.line = GetLine(caret.line.line_no - 1);
							caret.pos = caret.line.TextLengthWithoutEnding ();
							caret.tag = LineTag.FindTag(caret.line, caret.pos);
						}
					}
					UpdateCaret();
					return;
				}

				case CaretDirection.WordForward: {
					int len;

					len = caret.line.text.Length;
					if (caret.pos < len) {
						while ((caret.pos < len) && (caret.line.text[caret.pos] != ' ')) {
							caret.pos++;
						}
						if (caret.pos < len) {
							// Skip any whitespace
							while ((caret.pos < len) && (caret.line.text[caret.pos] == ' ')) {
								caret.pos++;
							}
						}
						caret.tag = LineTag.FindTag(caret.line, caret.pos);
					} else {
						if (caret.line.line_no < this.lines) {
							caret.line = GetLine(caret.line.line_no + 1);
							caret.pos = 0;
							caret.tag = caret.line.tags;
						}
					}
					UpdateCaret();
					return;
				}

				case CaretDirection.WordBack: {
					if (caret.pos > 0) {
						caret.pos--;

						while ((caret.pos > 0) && (caret.line.text[caret.pos] == ' ')) {
							caret.pos--;
						}

						while ((caret.pos > 0) && (caret.line.text[caret.pos] != ' ')) {
							caret.pos--;
						}

						if (caret.line.text.ToString(caret.pos, 1) == " ") {
							if (caret.pos != 0) {
								caret.pos++;
							} else {
								caret.line = GetLine(caret.line.line_no - 1);
								caret.pos = caret.line.text.Length;
							}
						}
						caret.tag = LineTag.FindTag(caret.line, caret.pos);
					} else {
						if (caret.line.line_no > 1) {
							caret.line = GetLine(caret.line.line_no - 1);
							caret.pos = caret.line.text.Length;
							caret.tag = LineTag.FindTag(caret.line, caret.pos);
						}
					}
					UpdateCaret();
					return;
				}

				case CaretDirection.LineUp: {
					if (caret.line.line_no > 1) {
						int	pixel;

						pixel = (int)caret.line.widths[caret.pos];
						PositionCaret(pixel, GetLine(caret.line.line_no - 1).Y);

						DisplayCaret ();
					}
					return;
				}

				case CaretDirection.LineDown: {
					if (caret.line.line_no < lines) {
						int	pixel;

						pixel = (int)caret.line.widths[caret.pos];
						PositionCaret(pixel, GetLine(caret.line.line_no + 1).Y);

						DisplayCaret ();
					}
					return;
				}

				case CaretDirection.Home: {
					if (caret.pos > 0) {
						caret.pos = 0;
						caret.tag = caret.line.tags;
						UpdateCaret();
					}
					return;
				}

				case CaretDirection.End: {
					if (caret.pos < caret.line.TextLengthWithoutEnding ()) {
						caret.pos = caret.line.TextLengthWithoutEnding ();
						caret.tag = LineTag.FindTag(caret.line, caret.pos);
						UpdateCaret();
					}
					return;
				}

				case CaretDirection.PgUp: {

					if (caret.line.line_no == 1 && owner.richtext) {
						owner.vscroll.Value = 0;
						Line line = GetLine (1);
						PositionCaret (line, 0);
					}

					int y_offset = caret.line.Y + caret.line.height - 1 - viewport_y;
					int index;
					LineTag top = FindCursor ((int) caret.line.widths [caret.pos],
							viewport_y - viewport_height, out index);

					owner.vscroll.Value = Math.Min (top.Line.Y, owner.vscroll.Maximum - viewport_height);
					PositionCaret ((int) caret.line.widths [caret.pos], y_offset + viewport_y);

					return;
				}

				case CaretDirection.PgDn: {

					if (caret.line.line_no == lines && owner.richtext) {
						owner.vscroll.Value = owner.vscroll.Maximum - viewport_height + 1;
						Line line = GetLine (lines);
						PositionCaret (line, line.TextLengthWithoutEnding());
					}

					int y_offset = caret.line.Y - viewport_y;
					int index;
					LineTag top = FindCursor ((int) caret.line.widths [caret.pos],
							viewport_y + viewport_height, out index);

					owner.vscroll.Value = Math.Min (top.Line.Y, owner.vscroll.Maximum - viewport_height);
					PositionCaret ((int) caret.line.widths [caret.pos], y_offset + viewport_y);
					
					return;
				}

				case CaretDirection.CtrlPgUp: {
					PositionCaret(0, viewport_y);
					DisplayCaret ();
					return;
				}

				case CaretDirection.CtrlPgDn: {
					Line	line;
					LineTag	tag;
					int	index;

					tag = FindCursor (0, viewport_y + viewport_height, out index);
					if (tag.Line.line_no > 1) {
						line = GetLine(tag.Line.line_no - 1);
					} else {
						line = tag.Line;
					}
					PositionCaret(line, line.Text.Length);
					DisplayCaret ();
					return;
				}

				case CaretDirection.CtrlHome: {
					caret.line = GetLine(1);
					caret.pos = 0;
					caret.tag = caret.line.tags;

					UpdateCaret();
					return;
				}

				case CaretDirection.CtrlEnd: {
					caret.line = GetLine(lines);
					caret.pos = caret.line.TextLengthWithoutEnding ();
					caret.tag = LineTag.FindTag(caret.line, caret.pos);

					UpdateCaret();
					return;
				}

				case CaretDirection.SelectionStart: {
					caret.line = selection_start.line;
					caret.pos = selection_start.pos;
					caret.tag = selection_start.tag;

					UpdateCaret();
					return;
				}

				case CaretDirection.SelectionEnd: {
					caret.line = selection_end.line;
					caret.pos = selection_end.pos;
					caret.tag = selection_end.tag;

					UpdateCaret();
					return;
				}
			}
		}
Пример #10
0
	private static bool IsTowardsTextEnd(CaretDirection dir)
	{
		return
			dir == CaretDirection.Right
			||
			dir == CaretDirection.WordRight
			||
			dir == CaretDirection.LineEnd
			||
			dir == CaretDirection.LineDown
			||
			dir == CaretDirection.PageDown
			||
			dir == CaretDirection.TextEnd;
	}
Пример #11
0
	protected override void DeleteTextOp(CaretDirection dir)
	{
		if (ReadOnly)
			return;

		switch (dir)
		{
			case CaretDirection.WordLeft:
			case CaretDirection.Left:
			{
				if (layout.Items.Length == 0)
					break;
				int widthText = layout.Items[layout.Items.Length - 1].bounds.Right;
				int bottomCaret = caretBounds.Bottom;

				if (GetSelectionLength()>0)
				{
					SetSelectionText("");
					SelectInternal(GetSelectionStart(), 0);
				}
				else
				{
					int startPos = GetSelectionStart();
					int newPos =
						dir==CaretDirection.Left
						?
						ComputeCharLeftPos(startPos)
						:
						ComputeWordLeftPos(startPos);
						
					if (newPos < startPos)
					{
						int nbCharsToDelete = startPos - newPos;
						SetTextActual(Text.Substring(0, GetSelectionStart() - nbCharsToDelete) + Text.Substring(GetSelectionStart()));
						SelectInternal(GetSelectionStart()-nbCharsToDelete, 0);
					}
				}
				OnTextChanged(EventArgs.Empty);

				// In the case of multiline we ensure that we recover any blank lines created by backspacing at the bottom (if the text is bigger than the view area).
				// In the case of non multiline, we recover any character space that is now there after deleting
				if (!Multiline && layout.Items.Length > 0)
				{
					if (textAlign == HorizontalAlignment.Center && XViewOffset > maxXY/2 - TextDrawArea.Width/2)
					{
						XViewOffset -= widthText - layout.Items[layout.Items.Length - 1].bounds.Right;
						int x = maxXY/2 - TextDrawArea.Width/2;
						if (x > xViewOffset)
						{
							XViewOffset = x;
						}
					}
					else if (textAlign == HorizontalAlignment.Left && XViewOffset > 0)
					{
						XViewOffset -= widthText - layout.Items[layout.Items.Length - 1].bounds.Right;
						if (xViewOffset < 0)
						{
							XViewOffset = 0;
						}
					}
				}
				else
				{
					//Move the caret first
					CaretSetEndSelection();
					if (bottomCaret != caretBounds.Bottom)
					{
						int yViewOffset = YViewOffset - bottomCaret + caretBounds.Bottom - 1;
						if (yViewOffset < 0)
							yViewOffset = 0;
						YViewOffset = yViewOffset;
					}
				}
				InvalidateDirty();
				break;
			}

			case CaretDirection.Right:
			case CaretDirection.WordRight:
			{
				if (GetSelectionLength()>0)
				{
					SetSelectionText("");
				}
				else
				{
					int startPos = GetSelectionStart();
					int newPos =
						dir==CaretDirection.Right
						?
						ComputeCharRightPos(startPos)
						:
						ComputeWordRightPos(startPos);
						
					if (newPos > startPos)
					{
						SetTextActual(Text.Substring(0, GetSelectionStart()) + Text.Substring(GetSelectionStart() + newPos - startPos));
					}
				}
				SelectInternal(GetSelectionStart(),0);
				InvalidateDirty();
				OnTextChanged(EventArgs.Empty);
				break;
			}
		}

		CaretSetEndSelection();
		ScrollToCaretNoRedraw();
	}
Пример #12
0
	// Caret navigation
	protected override void MoveCaret(CaretDirection dir, bool extend)
	{
		int startSel = GetSelectionStart();
		
		int newPos = startSel;
		if ((extend && selectionLengthActual>0) || (!extend && IsTowardsTextEnd(dir)))
		{
			newPos += GetSelectionLength();
		}
		
		switch (dir)
		{
		case CaretDirection.Left:
			newPos = ComputeCharLeftPos(newPos);
			break;
		case CaretDirection.Right:
			newPos = ComputeCharRightPos(newPos);
			break;
		case CaretDirection.WordLeft:
			newPos = ComputeWordLeftPos(newPos);
			break;
		case CaretDirection.WordRight:
			newPos = ComputeWordRightPos(newPos);
			break;
		case CaretDirection.LineStart:
			newPos = ComputeLineStartPos(newPos);
			break;
		case CaretDirection.LineEnd:
			newPos = ComputeLineEndPos(newPos);
			break;
		case CaretDirection.LineUp:
			if (caretBounds.Top >= caretBounds.Height )
			{
				newPos = ComputeLineOffset(newPos, -1);
			}
			break;
		case CaretDirection.LineDown:
			if (layout.Items.Length == 0)
			{
				return;
			}
			if (caretBounds.Top < layout.Items[layout.Items.Length - 1].bounds.Top)
			{
				newPos = ComputeLineOffset(newPos, 1);
			}
			break;
		case CaretDirection.PageUp:
			newPos = ComputeLineOffset(newPos, - (int) TextDrawArea.Height / Font.Height);
			break;
		case CaretDirection.PageDown:
			newPos = ComputeLineOffset(newPos, (int) TextDrawArea.Height / Font.Height);
			break;
		case CaretDirection.TextStart:
			newPos = 0;
			break;
		case CaretDirection.TextEnd:
			newPos = Text.Length;
			break;
		}
		
		if (extend)
		{
			UpdateSelectionInternal(newPos);
		}
		else
		{
			SelectInternal(newPos, 0);
			CaretSetPosition(newPos);
			ScrollToCaretNoRedraw();
			InvalidateDirty();
		}
	}
Пример #13
0
        private void UpdateCaretPosition(SelectionPoint sp, bool resetX, CaretDirection d)
        {
            Rectangle rc=Rectangle.Empty;
            if ( layoutEngine != null )
            {
                using ( IGraphics gr=grFactory.CreateGraphics(this) )
                    rc=layoutEngine.GetCaretPosition(gr, sp, d);
            }
            if ( !rc.IsEmpty )
            {
                SetCaretPosition(rc.Location, rc.Height);

                if ( resetX )
                    linePosition=rc.Left;

                caret.Visible=!currentSelection.IsRange;
                return;
            }

            // TODO: M: not sure why caret does not update when window resizing
            caret.Visible=false;
            Logger.Log("WARN: failed to get caret position");
        }
Пример #14
0
        private void UpdateCaretPosition(bool resetX, CaretDirection d)
        {
            if ( currentSelection.IsEmpty )
                return;

            SelectionPoint sp=currentSelection.IsRange ? currentSelection.End : currentSelection.Start;
            UpdateCaretPosition(sp, resetX, d);
        }
Пример #15
0
	protected override void DeleteTextOp(CaretDirection dir)
	{
	}
Пример #16
0
	protected override void MoveCaret(CaretDirection dir, bool extend)
	{
	}
Пример #17
0
	protected abstract void MoveCaret(CaretDirection dir, bool extend);