+ long startPos = -1;
+
+ if (m_caretPosition > startPos - noPositions + 1)
+ {
+ long oldPos = m_caretPosition;
+ long newPos = m_caretPosition - noPositions;
+ bool extendSel = ExtendSelection(m_caretPosition, newPos, flags);
+ if (!extendSel)
+ SelectNone();
+
+ if (noPositions == 1)
+ MoveCaretBack(oldPos);
+ else
+ SetCaretPosition(newPos);
+
+ PositionCaret();
+ SetDefaultStyleToCursorStyle();
+
+ return true;
+ }
+ else
+ return false;
+}
+
+// Find the caret position for the combination of hit-test flags and character position.
+// Returns the caret position and also an indication of where to place the caret (caretLineStart)
+// since this is ambiguous (same position used for end of line and start of next).
+long wxRichTextCtrl::FindCaretPositionForCharacterPosition(long position, int hitTestFlags, wxRichTextParagraphLayoutBox* container,
+ bool& caretLineStart)
+{
+ // If end of previous line, and hitTest is wxRICHTEXT_HITTEST_BEFORE,
+ // we want to be at the end of the last line but with m_caretAtLineStart set to true,
+ // so we view the caret at the start of the line.
+ caretLineStart = false;
+ long caretPosition = position;
+
+ if (hitTestFlags & wxRICHTEXT_HITTEST_BEFORE)
+ {
+ wxRichTextLine* thisLine = container->GetLineAtPosition(position-1);
+ wxRichTextRange lineRange;
+ if (thisLine)
+ lineRange = thisLine->GetAbsoluteRange();
+
+ if (thisLine && (position-1) == lineRange.GetEnd())
+ {
+ caretPosition --;
+ caretLineStart = true;
+ }
+ else
+ {
+ wxRichTextParagraph* para = container->GetParagraphAtPosition(position);
+ if (para && para->GetRange().GetStart() == position)
+ caretPosition --;
+ }
+ }
+ return caretPosition;
+}
+
+/// Move up
+bool wxRichTextCtrl::MoveUp(int noLines, int flags)
+{
+ return MoveDown(- noLines, flags);
+}
+
+/// Move up
+bool wxRichTextCtrl::MoveDown(int noLines, int flags)
+{
+ if (!GetCaret())
+ return false;
+
+ long lineNumber = GetFocusObject()->GetVisibleLineNumber(m_caretPosition, true, m_caretAtLineStart);
+ wxPoint pt = GetCaret()->GetPosition();
+ long newLine = lineNumber + noLines;
+ bool notInThisObject = false;
+
+ if (lineNumber != -1)
+ {
+ if (noLines > 0)
+ {
+ long lastLine = GetFocusObject()->GetVisibleLineNumber(GetFocusObject()->GetOwnRange().GetEnd());
+ if (newLine > lastLine)
+ notInThisObject = true;
+ }
+ else
+ {
+ if (newLine < 0)
+ notInThisObject = true;
+ }
+ }
+
+ wxRichTextParagraphLayoutBox* container = GetFocusObject();
+ int hitTestFlags = wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS|wxRICHTEXT_HITTEST_NO_FLOATING_OBJECTS|wxRICHTEXT_HITTEST_HONOUR_ATOMIC;
+
+ bool lineIsEmpty = false;
+ if (notInThisObject)
+ {
+ // If we know we're navigating out of the current object,
+ // try to find an object anywhere in the buffer at the new position (up or down a bit)
+ container = & GetBuffer();
+ hitTestFlags &= ~wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS;
+
+ if (noLines > 0) // going down
+ {
+ pt.y = GetFocusObject()->GetPosition().y + GetFocusObject()->GetCachedSize().y + 2;
+ }
+ else // going up
+ {
+ pt.y = GetFocusObject()->GetPosition().y - 2;
+ }
+ }
+ else
+ {
+ wxRichTextLine* lineObj = GetFocusObject()->GetLineForVisibleLineNumber(newLine);
+ if (lineObj)
+ {
+ pt.y = lineObj->GetAbsolutePosition().y + 2;
+ if (lineObj->GetRange().GetStart() == lineObj->GetRange().GetEnd())
+ lineIsEmpty = true;
+ }
+ else
+ return false;
+ }
+
+ long newPos = 0;
+ wxClientDC dc(this);
+ PrepareDC(dc);
+ dc.SetFont(GetFont());
+
+ wxRichTextObject* hitObj = NULL;
+ wxRichTextObject* contextObj = NULL;
+ wxRichTextDrawingContext context(& GetBuffer());
+ int hitTest = container->HitTest(dc, context, pt, newPos, & hitObj, & contextObj, hitTestFlags);
+
+ if (hitObj &&
+ ((hitTest & wxRICHTEXT_HITTEST_NONE) == 0) &&
+ (! (hitObj == (& m_buffer) && ((hitTest & wxRICHTEXT_HITTEST_OUTSIDE) != 0))) // outside the buffer counts as 'do nothing'
+ )
+ {
+ if (notInThisObject)
+ {
+ wxRichTextParagraphLayoutBox* actualContainer = wxDynamicCast(contextObj, wxRichTextParagraphLayoutBox);
+ if (actualContainer && actualContainer != GetFocusObject() && actualContainer->AcceptsFocus())
+ {
+ SetFocusObject(actualContainer, false /* don't set caret position yet */);
+
+ container = actualContainer;
+ }
+ }
+
+ bool caretLineStart = true;
+
+ // If the line is empty, there is only one possible position for the caret,
+ // so force the 'before' state so FindCaretPositionForCharacterPosition doesn't
+ // just return the same position.
+ if (lineIsEmpty)
+ {
+ hitTest &= ~wxRICHTEXT_HITTEST_AFTER;
+ hitTest |= wxRICHTEXT_HITTEST_BEFORE;
+ }
+ long caretPosition = FindCaretPositionForCharacterPosition(newPos, hitTest, container, caretLineStart);
+ long newSelEnd = caretPosition;
+ bool extendSel;
+
+ if (notInThisObject)
+ extendSel = false;
+ else
+ extendSel = ExtendSelection(m_caretPosition, newSelEnd, flags);
+
+ if (!extendSel)
+ SelectNone();
+
+ SetCaretPosition(caretPosition, caretLineStart);
+ PositionCaret();
+ SetDefaultStyleToCursorStyle();
+
+ return true;
+ }
+
+ return false;
+}
+
+/// Move to the end of the paragraph
+bool wxRichTextCtrl::MoveToParagraphEnd(int flags)
+{
+ wxRichTextParagraph* para = GetFocusObject()->GetParagraphAtPosition(m_caretPosition, true);
+ if (para)
+ {
+ long newPos = para->GetRange().GetEnd() - 1;
+ bool extendSel = ExtendSelection(m_caretPosition, newPos, flags);
+ if (!extendSel)
+ SelectNone();
+
+ SetCaretPosition(newPos);
+ PositionCaret();
+ SetDefaultStyleToCursorStyle();
+
+ return true;
+ }
+
+ return false;
+}
+
+/// Move to the start of the paragraph
+bool wxRichTextCtrl::MoveToParagraphStart(int flags)
+{
+ wxRichTextParagraph* para = GetFocusObject()->GetParagraphAtPosition(m_caretPosition, true);
+ if (para)
+ {
+ long newPos = para->GetRange().GetStart() - 1;
+ bool extendSel = ExtendSelection(m_caretPosition, newPos, flags);
+ if (!extendSel)
+ SelectNone();
+
+ SetCaretPosition(newPos, true);
+ PositionCaret();
+ SetDefaultStyleToCursorStyle();
+
+ return true;
+ }
+
+ return false;
+}
+
+/// Move to the end of the line
+bool wxRichTextCtrl::MoveToLineEnd(int flags)
+{
+ wxRichTextLine* line = GetVisibleLineForCaretPosition(m_caretPosition);
+
+ if (line)
+ {
+ wxRichTextRange lineRange = line->GetAbsoluteRange();
+ long newPos = lineRange.GetEnd();
+ bool extendSel = ExtendSelection(m_caretPosition, newPos, flags);
+ if (!extendSel)
+ SelectNone();
+
+ SetCaretPosition(newPos);
+ PositionCaret();
+ SetDefaultStyleToCursorStyle();
+
+ return true;
+ }
+
+ return false;
+}
+
+/// Move to the start of the line
+bool wxRichTextCtrl::MoveToLineStart(int flags)
+{
+ wxRichTextLine* line = GetVisibleLineForCaretPosition(m_caretPosition);
+ if (line)
+ {
+ wxRichTextRange lineRange = line->GetAbsoluteRange();
+ long newPos = lineRange.GetStart()-1;
+
+ bool extendSel = ExtendSelection(m_caretPosition, newPos, flags);
+ if (!extendSel)
+ SelectNone();
+
+ wxRichTextParagraph* para = GetFocusObject()->GetParagraphForLine(line);
+
+ SetCaretPosition(newPos, para->GetRange().GetStart() != lineRange.GetStart());
+ PositionCaret();
+ SetDefaultStyleToCursorStyle();
+
+ return true;
+ }
+
+ return false;
+}
+
+/// Move to the start of the buffer
+bool wxRichTextCtrl::MoveHome(int flags)
+{
+ if (m_caretPosition != -1)
+ {
+ bool extendSel = ExtendSelection(m_caretPosition, -1, flags);
+ if (!extendSel)
+ SelectNone();
+
+ SetCaretPosition(-1);
+ PositionCaret();
+ SetDefaultStyleToCursorStyle();
+
+ return true;
+ }
+ else
+ return false;
+}
+
+/// Move to the end of the buffer
+bool wxRichTextCtrl::MoveEnd(int flags)
+{
+ long endPos = GetFocusObject()->GetOwnRange().GetEnd()-1;
+
+ if (m_caretPosition != endPos)
+ {
+ bool extendSel = ExtendSelection(m_caretPosition, endPos, flags);
+ if (!extendSel)
+ SelectNone();
+
+ SetCaretPosition(endPos);
+ PositionCaret();
+ SetDefaultStyleToCursorStyle();
+
+ return true;
+ }
+ else
+ return false;
+}
+
+/// Move noPages pages up
+bool wxRichTextCtrl::PageUp(int noPages, int flags)
+{
+ return PageDown(- noPages, flags);
+}
+
+/// Move noPages pages down
+bool wxRichTextCtrl::PageDown(int noPages, int flags)
+{
+ // Calculate which line occurs noPages * screen height further down.
+ wxRichTextLine* line = GetVisibleLineForCaretPosition(m_caretPosition);
+ if (line)
+ {
+ wxSize clientSize = GetClientSize();
+ int newY = line->GetAbsolutePosition().y + noPages*clientSize.y;
+
+ wxRichTextLine* newLine = GetFocusObject()->GetLineAtYPosition(newY);
+ if (newLine)
+ {
+ wxRichTextRange lineRange = newLine->GetAbsoluteRange();
+ long pos = lineRange.GetStart()-1;
+ if (pos != m_caretPosition)
+ {
+ wxRichTextParagraph* para = GetFocusObject()->GetParagraphForLine(newLine);
+
+ bool extendSel = ExtendSelection(m_caretPosition, pos, flags);
+ if (!extendSel)
+ SelectNone();
+
+ SetCaretPosition(pos, para->GetRange().GetStart() != lineRange.GetStart());
+ PositionCaret();
+ SetDefaultStyleToCursorStyle();
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static bool wxRichTextCtrlIsWhitespace(const wxString& str)
+{
+ return str == wxT(" ") || str == wxT("\t") || (!str.empty() && (str[0] == (wxChar) 160));
+}
+
+// Finds the caret position for the next word
+long wxRichTextCtrl::FindNextWordPosition(int direction) const
+{
+ long endPos = GetFocusObject()->GetOwnRange().GetEnd();
+
+ if (direction > 0)
+ {
+ long i = m_caretPosition+1+direction; // +1 for conversion to character pos
+
+ // First skip current text to space
+ while (i < endPos && i > -1)
+ {
+ // i is in character, not caret positions
+ wxString text = GetFocusObject()->GetTextForRange(wxRichTextRange(i, i));
+ wxRichTextLine* line = GetFocusObject()->GetLineAtPosition(i, false);
+ if (line && (i == line->GetAbsoluteRange().GetEnd()))
+ {
+ break;
+ }
+ else if (!wxRichTextCtrlIsWhitespace(text) && !text.empty())
+ i += direction;
+ else
+ {
+ break;
+ }
+ }
+ while (i < endPos && i > -1)
+ {
+ // i is in character, not caret positions
+ wxString text = GetFocusObject()->GetTextForRange(wxRichTextRange(i, i));
+ wxRichTextLine* line = GetFocusObject()->GetLineAtPosition(i, false);
+ if (line && (i == line->GetAbsoluteRange().GetEnd()))
+ return wxMax(-1, i);
+
+ if (text.empty()) // End of paragraph, or maybe an image
+ return wxMax(-1, i - 1);
+ else if (wxRichTextCtrlIsWhitespace(text) || text.empty())
+ i += direction;
+ else
+ {
+ // Convert to caret position
+ return wxMax(-1, i - 1);
+ }
+ }
+ if (i >= endPos)
+ return endPos-1;
+ return i-1;
+ }
+ else
+ {
+ long i = m_caretPosition;
+
+ // First skip white space
+ while (i < endPos && i > -1)
+ {
+ // i is in character, not caret positions
+ wxString text = GetFocusObject()->GetTextForRange(wxRichTextRange(i, i));
+ wxRichTextLine* line = GetFocusObject()->GetLineAtPosition(i, false);
+
+ if (text.empty() || (line && (i == line->GetAbsoluteRange().GetStart()))) // End of paragraph, or maybe an image
+ break;
+ else if (wxRichTextCtrlIsWhitespace(text) || text.empty())
+ i += direction;
+ else
+ break;
+ }
+ // Next skip current text to space
+ while (i < endPos && i > -1)
+ {
+ // i is in character, not caret positions
+ wxString text = GetFocusObject()->GetTextForRange(wxRichTextRange(i, i));
+ wxRichTextLine* line = GetFocusObject()->GetLineAtPosition(i, false);
+ if (line && line->GetAbsoluteRange().GetStart() == i)
+ return i-1;
+
+ if (!wxRichTextCtrlIsWhitespace(text) /* && !text.empty() */)
+ i += direction;
+ else
+ {
+ return i;
+ }
+ }
+ if (i < -1)
+ return -1;
+ return i;
+ }
+}
+
+/// Move n words left
+bool wxRichTextCtrl::WordLeft(int WXUNUSED(n), int flags)
+{
+ long pos = FindNextWordPosition(-1);
+ if (pos != m_caretPosition)
+ {
+ wxRichTextParagraph* para = GetFocusObject()->GetParagraphAtPosition(pos, true);
+
+ bool extendSel = ExtendSelection(m_caretPosition, pos, flags);
+ if (!extendSel)
+ SelectNone();
+
+ SetCaretPosition(pos, para->GetRange().GetStart() != pos);
+ PositionCaret();
+ SetDefaultStyleToCursorStyle();
+
+ return true;
+ }
+
+ return false;
+}
+
+/// Move n words right
+bool wxRichTextCtrl::WordRight(int WXUNUSED(n), int flags)
+{
+ long pos = FindNextWordPosition(1);
+ if (pos != m_caretPosition)
+ {
+ wxRichTextParagraph* para = GetFocusObject()->GetParagraphAtPosition(pos, true);
+
+ bool extendSel = ExtendSelection(m_caretPosition, pos, flags);
+ if (!extendSel)
+ SelectNone();
+
+ SetCaretPosition(pos, para->GetRange().GetStart() != pos);
+ PositionCaret();
+ SetDefaultStyleToCursorStyle();
+
+ return true;
+ }
+
+ return false;
+}
+
+/// Sizing
+void wxRichTextCtrl::OnSize(wxSizeEvent& event)
+{
+ // Only do sizing optimization for large buffers
+ if (GetBuffer().GetOwnRange().GetEnd() > m_delayedLayoutThreshold)
+ {
+ m_fullLayoutRequired = true;
+ m_fullLayoutTime = wxGetLocalTimeMillis();
+ m_fullLayoutSavedPosition = GetFirstVisiblePosition();
+ LayoutContent(true /* onlyVisibleRect */);
+ }
+ else
+ GetBuffer().Invalidate(wxRICHTEXT_ALL);
+
+#if wxRICHTEXT_BUFFERED_PAINTING
+ RecreateBuffer();
+#endif
+
+ event.Skip();
+}
+
+// Force any pending layout due to large buffer
+void wxRichTextCtrl::ForceDelayedLayout()
+{
+ if (m_fullLayoutRequired)
+ {
+ m_fullLayoutRequired = false;
+ m_fullLayoutTime = 0;
+ GetBuffer().Invalidate(wxRICHTEXT_ALL);
+ ShowPosition(m_fullLayoutSavedPosition);
+ Refresh(false);
+ Update();
+ }
+}
+
+/// Idle-time processing
+void wxRichTextCtrl::OnIdle(wxIdleEvent& event)
+{
+#if wxRICHTEXT_USE_OWN_CARET
+ if (((wxRichTextCaret*) GetCaret())->GetNeedsUpdate())
+ {
+ ((wxRichTextCaret*) GetCaret())->SetNeedsUpdate(false);
+ PositionCaret();
+ GetCaret()->Show();
+ }
+#endif
+
+ const int layoutInterval = wxRICHTEXT_DEFAULT_LAYOUT_INTERVAL;
+
+ if (m_fullLayoutRequired && (wxGetLocalTimeMillis() > (m_fullLayoutTime + layoutInterval)))
+ {
+ m_fullLayoutRequired = false;
+ m_fullLayoutTime = 0;
+ GetBuffer().Invalidate(wxRICHTEXT_ALL);
+ ShowPosition(m_fullLayoutSavedPosition);
+ Refresh(false);
+ }
+
+ if (m_caretPositionForDefaultStyle != -2)
+ {
+ // If the caret position has changed, no longer reflect the default style
+ // in the UI.
+ if (GetCaretPosition() != m_caretPositionForDefaultStyle)
+ m_caretPositionForDefaultStyle = -2;
+ }
+
+ event.Skip();
+}
+
+/// Scrolling
+void wxRichTextCtrl::OnScroll(wxScrollWinEvent& event)
+{
+#if wxRICHTEXT_USE_OWN_CARET
+ if (!((wxRichTextCaret*) GetCaret())->GetNeedsUpdate())
+ {
+ GetCaret()->Hide();
+ ((wxRichTextCaret*) GetCaret())->SetNeedsUpdate();
+ }
+#endif
+
+ event.Skip();
+}
+
+/// Set up scrollbars, e.g. after a resize
+void wxRichTextCtrl::SetupScrollbars(bool atTop)
+{
+ if (IsFrozen())
+ return;
+
+ if (GetBuffer().IsEmpty() || !m_verticalScrollbarEnabled)
+ {
+ SetScrollbars(0, 0, 0, 0, 0, 0);
+ return;
+ }
+
+ // TODO: reimplement scrolling so we scroll by line, not by fixed number
+ // of pixels. See e.g. wxVScrolledWindow for ideas.
+ int pixelsPerUnit = 5;
+ wxSize clientSize = GetClientSize();
+
+ int maxHeight = (int) (0.5 + GetScale() * (GetBuffer().GetCachedSize().y + GetBuffer().GetTopMargin()));
+
+ // Round up so we have at least maxHeight pixels
+ int unitsY = (int) (((float)maxHeight/(float)pixelsPerUnit) + 0.5);
+
+ int startX = 0, startY = 0;
+ if (!atTop)
+ GetViewStart(& startX, & startY);
+
+ int maxPositionX = 0;
+ int maxPositionY = (int) ((((float)(wxMax((unitsY*pixelsPerUnit) - clientSize.y, 0)))/((float)pixelsPerUnit)) + 0.5);
+
+ int newStartX = wxMin(maxPositionX, startX);
+ int newStartY = wxMin(maxPositionY, startY);
+
+ int oldPPUX, oldPPUY;
+ int oldStartX, oldStartY;
+ int oldVirtualSizeX = 0, oldVirtualSizeY = 0;
+ GetScrollPixelsPerUnit(& oldPPUX, & oldPPUY);
+ GetViewStart(& oldStartX, & oldStartY);
+ GetVirtualSize(& oldVirtualSizeX, & oldVirtualSizeY);
+ if (oldPPUY > 0)
+ oldVirtualSizeY /= oldPPUY;
+
+ if (oldPPUX == 0 && oldPPUY == pixelsPerUnit && oldVirtualSizeY == unitsY && oldStartX == newStartX && oldStartY == newStartY)
+ return;
+
+ // Don't set scrollbars if there were none before, and there will be none now.
+ if (oldPPUY != 0 && (oldVirtualSizeY*oldPPUY < clientSize.y) && (unitsY*pixelsPerUnit < clientSize.y))
+ return;
+
+ // Move to previous scroll position if
+ // possible
+ SetScrollbars(0, pixelsPerUnit, 0, unitsY, newStartX, newStartY);
+}
+
+/// Paint the background
+void wxRichTextCtrl::PaintBackground(wxDC& dc)
+{
+ wxColour backgroundColour = GetBackgroundColour();
+ if (!backgroundColour.IsOk())
+ backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
+
+ // Clear the background
+ dc.SetBrush(wxBrush(backgroundColour));
+ dc.SetPen(*wxTRANSPARENT_PEN);
+ wxRect windowRect(GetClientSize());
+ windowRect.x -= 2; windowRect.y -= 2;
+ windowRect.width += 4; windowRect.height += 4;
+
+ // We need to shift the rectangle to take into account
+ // scrolling. Converting device to logical coordinates.
+ CalcUnscrolledPosition(windowRect.x, windowRect.y, & windowRect.x, & windowRect.y);
+ dc.DrawRectangle(windowRect);
+}
+
+#if wxRICHTEXT_BUFFERED_PAINTING
+/// Recreate buffer bitmap if necessary
+bool wxRichTextCtrl::RecreateBuffer(const wxSize& size)
+{
+ wxSize sz = size;
+ if (sz == wxDefaultSize)
+ sz = GetClientSize();
+
+ if (sz.x < 1 || sz.y < 1)
+ return false;
+
+ if (!m_bufferBitmap.IsOk() || m_bufferBitmap.GetWidth() < sz.x || m_bufferBitmap.GetHeight() < sz.y)
+ m_bufferBitmap = wxBitmap(sz.x, sz.y);
+ return m_bufferBitmap.IsOk();
+}
+#endif
+
+// ----------------------------------------------------------------------------
+// file IO functions
+// ----------------------------------------------------------------------------
+
+bool wxRichTextCtrl::DoLoadFile(const wxString& filename, int fileType)
+{
+ SetFocusObject(& GetBuffer(), true);
+
+ bool success = GetBuffer().LoadFile(filename, (wxRichTextFileType)fileType);
+ if (success)
+ m_filename = filename;
+
+ DiscardEdits();
+ SetInsertionPoint(0);
+ LayoutContent();
+ PositionCaret();
+ SetupScrollbars(true);
+ Refresh(false);
+ wxTextCtrl::SendTextUpdatedEvent(this);
+
+ if (success)
+ return true;
+ else
+ {
+ wxLogError(_("File couldn't be loaded."));
+
+ return false;
+ }
+}
+
+bool wxRichTextCtrl::DoSaveFile(const wxString& filename, int fileType)
+{
+ if (GetBuffer().SaveFile(filename, (wxRichTextFileType)fileType))
+ {
+ m_filename = filename;
+
+ DiscardEdits();
+
+ return true;
+ }
+
+ wxLogError(_("The text couldn't be saved."));
+
+ return false;
+}
+
+// ----------------------------------------------------------------------------
+// wxRichTextCtrl specific functionality
+// ----------------------------------------------------------------------------
+
+/// Add a new paragraph of text to the end of the buffer
+wxRichTextRange wxRichTextCtrl::AddParagraph(const wxString& text)
+{
+ wxRichTextRange range = GetFocusObject()->AddParagraph(text);
+ GetBuffer().Invalidate();
+ LayoutContent();
+ return range;
+}
+
+/// Add an image
+wxRichTextRange wxRichTextCtrl::AddImage(const wxImage& image)
+{
+ wxRichTextRange range = GetFocusObject()->AddImage(image);
+ GetBuffer().Invalidate();
+ LayoutContent();
+ return range;
+}
+
+// ----------------------------------------------------------------------------
+// selection and ranges
+// ----------------------------------------------------------------------------
+
+/// Select none
+void wxRichTextCtrl::SelectNone()
+{
+ if (m_selection.IsValid())
+ {
+ wxRichTextSelection oldSelection = m_selection;
+
+ m_selection.Reset();
+
+ RefreshForSelectionChange(oldSelection, m_selection);
+ }
+ m_selectionAnchor = -2;
+ m_selectionAnchorObject = NULL;
+ m_selectionState = wxRichTextCtrlSelectionState_Normal;
+}
+
+static bool wxIsWordDelimiter(const wxString& text)
+{
+ return !text.IsEmpty() && !wxIsalnum(text[0]);
+}
+
+/// Select the word at the given character position
+bool wxRichTextCtrl::SelectWord(long position)
+{
+ if (position < 0 || position > GetFocusObject()->GetOwnRange().GetEnd())
+ return false;
+
+ wxRichTextParagraph* para = GetFocusObject()->GetParagraphAtPosition(position);
+ if (!para)
+ return false;
+
+ if (position == para->GetRange().GetEnd())
+ position --;
+
+ long positionStart = position;
+ long positionEnd = position;
+
+ for (positionStart = position; positionStart >= para->GetRange().GetStart(); positionStart --)
+ {
+ wxString text = GetFocusObject()->GetTextForRange(wxRichTextRange(positionStart, positionStart));
+ if (wxIsWordDelimiter(text))
+ {
+ positionStart ++;
+ break;
+ }
+ }
+ if (positionStart < para->GetRange().GetStart())
+ positionStart = para->GetRange().GetStart();
+
+ for (positionEnd = position; positionEnd < para->GetRange().GetEnd(); positionEnd ++)
+ {
+ wxString text = GetFocusObject()->GetTextForRange(wxRichTextRange(positionEnd, positionEnd));
+ if (wxIsWordDelimiter(text))
+ {
+ positionEnd --;
+ break;
+ }
+ }
+ if (positionEnd >= para->GetRange().GetEnd())
+ positionEnd = para->GetRange().GetEnd();
+
+ if (positionEnd < positionStart)
+ return false;
+
+ SetSelection(positionStart, positionEnd+1);
+
+ if (positionStart >= 0)
+ {
+ MoveCaret(positionStart-1, true);
+ SetDefaultStyleToCursorStyle();
+ }
+
+ return true;
+}
+
+wxString wxRichTextCtrl::GetStringSelection() const
+{
+ long from, to;
+ GetSelection(&from, &to);
+
+ return GetRange(from, to);
+}
+
+// ----------------------------------------------------------------------------
+// hit testing
+// ----------------------------------------------------------------------------
+
+wxTextCtrlHitTestResult
+wxRichTextCtrl::HitTest(const wxPoint& pt, wxTextCoord *x, wxTextCoord *y) const
+{
+ // implement in terms of the other overload as the native ports typically
+ // can get the position and not (x, y) pair directly (although wxUniv
+ // directly gets x and y -- and so overrides this method as well)
+ long pos;
+ wxTextCtrlHitTestResult rc = HitTest(pt, &pos);
+
+ if ( rc != wxTE_HT_UNKNOWN )
+ {
+ PositionToXY(pos, x, y);
+ }
+
+ return rc;
+}
+
+wxTextCtrlHitTestResult
+wxRichTextCtrl::HitTest(const wxPoint& pt,
+ long * pos) const
+{
+ wxClientDC dc((wxRichTextCtrl*) this);
+ ((wxRichTextCtrl*)this)->PrepareDC(dc);
+
+ // Buffer uses logical position (relative to start of buffer)
+ // so convert
+ wxPoint pt2 = GetLogicalPoint(pt);
+
+ wxRichTextObject* hitObj = NULL;
+ wxRichTextObject* contextObj = NULL;
+ wxRichTextDrawingContext context((wxRichTextBuffer*) & GetBuffer());
+ int hit = ((wxRichTextCtrl*)this)->GetFocusObject()->HitTest(dc, context, pt2, *pos, & hitObj, & contextObj, wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS);
+
+ if ((hit & wxRICHTEXT_HITTEST_BEFORE) && (hit & wxRICHTEXT_HITTEST_OUTSIDE))
+ return wxTE_HT_BEFORE;
+ else if ((hit & wxRICHTEXT_HITTEST_AFTER) && (hit & wxRICHTEXT_HITTEST_OUTSIDE))
+ return wxTE_HT_BEYOND;
+ else if (hit & (wxRICHTEXT_HITTEST_BEFORE|wxRICHTEXT_HITTEST_AFTER))
+ return wxTE_HT_ON_TEXT;
+
+ return wxTE_HT_UNKNOWN;
+}
+
+wxRichTextParagraphLayoutBox*
+wxRichTextCtrl::FindContainerAtPoint(const wxPoint pt, long& position, int& hit, wxRichTextObject* hitObj, int flags/* = 0*/)
+{
+ wxClientDC dc(this);
+ PrepareDC(dc);
+ dc.SetFont(GetFont());