]> git.saurik.com Git - wxWidgets.git/commitdiff
Further wxRichTextCtrl performance improvements
authorJulian Smart <julian@anthemion.co.uk>
Sun, 27 Apr 2008 13:29:53 +0000 (13:29 +0000)
committerJulian Smart <julian@anthemion.co.uk>
Sun, 27 Apr 2008 13:29:53 +0000 (13:29 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@53382 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/richtext/richtextbuffer.h
include/wx/richtext/richtextctrl.h
src/richtext/richtextbuffer.cpp
src/richtext/richtextctrl.cpp

index 4201ec88450fd6362659a80726c21adf4ced5313..c5e4fb68b41a239ae384ffa179d0f56d140765ac 100644 (file)
@@ -1698,7 +1698,7 @@ public:
 
     /// Update the control appearance
     void UpdateAppearance(long caretPosition, bool sendUpdateEvent = false,
 
     /// Update the control appearance
     void UpdateAppearance(long caretPosition, bool sendUpdateEvent = false,
-                            wxArrayInt* optimizationLineCharPositions = NULL, wxArrayInt* optimizationLineYPositions = NULL);
+                            wxArrayInt* optimizationLineCharPositions = NULL, wxArrayInt* optimizationLineYPositions = NULL, bool isDoCmd = true);
 
     /// Replace the buffer paragraphs with the given fragment.
     void ApplyParagraphs(const wxRichTextParagraphLayoutBox& fragment);
 
     /// Replace the buffer paragraphs with the given fragment.
     void ApplyParagraphs(const wxRichTextParagraphLayoutBox& fragment);
@@ -1707,6 +1707,9 @@ public:
     wxRichTextParagraphLayoutBox& GetNewParagraphs() { return m_newParagraphs; }
     wxRichTextParagraphLayoutBox& GetOldParagraphs() { return m_oldParagraphs; }
 
     wxRichTextParagraphLayoutBox& GetNewParagraphs() { return m_newParagraphs; }
     wxRichTextParagraphLayoutBox& GetOldParagraphs() { return m_oldParagraphs; }
 
+    /// Calculate arrays for refresh optimization
+    void CalculateRefreshOptimizations(wxArrayInt& optimizationLineCharPositions, wxArrayInt& optimizationLineYPositions);
+
     /// Set/get the position used for e.g. insertion
     void SetPosition(long pos) { m_position = pos; }
     long GetPosition() const { return m_position; }
     /// Set/get the position used for e.g. insertion
     void SetPosition(long pos) { m_position = pos; }
     long GetPosition() const { return m_position; }
index 47b752f9266dd15a1c86625226bc7c59cca0b161..ff951013014f6fbaa00281781b39b735061832e2 100644 (file)
@@ -683,6 +683,9 @@ public:
     /// Scroll into view. This takes a _caret_ position.
     virtual bool ScrollIntoView(long position, int keyCode);
 
     /// Scroll into view. This takes a _caret_ position.
     virtual bool ScrollIntoView(long position, int keyCode);
 
+    /// Refresh the area affected by a selection change
+    bool RefreshForSelectionChange(const wxRichTextRange& oldSelection, const wxRichTextRange& newSelection);
+
     /// The caret position is the character position just before the caret.
     /// A value of -1 means the caret is at the start of the buffer.
     void SetCaretPosition(long position, bool showAtLineStart = false) ;
     /// The caret position is the character position just before the caret.
     /// A value of -1 means the caret is at the start of the buffer.
     void SetCaretPosition(long position, bool showAtLineStart = false) ;
index a258c962e417e0acc165ea9747b22042b4680b81..0c2e22642a6d187638f19e07a237ac5edc943dc3 100644 (file)
@@ -589,7 +589,7 @@ bool wxRichTextParagraphLayoutBox::Draw(wxDC& dc, const wxRichTextRange& range,
                 // Skip
             }
             else
                 // Skip
             }
             else
-                child->Draw(dc, range, selectionRange, childRect, descent, style);
+                child->Draw(dc, range, selectionRange, rect, descent, style);
         }
 
         node = node->GetNext();
         }
 
         node = node->GetNext();
@@ -857,25 +857,29 @@ wxRichTextLine* wxRichTextParagraphLayoutBox::GetLineAtPosition(long pos, bool c
     wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
     while (node)
     {
     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();
         }
 
         node = node->GetNext();
@@ -3105,7 +3109,7 @@ wxRichTextParagraph::~wxRichTextParagraph()
 }
 
 /// Draw the item
 }
 
 /// 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();
 
 {
     wxTextAttr attr = GetCombinedAttributes();
 
@@ -3184,52 +3188,56 @@ bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
         wxRichTextLine* line = node->GetData();
         wxRichTextRange lineRange = line->GetAbsoluteRange();
 
         wxRichTextLine* line = node->GetData();
         wxRichTextRange lineRange = line->GetAbsoluteRange();
 
-        int maxDescent = line->GetDescent();
-
         // Lines are specified relative to the paragraph
 
         wxPoint linePosition = line->GetPosition() + GetPosition();
         // 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
 #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();
         }
 
         node = node->GetNext();
@@ -5548,8 +5556,6 @@ bool wxRichTextBuffer::BeginStyle(const wxTextAttr& style)
 
     SetDefaultStyle(newStyle);
 
 
     SetDefaultStyle(newStyle);
 
-    // wxLogDebug("Default style size = %d", GetDefaultStyle().GetFont().GetPointSize());
-
     return true;
 }
 
     return true;
 }
 
@@ -6518,6 +6524,58 @@ wxRichTextAction::~wxRichTextAction()
 {
 }
 
 {
 }
 
+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);
 bool wxRichTextAction::Do()
 {
     m_buffer->Modify(true);
@@ -6532,49 +6590,7 @@ bool wxRichTextAction::Do()
             wxArrayInt optimizationLineYPositions;
 
 #if wxRICHTEXT_USE_OPTIMIZED_DRAWING
             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);
 #endif
 
             m_buffer->InsertFragment(GetRange().GetStart(), m_newParagraphs);
@@ -6599,10 +6615,7 @@ bool wxRichTextAction::Do()
 
             newCaretPosition = wxMin(newCaretPosition, (m_buffer->GetRange().GetEnd()-1));
 
 
             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,
 
             wxRichTextEvent cmdEvent(
                 wxEVT_COMMAND_RICHTEXT_CONTENT_INSERTED,
@@ -6617,6 +6630,13 @@ bool wxRichTextAction::Do()
         }
     case wxRICHTEXT_DELETE:
         {
         }
     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()));
             m_buffer->DeleteRange(GetRange());
             m_buffer->UpdateRanges();
             m_buffer->Invalidate(wxRichTextRange(GetRange().GetStart(), GetRange().GetStart()));
@@ -6625,7 +6645,7 @@ bool wxRichTextAction::Do()
             if (caretPos >= m_buffer->GetRange().GetEnd())
                 caretPos --;
 
             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,
 
             wxRichTextEvent cmdEvent(
                 wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED,
@@ -6671,13 +6691,20 @@ bool wxRichTextAction::Undo()
     {
     case wxRICHTEXT_INSERT:
         {
     {
     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;
 
             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,
 
             wxRichTextEvent cmdEvent(
                 wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED,
@@ -6692,11 +6719,18 @@ bool wxRichTextAction::Undo()
         }
     case wxRICHTEXT_DELETE:
         {
         }
     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());
 
             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,
 
             wxRichTextEvent cmdEvent(
                 wxEVT_COMMAND_RICHTEXT_CONTENT_INSERTED,
@@ -6735,7 +6769,7 @@ bool wxRichTextAction::Undo()
 }
 
 /// Update the control appearance
 }
 
 /// 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 (m_ctrl)
     {
@@ -6746,7 +6780,7 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent
 
 #if wxRICHTEXT_USE_OPTIMIZED_DRAWING
             // Find refresh rectangle if we are in a position to optimise refresh
 
 #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;
 
             {
                 size_t i;
 
@@ -6757,17 +6791,57 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent
                 int firstY = 0;
                 int lastY = firstVisiblePt.y + clientSize.y;
 
                 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();
 
                 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());
                 // 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)
                 {
                 wxRichTextObjectList::compatibility_iterator node = m_buffer->GetChildren().Find(para);
                 while (node)
                 {
@@ -6787,14 +6861,19 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent
                             node2 = wxRichTextLineList::compatibility_iterator();
                             node = wxRichTextObjectList::compatibility_iterator();
                         }
                             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++)
                             {
                             // search for this line being at the same position as before
                             for (i = 0; i < optimizationLineCharPositions->GetCount(); i++)
                             {
@@ -6803,7 +6882,8 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent
                                 {
                                     // Stop, we're now the same as we were
                                     foundEnd = true;
                                 {
                                     // 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();
 
                                     node2 = wxRichTextLineList::compatibility_iterator();
                                     node = wxRichTextObjectList::compatibility_iterator();
@@ -6821,17 +6901,13 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent
                         node = node->GetNext();
                 }
 
                         node = node->GetNext();
                 }
 
-                if (!foundStart)
-                    firstY = firstVisiblePt.y;
+                firstY = wxMax(firstVisiblePt.y, firstY);
                 if (!foundEnd)
                     lastY = firstVisiblePt.y + clientSize.y;
 
                 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);
                 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
             }
             else
 #endif
index 76221b479fb141e754ee6c63703e2f17fc0a90a1..61ff087e2b61fb8fc05ae41bc4c494ba96e6613e 100644 (file)
@@ -364,14 +364,10 @@ void wxRichTextCtrl::OnLeftClick(wxMouseEvent& event)
 
         if (event.ShiftDown())
         {
 
         if (event.ShiftDown())
         {
-            bool extendSel = false;
             if (m_selectionRange.GetStart() == -2)
             if (m_selectionRange.GetStart() == -2)
-                extendSel = ExtendSelection(oldCaretPos, m_caretPosition, wxRICHTEXT_SHIFT_DOWN);
+                ExtendSelection(oldCaretPos, m_caretPosition, wxRICHTEXT_SHIFT_DOWN);
             else
             else
-                extendSel = ExtendSelection(m_caretPosition, m_caretPosition, wxRICHTEXT_SHIFT_DOWN);
-
-            if (extendSel)
-                Refresh(false);
+                ExtendSelection(m_caretPosition, m_caretPosition, wxRICHTEXT_SHIFT_DOWN);
         }
         else
             SelectNone();
         }
         else
             SelectNone();
@@ -500,13 +496,10 @@ void wxRichTextCtrl::OnMoveMouse(wxMouseEvent& event)
 
         if (m_caretPosition != position)
         {
 
         if (m_caretPosition != position)
         {
-            bool extendSel = ExtendSelection(m_caretPosition, position, wxRICHTEXT_SHIFT_DOWN);
+            ExtendSelection(m_caretPosition, position, wxRICHTEXT_SHIFT_DOWN);
 
             MoveCaret(position, caretAtLineStart);
             SetDefaultStyleToCursorStyle();
 
             MoveCaret(position, caretAtLineStart);
             SetDefaultStyleToCursorStyle();
-
-            if (extendSel)
-                Refresh(false);
         }
     }
 }
         }
     }
 }
@@ -1006,6 +999,8 @@ bool wxRichTextCtrl::ExtendSelection(long oldPos, long newPos, int flags)
 {
     if (flags & wxRICHTEXT_SHIFT_DOWN)
     {
 {
     if (flags & wxRICHTEXT_SHIFT_DOWN)
     {
+        wxRichTextRange oldSelection = m_selectionRange;
+
         // If not currently selecting, start selecting
         if (m_selectionRange.GetStart() == -2)
         {
         // If not currently selecting, start selecting
         if (m_selectionRange.GetStart() == -2)
         {
@@ -1026,6 +1021,8 @@ bool wxRichTextCtrl::ExtendSelection(long oldPos, long newPos, int flags)
                 m_selectionRange.SetRange(newPos+1, m_selectionAnchor);
         }
 
                 m_selectionRange.SetRange(newPos+1, m_selectionAnchor);
         }
 
+        RefreshForSelectionChange(oldSelection, m_selectionRange);
+
         if (m_selectionRange.GetStart() > m_selectionRange.GetEnd())
         {
             wxLogDebug(wxT("Strange selection range"));
         if (m_selectionRange.GetStart() > m_selectionRange.GetEnd())
         {
             wxLogDebug(wxT("Strange selection range"));
@@ -1297,8 +1294,6 @@ bool wxRichTextCtrl::MoveRight(int noPositions, int flags)
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (extendSel)
-            Refresh(false);
         return true;
     }
     else
         return true;
     }
     else
@@ -1326,8 +1321,6 @@ bool wxRichTextCtrl::MoveLeft(int noPositions, int flags)
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (extendSel)
-            Refresh(false);
         return true;
     }
     else
         return true;
     }
     else
@@ -1417,8 +1410,6 @@ bool wxRichTextCtrl::MoveDown(int noLines, int flags)
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (extendSel)
-            Refresh(false);
         return true;
     }
 
         return true;
     }
 
@@ -1440,8 +1431,6 @@ bool wxRichTextCtrl::MoveToParagraphEnd(int flags)
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (extendSel)
-            Refresh(false);
         return true;
     }
 
         return true;
     }
 
@@ -1463,8 +1452,6 @@ bool wxRichTextCtrl::MoveToParagraphStart(int flags)
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (extendSel)
-            Refresh(false);
         return true;
     }
 
         return true;
     }
 
@@ -1488,8 +1475,6 @@ bool wxRichTextCtrl::MoveToLineEnd(int flags)
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (extendSel)
-            Refresh(false);
         return true;
     }
 
         return true;
     }
 
@@ -1515,8 +1500,6 @@ bool wxRichTextCtrl::MoveToLineStart(int flags)
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (extendSel)
-            Refresh(false);
         return true;
     }
 
         return true;
     }
 
@@ -1536,8 +1519,6 @@ bool wxRichTextCtrl::MoveHome(int flags)
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (extendSel)
-            Refresh(false);
         return true;
     }
     else
         return true;
     }
     else
@@ -1559,8 +1540,6 @@ bool wxRichTextCtrl::MoveEnd(int flags)
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (extendSel)
-            Refresh(false);
         return true;
     }
     else
         return true;
     }
     else
@@ -1600,8 +1579,6 @@ bool wxRichTextCtrl::PageDown(int noPages, int flags)
                 PositionCaret();
                 SetDefaultStyleToCursorStyle();
 
                 PositionCaret();
                 SetDefaultStyleToCursorStyle();
 
-                if (extendSel)
-                    Refresh(false);
                 return true;
             }
         }
                 return true;
             }
         }
@@ -1719,8 +1696,6 @@ bool wxRichTextCtrl::WordLeft(int WXUNUSED(n), int flags)
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (extendSel)
-            Refresh(false);
         return true;
     }
 
         return true;
     }
 
@@ -1743,8 +1718,6 @@ bool wxRichTextCtrl::WordRight(int WXUNUSED(n), int flags)
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (extendSel)
-            Refresh(false);
         return true;
     }
 
         return true;
     }
 
@@ -1831,14 +1804,31 @@ void wxRichTextCtrl::SetupScrollbars(bool atTop)
     if (!atTop)
         GetViewStart(& startX, & startY);
 
     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 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
     // 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
 }
 
 /// Paint the background
@@ -1957,8 +1947,11 @@ void wxRichTextCtrl::SelectNone()
 {
     if (!(GetSelectionRange() == wxRichTextRange(-2, -2)))
     {
 {
     if (!(GetSelectionRange() == wxRichTextRange(-2, -2)))
     {
-        Refresh(false);
+        wxRichTextRange oldSelection = m_selectionRange;
+
         m_selectionRange = wxRichTextRange(-2, -2);
         m_selectionRange = wxRichTextRange(-2, -2);
+
+        RefreshForSelectionChange(oldSelection, m_selectionRange);
     }
     m_selectionAnchor = -2;
 }
     }
     m_selectionAnchor = -2;
 }
@@ -2357,12 +2350,13 @@ void wxRichTextCtrl::DoSetSelection(long from, long to, bool WXUNUSED(scrollCare
     }
     else
     {
     }
     else
     {
+        wxRichTextRange oldSelection = m_selectionRange;
         m_selectionAnchor = from;
         m_selectionRange.SetRange(from, to-1);
         if (from > -2)
             m_caretPosition = from-1;
 
         m_selectionAnchor = from;
         m_selectionRange.SetRange(from, to-1);
         if (from > -2)
             m_caretPosition = from-1;
 
-        Refresh(false);
+        RefreshForSelectionChange(oldSelection, m_selectionRange);
         PositionCaret();
     }
 }
         PositionCaret();
     }
 }
@@ -3195,5 +3189,53 @@ void wxRichTextCtrl::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event)
     Refresh();
 }
 
     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
 #endif
     // wxUSE_RICHTEXT