]> git.saurik.com Git - wxWidgets.git/commitdiff
Fixed some styling bugs, optimized resize for large files
authorJulian Smart <julian@anthemion.co.uk>
Fri, 21 Oct 2005 13:02:15 +0000 (13:02 +0000)
committerJulian Smart <julian@anthemion.co.uk>
Fri, 21 Oct 2005 13:02:15 +0000 (13:02 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@35962 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/richtext/richtextbuffer.h
include/wx/richtext/richtextctrl.h
samples/richtext/todo.txt
src/richtext/richtextbuffer.cpp
src/richtext/richtextctrl.cpp

index 97469190c856d10f1e1a34a88a9b9a6b383386dd..68e1fefd458d3f7d0ab501d90db80328242b492b 100644 (file)
@@ -134,6 +134,10 @@ class WXDLLIMPEXP_ADV wxTextAttrEx;
 #define wxRICHTEXT_VARIABLE_WIDTH   0x04
 #define wxRICHTEXT_VARIABLE_HEIGHT  0x08
 
+// Only lay out the part of the buffer that lies within
+// the rect passed to Layout.
+#define wxRICHTEXT_LAYOUT_SPECIFIED_RECT 0x10
+
 /*!
  * Flags returned from hit-testing
  */
index fcd77bd77e610505f0a44c5981e40ac1d9bf7c3c..407fc1cb95151ef81ac75be93a36a9a62fcfeed4 100644 (file)
 #define wxRICHTEXT_DEFAULT_TYPE_COLOUR wxColour(0, 0, 200)
 #define wxRICHTEXT_DEFAULT_FOCUS_RECT_COLOUR wxColour(100, 80, 80)
 #define wxRICHTEXT_DEFAULT_CARET_WIDTH 2
+// Minimum buffer size before delayed layout kicks in
+#define wxRICHTEXT_DEFAULT_DELAYED_LAYOUT_THRESHOLD 20000
+// Milliseconds before layout occurs after resize
+#define wxRICHTEXT_DEFAULT_LAYOUT_INTERVAL 50
 
 /*!
  * Forward declarations
@@ -136,6 +140,12 @@ public:
     /// Set filename
     void SetFilename(const wxString& filename) { m_filename = filename; }
 
+    /// Set the threshold in character positions for doing layout optimization during sizing
+    void SetDelayedLayoutThreshold(long threshold) { m_delayedLayoutThreshold = threshold; }
+
+    /// Get the threshold in character positions for doing layout optimization during sizing
+    long GetDelayedLayoutThreshold() const { return m_delayedLayoutThreshold; }
+
 // Operations
 
     // editing
@@ -373,7 +383,7 @@ public:
 
     /// Layout the buffer: which we must do before certain operations, such as
     /// setting the caret position.
-    virtual bool Layout();
+    virtual bool Layout(bool onlyVisibleRect = false);
 
     /// Move the caret to the given character position
     virtual bool MoveCaret(long pos, bool showAtLineStart = false);
@@ -555,6 +565,9 @@ public:
     void OnSetFocus(wxFocusEvent& event);
     void OnKillFocus(wxFocusEvent& event);
 
+    /// Idle-time processing
+    void OnIdle(wxIdleEvent& event);
+
 // Implementation
 
     /// Set font, and also default attributes
@@ -633,10 +646,10 @@ public:
     bool DeleteSelectedContent(long* newPos= NULL);
 
     /// Transform logical to physical
-    wxPoint GetPhysicalPoint(const wxPoint& ptLogical);
+    wxPoint GetPhysicalPoint(const wxPoint& ptLogical) const;
 
     /// Transform physical to logical
-    wxPoint GetLogicalPoint(const wxPoint& ptPhysical);
+    wxPoint GetLogicalPoint(const wxPoint& ptPhysical) const;
 
     /// Finds the caret position for the next word. Direction
     /// is 1 (forward) or -1 (backwards).
@@ -645,6 +658,9 @@ public:
     /// Is the given position visible on the screen?
     bool IsPositionVisible(long pos) const;
 
+    /// Returns the first visible position in the current view
+    long GetFirstVisiblePosition() const;
+
 // Overrides
 
     virtual wxSize DoGetBestSize() const ;
@@ -689,6 +705,14 @@ private:
 
     /// Start position for drag
     wxPoint                 m_dragStart;
+
+    /// Do we need full layout in idle?
+    bool                    m_fullLayoutRequired;
+    wxLongLong              m_fullLayoutTime;
+    long                    m_fullLayoutSavedPosition;
+
+    /// Threshold for doing delayed layout
+    long                    m_delayedLayoutThreshold;
 };
 
 /*!
index 6c3b40396f16f1951feafec2a9254a471c68b7e6..8cc4886ceb7095c78f5a8b67c2c74096be892797 100644 (file)
@@ -10,6 +10,8 @@ BUGS:
   lengths. See wxRichTextCtrl::ExtendSelection.
 - Word forward can miss first word on line.
 - Doesn't correctly undo deletion of bulleted paragraphs.
+- Sizing doesn't restore the scroll position correctly (related
+  to the use of buffer layout optimization and OnIdle full layout.)
 
 
 IMPROVEMENTS:
index 168cac92aa548aa754ed74f071a0497d8bb0ef56..9f180d44215350260dd0f3d0f2ae62f8b610cb03 100644 (file)
@@ -516,7 +516,31 @@ bool wxRichTextParagraphLayoutBox::Draw(wxDC& dc, const wxRichTextRange& range,
 /// Lay the item out
 bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, const wxRect& rect, int style)
 {
-    wxRect availableSpace(rect.x + m_leftMargin,
+    wxRect availableSpace;
+    bool formatRect = (style & wxRICHTEXT_LAYOUT_SPECIFIED_RECT) == wxRICHTEXT_LAYOUT_SPECIFIED_RECT;
+
+    // If only laying out a specific area, the passed rect has a different meaning:
+    // the visible part of the buffer.
+    if (formatRect)
+    {
+        availableSpace = wxRect(0 + m_leftMargin,
+                          0 + m_topMargin,
+                          rect.width - m_leftMargin - m_rightMargin,
+                          rect.height);
+
+        // Invalidate the part of the buffer from the first visible line
+        // to the end. If other parts of the buffer are currently invalid,
+        // then they too will be taken into account if they are above
+        // the visible point.
+        long startPos = 0;
+        wxRichTextLine* line = GetLineAtYPosition(rect.y);
+        if (line)
+            startPos = line->GetAbsoluteRange().GetStart();
+
+        Invalidate(wxRichTextRange(startPos, GetRange().GetEnd()));
+    }
+    else
+        availableSpace = wxRect(rect.x + m_leftMargin,
                           rect.y + m_topMargin,
                           rect.width - m_leftMargin - m_rightMargin,
                           rect.height - m_topMargin - m_bottomMargin);
@@ -530,7 +554,7 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, const wxRect& rect, int styl
     // Get invalid range, rounding to paragraph start/end.
     wxRichTextRange invalidRange = GetInvalidRange(true);
 
-    if (invalidRange == wxRICHTEXT_NONE)
+    if (invalidRange == wxRICHTEXT_NONE && !formatRect)
         return true;
 
     if (invalidRange == wxRICHTEXT_ALL)
@@ -556,6 +580,9 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, const wxRect& rect, int styl
         }
     }
 
+    // A way to force speedy rest-of-buffer layout (the 'else' below)
+    bool forceQuickLayout = false;
+        
     while (node)
     {
         // Assume this box only contains paragraphs
@@ -564,13 +591,19 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, const wxRect& rect, int styl
         wxASSERT (child != NULL);
 
         // TODO: what if the child hasn't been laid out (e.g. involved in Undo) but still has 'old' lines
-        if (child && (layoutAll || child->GetLines().GetCount() == 0 || !child->GetRange().IsOutside(invalidRange)))
+        if (child && !forceQuickLayout && (layoutAll || child->GetLines().GetCount() == 0 || !child->GetRange().IsOutside(invalidRange)))
         {
             child->Layout(dc, availableSpace, style);
 
             // Layout must set the cached size
             availableSpace.y += child->GetCachedSize().y;
             maxWidth = wxMax(maxWidth, child->GetCachedSize().x);
+
+            // If we're just formatting the visible part of the buffer,
+            // and we're now past the bottom of the window, start quick
+            // layout.
+            if (formatRect && child->GetPosition().y > rect.GetBottom())
+                forceQuickLayout = true;
         }
         else
         {
@@ -2540,7 +2573,12 @@ wxRichTextObject* wxRichTextParagraph::SplitAt(long pos, wxRichTextObject** prev
         if (pos == child->GetRange().GetStart())
         {
             if (previousObject)
-                *previousObject = child;
+            {
+                if (node->GetPrevious())
+                    *previousObject = node->GetPrevious()->GetData();
+                else
+                    *previousObject = NULL;
+            }
 
             return child;
         }
@@ -4321,23 +4359,23 @@ bool wxTextAttrEqPartial(const wxTextAttrEx& attr1, const wxTextAttrEx& attr2, i
         (attr1.GetRightIndent() != attr2.GetRightIndent()))
         return false;
 
-    if ((flags && wxTEXT_ATTR_PARA_SPACING_AFTER) &&
+    if ((flags & wxTEXT_ATTR_PARA_SPACING_AFTER) &&
         (attr1.GetParagraphSpacingAfter() != attr2.GetParagraphSpacingAfter()))
         return false;
 
-    if ((flags && wxTEXT_ATTR_PARA_SPACING_BEFORE) &&
+    if ((flags & wxTEXT_ATTR_PARA_SPACING_BEFORE) &&
         (attr1.GetParagraphSpacingBefore() != attr2.GetParagraphSpacingBefore()))
         return false;
 
-    if ((flags && wxTEXT_ATTR_LINE_SPACING) &&
+    if ((flags & wxTEXT_ATTR_LINE_SPACING) &&
         (attr1.GetLineSpacing() != attr2.GetLineSpacing()))
         return false;
 
-    if ((flags && wxTEXT_ATTR_CHARACTER_STYLE_NAME) &&
+    if ((flags & wxTEXT_ATTR_CHARACTER_STYLE_NAME) &&
         (attr1.GetCharacterStyleName() != attr2.GetCharacterStyleName()))
         return false;
 
-    if ((flags && wxTEXT_ATTR_PARAGRAPH_STYLE_NAME) &&
+    if ((flags & wxTEXT_ATTR_PARAGRAPH_STYLE_NAME) &&
         (attr1.GetParagraphStyleName() != attr2.GetParagraphStyleName()))
         return false;
 
@@ -4403,23 +4441,23 @@ bool wxTextAttrEqPartial(const wxTextAttrEx& attr1, const wxRichTextAttr& attr2,
         (attr1.GetRightIndent() != attr2.GetRightIndent()))
         return false;
 
-    if ((flags && wxTEXT_ATTR_PARA_SPACING_AFTER) &&
+    if ((flags & wxTEXT_ATTR_PARA_SPACING_AFTER) &&
         (attr1.GetParagraphSpacingAfter() != attr2.GetParagraphSpacingAfter()))
         return false;
 
-    if ((flags && wxTEXT_ATTR_PARA_SPACING_BEFORE) &&
+    if ((flags & wxTEXT_ATTR_PARA_SPACING_BEFORE) &&
         (attr1.GetParagraphSpacingBefore() != attr2.GetParagraphSpacingBefore()))
         return false;
 
-    if ((flags && wxTEXT_ATTR_LINE_SPACING) &&
+    if ((flags & wxTEXT_ATTR_LINE_SPACING) &&
         (attr1.GetLineSpacing() != attr2.GetLineSpacing()))
         return false;
 
-    if ((flags && wxTEXT_ATTR_CHARACTER_STYLE_NAME) &&
+    if ((flags & wxTEXT_ATTR_CHARACTER_STYLE_NAME) &&
         (attr1.GetCharacterStyleName() != attr2.GetCharacterStyleName()))
         return false;
 
-    if ((flags && wxTEXT_ATTR_PARAGRAPH_STYLE_NAME) &&
+    if ((flags & wxTEXT_ATTR_PARAGRAPH_STYLE_NAME) &&
         (attr1.GetParagraphStyleName() != attr2.GetParagraphStyleName()))
         return false;
 
index 272fa94fb343d138162f83e48f971385b90146fc..8e8ec6227247268dbb7e41f90e33e0c02e9de72d 100644 (file)
@@ -56,6 +56,7 @@ BEGIN_EVENT_TABLE( wxRichTextCtrl, wxScrolledWindow )
 #endif
     EVT_PAINT(wxRichTextCtrl::OnPaint)
     EVT_ERASE_BACKGROUND(wxRichTextCtrl::OnEraseBackground)
+    EVT_IDLE(wxRichTextCtrl::OnIdle)
     EVT_LEFT_DOWN(wxRichTextCtrl::OnLeftClick)
     EVT_MOTION(wxRichTextCtrl::OnMoveMouse)
     EVT_LEFT_UP(wxRichTextCtrl::OnLeftUp)
@@ -177,6 +178,10 @@ void wxRichTextCtrl::Init()
     m_editable = true;
     m_caretAtLineStart = false;
     m_dragging = false;
+    m_fullLayoutRequired = false;
+    m_fullLayoutTime = 0;
+    m_fullLayoutSavedPosition = 0;
+    m_delayedLayoutThreshold = wxRICHTEXT_DEFAULT_DELAYED_LAYOUT_THRESHOLD;
 }
 
 /// Call Freeze to prevent refresh
@@ -1323,13 +1328,39 @@ bool wxRichTextCtrl::WordRight(int WXUNUSED(n), int flags)
 /// Sizing
 void wxRichTextCtrl::OnSize(wxSizeEvent& event)
 {
-    GetBuffer().Invalidate(wxRICHTEXT_ALL);
+    // Only do sizing optimization for large buffers
+    if (GetBuffer().GetRange().GetEnd() > m_delayedLayoutThreshold)
+    {
+        m_fullLayoutRequired = true;
+        m_fullLayoutTime = wxGetLocalTimeMillis();
+        m_fullLayoutSavedPosition = GetFirstVisiblePosition();
+        Layout(true /* onlyVisibleRect */);
+    }
+    else
+        GetBuffer().Invalidate(wxRICHTEXT_ALL);
 
     RecreateBuffer();
 
     event.Skip();
 }
 
+
+/// Idle-time processing
+void wxRichTextCtrl::OnIdle(wxIdleEvent& event)
+{
+    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();
+    }
+    event.Skip();
+}
+
 /// Set up scrollbars, e.g. after a resize
 void wxRichTextCtrl::SetupScrollbars(bool atTop)
 {
@@ -2119,8 +2150,8 @@ bool wxRichTextCtrl::SetFont(const wxFont& font)
     return true;
 }
 
-/// Transform logical to physical (unscrolling)
-wxPoint wxRichTextCtrl::GetPhysicalPoint(const wxPoint& ptLogical)
+/// Transform logical to physical
+wxPoint wxRichTextCtrl::GetPhysicalPoint(const wxPoint& ptLogical) const
 {
     wxPoint pt;
     CalcScrolledPosition(ptLogical.x, ptLogical.y, & pt.x, & pt.y);
@@ -2129,7 +2160,7 @@ wxPoint wxRichTextCtrl::GetPhysicalPoint(const wxPoint& ptLogical)
 }
 
 /// Transform physical to logical
-wxPoint wxRichTextCtrl::GetLogicalPoint(const wxPoint& ptPhysical)
+wxPoint wxRichTextCtrl::GetLogicalPoint(const wxPoint& ptPhysical) const
 {
     wxPoint pt;
     CalcUnscrolledPosition(ptPhysical.x, ptPhysical.y, & pt.x, & pt.y);
@@ -2213,15 +2244,22 @@ bool wxRichTextCtrl::MoveCaret(long pos, bool showAtLineStart)
 
 /// Layout the buffer: which we must do before certain operations, such as
 /// setting the caret position.
-bool wxRichTextCtrl::Layout()
+bool wxRichTextCtrl::Layout(bool onlyVisibleRect)
 {
-    if (GetBuffer().GetDirty())
+    if (GetBuffer().GetDirty() || onlyVisibleRect)
     {
         wxRect availableSpace(GetClientSize());
         if (availableSpace.width == 0)
             availableSpace.width = 10;
         if (availableSpace.height == 0)
             availableSpace.height = 10;
+
+        int flags = wxRICHTEXT_FIXED_WIDTH|wxRICHTEXT_VARIABLE_HEIGHT;
+        if (onlyVisibleRect)
+        {
+            flags |= wxRICHTEXT_LAYOUT_SPECIFIED_RECT;
+            availableSpace.SetPosition(GetLogicalPoint(wxPoint(0, 0)));
+        }
         
         wxClientDC dc(this);
         dc.SetFont(GetFont());
@@ -2230,7 +2268,7 @@ bool wxRichTextCtrl::Layout()
         
         GetBuffer().Defragment();
         GetBuffer().UpdateRanges();     // If items were deleted, ranges need recalculation
-        GetBuffer().Layout(dc, availableSpace, wxRICHTEXT_FIXED_WIDTH|wxRICHTEXT_VARIABLE_HEIGHT);
+        GetBuffer().Layout(dc, availableSpace, flags);
         GetBuffer().SetDirty(false);
         
         if (!IsFrozen())
@@ -2354,7 +2392,7 @@ bool wxRichTextCtrl::ApplyUnderlineToSelection()
 {
     wxRichTextAttr attr;
     attr.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE);
-    attr.SetFontWeight(!IsSelectionUnderlined());
+    attr.SetFontUnderlined(!IsSelectionUnderlined());
 
     if (HasSelection())
         return SetStyle(GetSelectionRange(), attr);
@@ -2415,6 +2453,16 @@ bool wxRichTextCtrl::SetDefaultStyleToCursorStyle()
         return false;
 }
 
+/// Returns the first visible position in the current view
+long wxRichTextCtrl::GetFirstVisiblePosition() const
+{
+    wxRichTextLine* line = GetBuffer().GetLineAtYPosition(GetLogicalPoint(wxPoint(0, 0)).y);
+    if (line)
+        return line->GetAbsoluteRange().GetStart();
+    else
+        return 0;
+}
+
 #endif
     // wxUSE_RICHTEXT