// Skip
}
else
- child->Draw(dc, range, selectionRange, childRect, descent, style);
+ child->Draw(dc, range, selectionRange, rect, descent, style);
}
node = node->GetNext();
wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
while (node)
{
- // child is a paragraph
- wxRichTextParagraph* child = wxDynamicCast(node->GetData(), wxRichTextParagraph);
- wxASSERT (child != NULL);
-
- wxRichTextLineList::compatibility_iterator node2 = child->GetLines().GetFirst();
- while (node2)
+ wxRichTextObject* obj = (wxRichTextObject*) node->GetData();
+ if (obj->GetRange().Contains(pos))
{
- wxRichTextLine* line = node2->GetData();
+ // child is a paragraph
+ wxRichTextParagraph* child = wxDynamicCast(obj, wxRichTextParagraph);
+ wxASSERT (child != NULL);
+
+ wxRichTextLineList::compatibility_iterator node2 = child->GetLines().GetFirst();
+ while (node2)
+ {
+ wxRichTextLine* line = node2->GetData();
- wxRichTextRange range = line->GetAbsoluteRange();
+ wxRichTextRange range = line->GetAbsoluteRange();
- if (range.Contains(pos) ||
+ if (range.Contains(pos) ||
- // If the position is end-of-paragraph, then return the last line of
- // of the paragraph.
- (range.GetEnd() == child->GetRange().GetEnd()-1) && (pos == child->GetRange().GetEnd()))
- return line;
+ // If the position is end-of-paragraph, then return the last line of
+ // of the paragraph.
+ (range.GetEnd() == child->GetRange().GetEnd()-1) && (pos == child->GetRange().GetEnd()))
+ return line;
- node2 = node2->GetNext();
+ node2 = node2->GetNext();
+ }
}
node = node->GetNext();
}
/// Draw the item
-bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& range, const wxRichTextRange& selectionRange, const wxRect& WXUNUSED(rect), int WXUNUSED(descent), int style)
+bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& range, const wxRichTextRange& selectionRange, const wxRect& rect, int WXUNUSED(descent), int style)
{
wxTextAttr attr = GetCombinedAttributes();
wxRichTextLine* line = node->GetData();
wxRichTextRange lineRange = line->GetAbsoluteRange();
- int maxDescent = line->GetDescent();
-
// Lines are specified relative to the paragraph
wxPoint linePosition = line->GetPosition() + GetPosition();
- wxPoint objectPosition = linePosition;
- // Loop through objects until we get to the one within range
- wxRichTextObjectList::compatibility_iterator node2 = m_children.GetFirst();
-
- int i = 0;
- while (node2)
+ // Don't draw if off the screen
+ if (((style & wxRICHTEXT_DRAW_IGNORE_CACHE) != 0) || ((linePosition.y + line->GetSize().y) >= rect.y && linePosition.y <= rect.y + rect.height))
{
- wxRichTextObject* child = node2->GetData();
+ wxPoint objectPosition = linePosition;
+ int maxDescent = line->GetDescent();
+
+ // Loop through objects until we get to the one within range
+ wxRichTextObjectList::compatibility_iterator node2 = m_children.GetFirst();
- if (!child->GetRange().IsOutside(lineRange) && !lineRange.IsOutside(range))
+ int i = 0;
+ while (node2)
{
- // Draw this part of the line at the correct position
- wxRichTextRange objectRange(child->GetRange());
- objectRange.LimitTo(lineRange);
+ wxRichTextObject* child = node2->GetData();
- wxSize objectSize;
-#if wxRICHTEXT_USE_OPTIMIZED_LINE_DRAWING && wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS
- if (i < (int) line->GetObjectSizes().GetCount())
+ if (!child->GetRange().IsOutside(lineRange) && !lineRange.IsOutside(range))
{
- objectSize.x = line->GetObjectSizes()[(size_t) i];
- }
- else
+ // Draw this part of the line at the correct position
+ wxRichTextRange objectRange(child->GetRange());
+ objectRange.LimitTo(lineRange);
+
+ wxSize objectSize;
+#if wxRICHTEXT_USE_OPTIMIZED_LINE_DRAWING && wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS
+ if (i < (int) line->GetObjectSizes().GetCount())
+ {
+ objectSize.x = line->GetObjectSizes()[(size_t) i];
+ }
+ else
#endif
- {
- int descent = 0;
- child->GetRangeSize(objectRange, objectSize, descent, dc, wxRICHTEXT_UNFORMATTED, objectPosition);
- }
+ {
+ int descent = 0;
+ child->GetRangeSize(objectRange, objectSize, descent, dc, wxRICHTEXT_UNFORMATTED, objectPosition);
+ }
- // Use the child object's width, but the whole line's height
- wxRect childRect(objectPosition, wxSize(objectSize.x, line->GetSize().y));
- child->Draw(dc, objectRange, selectionRange, childRect, maxDescent, style);
+ // Use the child object's width, but the whole line's height
+ wxRect childRect(objectPosition, wxSize(objectSize.x, line->GetSize().y));
+ child->Draw(dc, objectRange, selectionRange, childRect, maxDescent, style);
- objectPosition.x += objectSize.x;
- i ++;
- }
- else if (child->GetRange().GetStart() > lineRange.GetEnd())
- // Can break out of inner loop now since we've passed this line's range
- break;
+ objectPosition.x += objectSize.x;
+ i ++;
+ }
+ else if (child->GetRange().GetStart() > lineRange.GetEnd())
+ // Can break out of inner loop now since we've passed this line's range
+ break;
- node2 = node2->GetNext();
+ node2 = node2->GetNext();
+ }
}
node = node->GetNext();
SetDefaultStyle(newStyle);
- // wxLogDebug("Default style size = %d", GetDefaultStyle().GetFont().GetPointSize());
-
return true;
}
{
}
+void wxRichTextAction::CalculateRefreshOptimizations(wxArrayInt& optimizationLineCharPositions, wxArrayInt& optimizationLineYPositions)
+{
+ // Store a list of line start character and y positions so we can figure out which area
+ // we need to refresh
+
+#if wxRICHTEXT_USE_OPTIMIZED_DRAWING
+ // NOTE: we're assuming that the buffer is laid out correctly at this point.
+ // If we had several actions, which only invalidate and leave layout until the
+ // paint handler is called, then this might not be true. So we may need to switch
+ // optimisation on only when we're simply adding text and not simultaneously
+ // deleting a selection, for example. Or, we make sure the buffer is laid out correctly
+ // first, but of course this means we'll be doing it twice.
+ if (!m_buffer->GetDirty() && m_ctrl) // can only do optimisation if the buffer is already laid out correctly
+ {
+ wxSize clientSize = m_ctrl->GetClientSize();
+ wxPoint firstVisiblePt = m_ctrl->GetFirstVisiblePoint();
+ int lastY = firstVisiblePt.y + clientSize.y;
+
+ wxRichTextParagraph* para = m_buffer->GetParagraphAtPosition(GetRange().GetStart());
+ wxRichTextObjectList::compatibility_iterator node = m_buffer->GetChildren().Find(para);
+ while (node)
+ {
+ wxRichTextParagraph* child = (wxRichTextParagraph*) node->GetData();
+ wxRichTextLineList::compatibility_iterator node2 = child->GetLines().GetFirst();
+ while (node2)
+ {
+ wxRichTextLine* line = node2->GetData();
+ wxPoint pt = line->GetAbsolutePosition();
+ wxRichTextRange range = line->GetAbsoluteRange();
+
+ if (pt.y > lastY)
+ {
+ node2 = wxRichTextLineList::compatibility_iterator();
+ node = wxRichTextObjectList::compatibility_iterator();
+ }
+ else if (range.GetStart() > GetPosition() && pt.y >= firstVisiblePt.y)
+ {
+ optimizationLineCharPositions.Add(range.GetStart());
+ optimizationLineYPositions.Add(pt.y);
+ }
+
+ if (node2)
+ node2 = node2->GetNext();
+ }
+
+ if (node)
+ node = node->GetNext();
+ }
+ }
+#endif
+}
+
bool wxRichTextAction::Do()
{
m_buffer->Modify(true);
wxArrayInt optimizationLineYPositions;
#if wxRICHTEXT_USE_OPTIMIZED_DRAWING
- // NOTE: we're assuming that the buffer is laid out correctly at this point.
- // If we had several actions, which only invalidate and leave layout until the
- // paint handler is called, then this might not be true. So we may need to switch
- // optimisation on only when we're simply adding text and not simultaneously
- // deleting a selection, for example. Or, we make sure the buffer is laid out correctly
- // first, but of course this means we'll be doing it twice.
- if (!m_buffer->GetDirty() && m_ctrl) // can only do optimisation if the buffer is already laid out correctly
- {
- wxSize clientSize = m_ctrl->GetClientSize();
- wxPoint firstVisiblePt = m_ctrl->GetFirstVisiblePoint();
- int lastY = firstVisiblePt.y + clientSize.y;
-
- wxRichTextParagraph* para = m_buffer->GetParagraphAtPosition(GetRange().GetStart());
- wxRichTextObjectList::compatibility_iterator node = m_buffer->GetChildren().Find(para);
- while (node)
- {
- wxRichTextParagraph* child = (wxRichTextParagraph*) node->GetData();
- wxRichTextLineList::compatibility_iterator node2 = child->GetLines().GetFirst();
- while (node2)
- {
- wxRichTextLine* line = node2->GetData();
- wxPoint pt = line->GetAbsolutePosition();
- wxRichTextRange range = line->GetAbsoluteRange();
-
- if (pt.y > lastY)
- {
- node2 = wxRichTextLineList::compatibility_iterator();
- node = wxRichTextObjectList::compatibility_iterator();
- }
- else if (range.GetStart() > GetPosition() && pt.y >= firstVisiblePt.y)
- {
- optimizationLineCharPositions.Add(range.GetStart());
- optimizationLineYPositions.Add(pt.y);
- }
-
- if (node2)
- node2 = node2->GetNext();
- }
-
- if (node)
- node = node->GetNext();
- }
- }
+ CalculateRefreshOptimizations(optimizationLineCharPositions, optimizationLineYPositions);
#endif
m_buffer->InsertFragment(GetRange().GetStart(), m_newParagraphs);
newCaretPosition = wxMin(newCaretPosition, (m_buffer->GetRange().GetEnd()-1));
- if (optimizationLineCharPositions.GetCount() > 0)
- UpdateAppearance(newCaretPosition, true /* send update event */, & optimizationLineCharPositions, & optimizationLineYPositions);
- else
- UpdateAppearance(newCaretPosition, true /* send update event */);
+ UpdateAppearance(newCaretPosition, true /* send update event */, & optimizationLineCharPositions, & optimizationLineYPositions, true /* do */);
wxRichTextEvent cmdEvent(
wxEVT_COMMAND_RICHTEXT_CONTENT_INSERTED,
}
case wxRICHTEXT_DELETE:
{
+ wxArrayInt optimizationLineCharPositions;
+ wxArrayInt optimizationLineYPositions;
+
+#if wxRICHTEXT_USE_OPTIMIZED_DRAWING
+ CalculateRefreshOptimizations(optimizationLineCharPositions, optimizationLineYPositions);
+#endif
+
m_buffer->DeleteRange(GetRange());
m_buffer->UpdateRanges();
m_buffer->Invalidate(wxRichTextRange(GetRange().GetStart(), GetRange().GetStart()));
if (caretPos >= m_buffer->GetRange().GetEnd())
caretPos --;
- UpdateAppearance(caretPos, true /* send update event */);
+ UpdateAppearance(caretPos, true /* send update event */, & optimizationLineCharPositions, & optimizationLineYPositions, true /* do */);
wxRichTextEvent cmdEvent(
wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED,
{
case wxRICHTEXT_INSERT:
{
+ wxArrayInt optimizationLineCharPositions;
+ wxArrayInt optimizationLineYPositions;
+
+#if wxRICHTEXT_USE_OPTIMIZED_DRAWING
+ CalculateRefreshOptimizations(optimizationLineCharPositions, optimizationLineYPositions);
+#endif
+
m_buffer->DeleteRange(GetRange());
m_buffer->UpdateRanges();
m_buffer->Invalidate(wxRichTextRange(GetRange().GetStart(), GetRange().GetStart()));
long newCaretPosition = GetPosition() - 1;
- UpdateAppearance(newCaretPosition, true /* send update event */);
+ UpdateAppearance(newCaretPosition, true, /* send update event */ & optimizationLineCharPositions, & optimizationLineYPositions, false /* undo */);
wxRichTextEvent cmdEvent(
wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED,
}
case wxRICHTEXT_DELETE:
{
+ wxArrayInt optimizationLineCharPositions;
+ wxArrayInt optimizationLineYPositions;
+
+#if wxRICHTEXT_USE_OPTIMIZED_DRAWING
+ CalculateRefreshOptimizations(optimizationLineCharPositions, optimizationLineYPositions);
+#endif
+
m_buffer->InsertFragment(GetRange().GetStart(), m_oldParagraphs);
m_buffer->UpdateRanges();
m_buffer->Invalidate(GetRange());
- UpdateAppearance(GetPosition(), true /* send update event */);
+ UpdateAppearance(GetPosition(), true, /* send update event */ & optimizationLineCharPositions, & optimizationLineYPositions, false /* undo */);
wxRichTextEvent cmdEvent(
wxEVT_COMMAND_RICHTEXT_CONTENT_INSERTED,
}
/// Update the control appearance
-void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent, wxArrayInt* optimizationLineCharPositions, wxArrayInt* optimizationLineYPositions)
+void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent, wxArrayInt* optimizationLineCharPositions, wxArrayInt* optimizationLineYPositions, bool isDoCmd)
{
if (m_ctrl)
{
#if wxRICHTEXT_USE_OPTIMIZED_DRAWING
// Find refresh rectangle if we are in a position to optimise refresh
- if (m_cmdId == wxRICHTEXT_INSERT && optimizationLineCharPositions && optimizationLineCharPositions->GetCount() > 0)
+ if ((m_cmdId == wxRICHTEXT_INSERT || m_cmdId == wxRICHTEXT_DELETE) && optimizationLineCharPositions)
{
size_t i;
int firstY = 0;
int lastY = firstVisiblePt.y + clientSize.y;
- bool foundStart = false;
bool foundEnd = false;
// position offset - how many characters were inserted
int positionOffset = GetRange().GetLength();
+ // Determine whether this is Do or Undo, and adjust positionOffset accordingly
+ if ((m_cmdId == wxRICHTEXT_DELETE && isDoCmd) || (m_cmdId == wxRICHTEXT_INSERT && !isDoCmd))
+ positionOffset = - positionOffset;
+
// find the first line which is being drawn at the same position as it was
// before. Since we're talking about a simple insertion, we can assume
// that the rest of the window does not need to be redrawn.
wxRichTextParagraph* para = m_buffer->GetParagraphAtPosition(GetPosition());
+ if (para)
+ {
+ // Find line containing GetPosition().
+ wxRichTextLine* line = NULL;
+ wxRichTextLineList::compatibility_iterator node2 = para->GetLines().GetFirst();
+ while (node2)
+ {
+ wxRichTextLine* l = node2->GetData();
+ wxRichTextRange range = l->GetAbsoluteRange();
+ if (range.Contains(GetRange().GetStart()-1))
+ {
+ line = l;
+ break;
+ }
+ node2 = node2->GetNext();
+ }
+
+ if (line)
+ {
+ // Step back a couple of lines to where we can be sure of reformatting correctly
+ wxRichTextLineList::compatibility_iterator lineNode = para->GetLines().Find(line);
+ if (lineNode)
+ {
+ lineNode = lineNode->GetPrevious();
+ if (lineNode)
+ {
+ line = (wxRichTextLine*) lineNode->GetData();
+ lineNode = lineNode->GetPrevious();
+ if (lineNode)
+ line = (wxRichTextLine*) lineNode->GetData();
+ }
+ }
+
+ firstY = line->GetAbsolutePosition().y;
+ }
+ }
+
wxRichTextObjectList::compatibility_iterator node = m_buffer->GetChildren().Find(para);
while (node)
{
node2 = wxRichTextLineList::compatibility_iterator();
node = wxRichTextObjectList::compatibility_iterator();
}
- else
+ // Detect last line in the buffer
+ else if (!node2->GetNext() && para->GetRange().Contains(m_buffer->GetRange().GetEnd()))
{
- if (!foundStart)
- {
- firstY = pt.y - firstVisiblePt.y;
- foundStart = true;
- }
+ foundEnd = true;
+ lastY = pt.y + line->GetSize().y;
+ node2 = wxRichTextLineList::compatibility_iterator();
+ node = wxRichTextObjectList::compatibility_iterator();
+
+ break;
+ }
+ else
+ {
// search for this line being at the same position as before
for (i = 0; i < optimizationLineCharPositions->GetCount(); i++)
{
{
// Stop, we're now the same as we were
foundEnd = true;
- lastY = pt.y - firstVisiblePt.y;
+
+ lastY = pt.y;
node2 = wxRichTextLineList::compatibility_iterator();
node = wxRichTextObjectList::compatibility_iterator();
node = node->GetNext();
}
- if (!foundStart)
- firstY = firstVisiblePt.y;
+ firstY = wxMax(firstVisiblePt.y, firstY);
if (!foundEnd)
lastY = firstVisiblePt.y + clientSize.y;
- wxRect rect(firstVisiblePt.x, firstY, firstVisiblePt.x + clientSize.x, lastY - firstY);
+ // Convert to device coordinates
+ wxRect rect(m_ctrl->GetPhysicalPoint(wxPoint(firstVisiblePt.x, firstY)), wxSize(clientSize.x, lastY - firstY));
m_ctrl->RefreshRect(rect);
-
- // TODO: we need to make sure that lines are only drawn if in the update region. The rect
- // passed to Draw is currently used in different ways (to pass the position the content should
- // be drawn at as well as the relevant region).
}
else
#endif
if (event.ShiftDown())
{
- bool extendSel = false;
if (m_selectionRange.GetStart() == -2)
- extendSel = ExtendSelection(oldCaretPos, m_caretPosition, wxRICHTEXT_SHIFT_DOWN);
+ ExtendSelection(oldCaretPos, m_caretPosition, wxRICHTEXT_SHIFT_DOWN);
else
- extendSel = ExtendSelection(m_caretPosition, m_caretPosition, wxRICHTEXT_SHIFT_DOWN);
-
- if (extendSel)
- Refresh(false);
+ ExtendSelection(m_caretPosition, m_caretPosition, wxRICHTEXT_SHIFT_DOWN);
}
else
SelectNone();
if (m_caretPosition != position)
{
- bool extendSel = ExtendSelection(m_caretPosition, position, wxRICHTEXT_SHIFT_DOWN);
+ ExtendSelection(m_caretPosition, position, wxRICHTEXT_SHIFT_DOWN);
MoveCaret(position, caretAtLineStart);
SetDefaultStyleToCursorStyle();
-
- if (extendSel)
- Refresh(false);
}
}
}
{
if (flags & wxRICHTEXT_SHIFT_DOWN)
{
+ wxRichTextRange oldSelection = m_selectionRange;
+
// If not currently selecting, start selecting
if (m_selectionRange.GetStart() == -2)
{
m_selectionRange.SetRange(newPos+1, m_selectionAnchor);
}
+ RefreshForSelectionChange(oldSelection, m_selectionRange);
+
if (m_selectionRange.GetStart() > m_selectionRange.GetEnd())
{
wxLogDebug(wxT("Strange selection range"));
PositionCaret();
SetDefaultStyleToCursorStyle();
- if (extendSel)
- Refresh(false);
return true;
}
else
PositionCaret();
SetDefaultStyleToCursorStyle();
- if (extendSel)
- Refresh(false);
return true;
}
else
PositionCaret();
SetDefaultStyleToCursorStyle();
- if (extendSel)
- Refresh(false);
return true;
}
PositionCaret();
SetDefaultStyleToCursorStyle();
- if (extendSel)
- Refresh(false);
return true;
}
PositionCaret();
SetDefaultStyleToCursorStyle();
- if (extendSel)
- Refresh(false);
return true;
}
PositionCaret();
SetDefaultStyleToCursorStyle();
- if (extendSel)
- Refresh(false);
return true;
}
PositionCaret();
SetDefaultStyleToCursorStyle();
- if (extendSel)
- Refresh(false);
return true;
}
PositionCaret();
SetDefaultStyleToCursorStyle();
- if (extendSel)
- Refresh(false);
return true;
}
else
PositionCaret();
SetDefaultStyleToCursorStyle();
- if (extendSel)
- Refresh(false);
return true;
}
else
PositionCaret();
SetDefaultStyleToCursorStyle();
- if (extendSel)
- Refresh(false);
return true;
}
}
PositionCaret();
SetDefaultStyleToCursorStyle();
- if (extendSel)
- Refresh(false);
return true;
}
PositionCaret();
SetDefaultStyleToCursorStyle();
- if (extendSel)
- Refresh(false);
return true;
}
if (!atTop)
GetViewStart(& startX, & startY);
- int maxPositionX = 0; // wxMax(sz.x - clientSize.x, 0);
+ 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 < clientSize.y) && (unitsY*pixelsPerUnit < clientSize.y))
+ return;
+
// Move to previous scroll position if
// possible
- SetScrollbars(0, pixelsPerUnit,
- 0, unitsY,
- wxMin(maxPositionX, startX), wxMin(maxPositionY, startY));
+ SetScrollbars(0, pixelsPerUnit, 0, unitsY, newStartX, newStartY);
}
/// Paint the background
{
if (!(GetSelectionRange() == wxRichTextRange(-2, -2)))
{
- Refresh(false);
+ wxRichTextRange oldSelection = m_selectionRange;
+
m_selectionRange = wxRichTextRange(-2, -2);
+
+ RefreshForSelectionChange(oldSelection, m_selectionRange);
}
m_selectionAnchor = -2;
}
}
else
{
+ wxRichTextRange oldSelection = m_selectionRange;
m_selectionAnchor = from;
m_selectionRange.SetRange(from, to-1);
if (from > -2)
m_caretPosition = from-1;
- Refresh(false);
+ RefreshForSelectionChange(oldSelection, m_selectionRange);
PositionCaret();
}
}
Refresh();
}
+// Refresh the area affected by a selection change
+bool wxRichTextCtrl::RefreshForSelectionChange(const wxRichTextRange& oldSelection, const wxRichTextRange& newSelection)
+{
+ // Calculate the refresh rectangle - just the affected lines
+ long firstPos, lastPos;
+ if (oldSelection.GetStart() == -2 && newSelection.GetStart() != -2)
+ {
+ firstPos = newSelection.GetStart();
+ lastPos = newSelection.GetEnd();
+ }
+ else if (oldSelection.GetStart() != -2 && newSelection.GetStart() == -2)
+ {
+ firstPos = oldSelection.GetStart();
+ lastPos = oldSelection.GetEnd();
+ }
+ else if (oldSelection.GetStart() == -2 && newSelection.GetStart() == -2)
+ {
+ return false;
+ }
+ else
+ {
+ firstPos = wxMin(oldSelection.GetStart(), newSelection.GetStart());
+ lastPos = wxMax(oldSelection.GetEnd(), newSelection.GetEnd());
+ }
+
+ wxRichTextLine* firstLine = GetBuffer().GetLineAtPosition(firstPos);
+ wxRichTextLine* lastLine = GetBuffer().GetLineAtPosition(lastPos);
+
+ if (firstLine && lastLine)
+ {
+ wxSize clientSize = GetClientSize();
+ wxPoint pt1 = GetPhysicalPoint(firstLine->GetAbsolutePosition());
+ wxPoint pt2 = GetPhysicalPoint(lastLine->GetAbsolutePosition()) + wxPoint(0, lastLine->GetSize().y);
+
+ pt1.x = 0;
+ pt1.y = wxMax(0, pt1.y);
+ pt2.x = 0;
+ pt2.y = wxMin(clientSize.y, pt2.y);
+
+ wxRect rect(pt1, wxSize(clientSize.x, pt2.y - pt1.y));
+ RefreshRect(rect, false);
+ }
+ else
+ Refresh(false);
+
+ return true;
+}
+
#endif
// wxUSE_RICHTEXT