Fixed some styling bugs, optimized resize for large files

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@35962 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Julian Smart
2005-10-21 13:02:15 +00:00
parent 907c39f19b
commit 4d551ad5e5
5 changed files with 141 additions and 25 deletions

View File

@@ -134,6 +134,10 @@ class WXDLLIMPEXP_ADV wxTextAttrEx;
#define wxRICHTEXT_VARIABLE_WIDTH 0x04 #define wxRICHTEXT_VARIABLE_WIDTH 0x04
#define wxRICHTEXT_VARIABLE_HEIGHT 0x08 #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 * Flags returned from hit-testing
*/ */

View File

@@ -57,6 +57,10 @@
#define wxRICHTEXT_DEFAULT_TYPE_COLOUR wxColour(0, 0, 200) #define wxRICHTEXT_DEFAULT_TYPE_COLOUR wxColour(0, 0, 200)
#define wxRICHTEXT_DEFAULT_FOCUS_RECT_COLOUR wxColour(100, 80, 80) #define wxRICHTEXT_DEFAULT_FOCUS_RECT_COLOUR wxColour(100, 80, 80)
#define wxRICHTEXT_DEFAULT_CARET_WIDTH 2 #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 * Forward declarations
@@ -136,6 +140,12 @@ public:
/// Set filename /// Set filename
void SetFilename(const wxString& filename) { m_filename = 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 // Operations
// editing // editing
@@ -373,7 +383,7 @@ public:
/// Layout the buffer: which we must do before certain operations, such as /// Layout the buffer: which we must do before certain operations, such as
/// setting the caret position. /// setting the caret position.
virtual bool Layout(); virtual bool Layout(bool onlyVisibleRect = false);
/// Move the caret to the given character position /// Move the caret to the given character position
virtual bool MoveCaret(long pos, bool showAtLineStart = false); virtual bool MoveCaret(long pos, bool showAtLineStart = false);
@@ -555,6 +565,9 @@ public:
void OnSetFocus(wxFocusEvent& event); void OnSetFocus(wxFocusEvent& event);
void OnKillFocus(wxFocusEvent& event); void OnKillFocus(wxFocusEvent& event);
/// Idle-time processing
void OnIdle(wxIdleEvent& event);
// Implementation // Implementation
/// Set font, and also default attributes /// Set font, and also default attributes
@@ -633,10 +646,10 @@ public:
bool DeleteSelectedContent(long* newPos= NULL); bool DeleteSelectedContent(long* newPos= NULL);
/// Transform logical to physical /// Transform logical to physical
wxPoint GetPhysicalPoint(const wxPoint& ptLogical); wxPoint GetPhysicalPoint(const wxPoint& ptLogical) const;
/// Transform physical to logical /// Transform physical to logical
wxPoint GetLogicalPoint(const wxPoint& ptPhysical); wxPoint GetLogicalPoint(const wxPoint& ptPhysical) const;
/// Finds the caret position for the next word. Direction /// Finds the caret position for the next word. Direction
/// is 1 (forward) or -1 (backwards). /// is 1 (forward) or -1 (backwards).
@@ -645,6 +658,9 @@ public:
/// Is the given position visible on the screen? /// Is the given position visible on the screen?
bool IsPositionVisible(long pos) const; bool IsPositionVisible(long pos) const;
/// Returns the first visible position in the current view
long GetFirstVisiblePosition() const;
// Overrides // Overrides
virtual wxSize DoGetBestSize() const ; virtual wxSize DoGetBestSize() const ;
@@ -689,6 +705,14 @@ private:
/// Start position for drag /// Start position for drag
wxPoint m_dragStart; 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;
}; };
/*! /*!

View File

@@ -10,6 +10,8 @@ BUGS:
lengths. See wxRichTextCtrl::ExtendSelection. lengths. See wxRichTextCtrl::ExtendSelection.
- Word forward can miss first word on line. - Word forward can miss first word on line.
- Doesn't correctly undo deletion of bulleted paragraphs. - 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: IMPROVEMENTS:

View File

@@ -516,7 +516,31 @@ bool wxRichTextParagraphLayoutBox::Draw(wxDC& dc, const wxRichTextRange& range,
/// Lay the item out /// Lay the item out
bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, const wxRect& rect, int style) 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.y + m_topMargin,
rect.width - m_leftMargin - m_rightMargin, rect.width - m_leftMargin - m_rightMargin,
rect.height - m_topMargin - m_bottomMargin); 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. // Get invalid range, rounding to paragraph start/end.
wxRichTextRange invalidRange = GetInvalidRange(true); wxRichTextRange invalidRange = GetInvalidRange(true);
if (invalidRange == wxRICHTEXT_NONE) if (invalidRange == wxRICHTEXT_NONE && !formatRect)
return true; return true;
if (invalidRange == wxRICHTEXT_ALL) 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) while (node)
{ {
// Assume this box only contains paragraphs // Assume this box only contains paragraphs
@@ -564,13 +591,19 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, const wxRect& rect, int styl
wxASSERT (child != NULL); wxASSERT (child != NULL);
// TODO: what if the child hasn't been laid out (e.g. involved in Undo) but still has 'old' lines // 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); child->Layout(dc, availableSpace, style);
// Layout must set the cached size // Layout must set the cached size
availableSpace.y += child->GetCachedSize().y; availableSpace.y += child->GetCachedSize().y;
maxWidth = wxMax(maxWidth, child->GetCachedSize().x); 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 else
{ {
@@ -2540,7 +2573,12 @@ wxRichTextObject* wxRichTextParagraph::SplitAt(long pos, wxRichTextObject** prev
if (pos == child->GetRange().GetStart()) if (pos == child->GetRange().GetStart())
{ {
if (previousObject) if (previousObject)
*previousObject = child; {
if (node->GetPrevious())
*previousObject = node->GetPrevious()->GetData();
else
*previousObject = NULL;
}
return child; return child;
} }
@@ -4321,23 +4359,23 @@ bool wxTextAttrEqPartial(const wxTextAttrEx& attr1, const wxTextAttrEx& attr2, i
(attr1.GetRightIndent() != attr2.GetRightIndent())) (attr1.GetRightIndent() != attr2.GetRightIndent()))
return false; return false;
if ((flags && wxTEXT_ATTR_PARA_SPACING_AFTER) && if ((flags & wxTEXT_ATTR_PARA_SPACING_AFTER) &&
(attr1.GetParagraphSpacingAfter() != attr2.GetParagraphSpacingAfter())) (attr1.GetParagraphSpacingAfter() != attr2.GetParagraphSpacingAfter()))
return false; return false;
if ((flags && wxTEXT_ATTR_PARA_SPACING_BEFORE) && if ((flags & wxTEXT_ATTR_PARA_SPACING_BEFORE) &&
(attr1.GetParagraphSpacingBefore() != attr2.GetParagraphSpacingBefore())) (attr1.GetParagraphSpacingBefore() != attr2.GetParagraphSpacingBefore()))
return false; return false;
if ((flags && wxTEXT_ATTR_LINE_SPACING) && if ((flags & wxTEXT_ATTR_LINE_SPACING) &&
(attr1.GetLineSpacing() != attr2.GetLineSpacing())) (attr1.GetLineSpacing() != attr2.GetLineSpacing()))
return false; return false;
if ((flags && wxTEXT_ATTR_CHARACTER_STYLE_NAME) && if ((flags & wxTEXT_ATTR_CHARACTER_STYLE_NAME) &&
(attr1.GetCharacterStyleName() != attr2.GetCharacterStyleName())) (attr1.GetCharacterStyleName() != attr2.GetCharacterStyleName()))
return false; return false;
if ((flags && wxTEXT_ATTR_PARAGRAPH_STYLE_NAME) && if ((flags & wxTEXT_ATTR_PARAGRAPH_STYLE_NAME) &&
(attr1.GetParagraphStyleName() != attr2.GetParagraphStyleName())) (attr1.GetParagraphStyleName() != attr2.GetParagraphStyleName()))
return false; return false;
@@ -4403,23 +4441,23 @@ bool wxTextAttrEqPartial(const wxTextAttrEx& attr1, const wxRichTextAttr& attr2,
(attr1.GetRightIndent() != attr2.GetRightIndent())) (attr1.GetRightIndent() != attr2.GetRightIndent()))
return false; return false;
if ((flags && wxTEXT_ATTR_PARA_SPACING_AFTER) && if ((flags & wxTEXT_ATTR_PARA_SPACING_AFTER) &&
(attr1.GetParagraphSpacingAfter() != attr2.GetParagraphSpacingAfter())) (attr1.GetParagraphSpacingAfter() != attr2.GetParagraphSpacingAfter()))
return false; return false;
if ((flags && wxTEXT_ATTR_PARA_SPACING_BEFORE) && if ((flags & wxTEXT_ATTR_PARA_SPACING_BEFORE) &&
(attr1.GetParagraphSpacingBefore() != attr2.GetParagraphSpacingBefore())) (attr1.GetParagraphSpacingBefore() != attr2.GetParagraphSpacingBefore()))
return false; return false;
if ((flags && wxTEXT_ATTR_LINE_SPACING) && if ((flags & wxTEXT_ATTR_LINE_SPACING) &&
(attr1.GetLineSpacing() != attr2.GetLineSpacing())) (attr1.GetLineSpacing() != attr2.GetLineSpacing()))
return false; return false;
if ((flags && wxTEXT_ATTR_CHARACTER_STYLE_NAME) && if ((flags & wxTEXT_ATTR_CHARACTER_STYLE_NAME) &&
(attr1.GetCharacterStyleName() != attr2.GetCharacterStyleName())) (attr1.GetCharacterStyleName() != attr2.GetCharacterStyleName()))
return false; return false;
if ((flags && wxTEXT_ATTR_PARAGRAPH_STYLE_NAME) && if ((flags & wxTEXT_ATTR_PARAGRAPH_STYLE_NAME) &&
(attr1.GetParagraphStyleName() != attr2.GetParagraphStyleName())) (attr1.GetParagraphStyleName() != attr2.GetParagraphStyleName()))
return false; return false;

View File

@@ -56,6 +56,7 @@ BEGIN_EVENT_TABLE( wxRichTextCtrl, wxScrolledWindow )
#endif #endif
EVT_PAINT(wxRichTextCtrl::OnPaint) EVT_PAINT(wxRichTextCtrl::OnPaint)
EVT_ERASE_BACKGROUND(wxRichTextCtrl::OnEraseBackground) EVT_ERASE_BACKGROUND(wxRichTextCtrl::OnEraseBackground)
EVT_IDLE(wxRichTextCtrl::OnIdle)
EVT_LEFT_DOWN(wxRichTextCtrl::OnLeftClick) EVT_LEFT_DOWN(wxRichTextCtrl::OnLeftClick)
EVT_MOTION(wxRichTextCtrl::OnMoveMouse) EVT_MOTION(wxRichTextCtrl::OnMoveMouse)
EVT_LEFT_UP(wxRichTextCtrl::OnLeftUp) EVT_LEFT_UP(wxRichTextCtrl::OnLeftUp)
@@ -177,6 +178,10 @@ void wxRichTextCtrl::Init()
m_editable = true; m_editable = true;
m_caretAtLineStart = false; m_caretAtLineStart = false;
m_dragging = 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 /// Call Freeze to prevent refresh
@@ -1323,6 +1328,15 @@ bool wxRichTextCtrl::WordRight(int WXUNUSED(n), int flags)
/// Sizing /// Sizing
void wxRichTextCtrl::OnSize(wxSizeEvent& event) void wxRichTextCtrl::OnSize(wxSizeEvent& event)
{ {
// 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); GetBuffer().Invalidate(wxRICHTEXT_ALL);
RecreateBuffer(); RecreateBuffer();
@@ -1330,6 +1344,23 @@ void wxRichTextCtrl::OnSize(wxSizeEvent& event)
event.Skip(); 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 /// Set up scrollbars, e.g. after a resize
void wxRichTextCtrl::SetupScrollbars(bool atTop) void wxRichTextCtrl::SetupScrollbars(bool atTop)
{ {
@@ -2119,8 +2150,8 @@ bool wxRichTextCtrl::SetFont(const wxFont& font)
return true; return true;
} }
/// Transform logical to physical (unscrolling) /// Transform logical to physical
wxPoint wxRichTextCtrl::GetPhysicalPoint(const wxPoint& ptLogical) wxPoint wxRichTextCtrl::GetPhysicalPoint(const wxPoint& ptLogical) const
{ {
wxPoint pt; wxPoint pt;
CalcScrolledPosition(ptLogical.x, ptLogical.y, & pt.x, & pt.y); CalcScrolledPosition(ptLogical.x, ptLogical.y, & pt.x, & pt.y);
@@ -2129,7 +2160,7 @@ wxPoint wxRichTextCtrl::GetPhysicalPoint(const wxPoint& ptLogical)
} }
/// Transform physical to logical /// Transform physical to logical
wxPoint wxRichTextCtrl::GetLogicalPoint(const wxPoint& ptPhysical) wxPoint wxRichTextCtrl::GetLogicalPoint(const wxPoint& ptPhysical) const
{ {
wxPoint pt; wxPoint pt;
CalcUnscrolledPosition(ptPhysical.x, ptPhysical.y, & pt.x, & pt.y); CalcUnscrolledPosition(ptPhysical.x, ptPhysical.y, & pt.x, & pt.y);
@@ -2213,9 +2244,9 @@ bool wxRichTextCtrl::MoveCaret(long pos, bool showAtLineStart)
/// Layout the buffer: which we must do before certain operations, such as /// Layout the buffer: which we must do before certain operations, such as
/// setting the caret position. /// setting the caret position.
bool wxRichTextCtrl::Layout() bool wxRichTextCtrl::Layout(bool onlyVisibleRect)
{ {
if (GetBuffer().GetDirty()) if (GetBuffer().GetDirty() || onlyVisibleRect)
{ {
wxRect availableSpace(GetClientSize()); wxRect availableSpace(GetClientSize());
if (availableSpace.width == 0) if (availableSpace.width == 0)
@@ -2223,6 +2254,13 @@ bool wxRichTextCtrl::Layout()
if (availableSpace.height == 0) if (availableSpace.height == 0)
availableSpace.height = 10; 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); wxClientDC dc(this);
dc.SetFont(GetFont()); dc.SetFont(GetFont());
@@ -2230,7 +2268,7 @@ bool wxRichTextCtrl::Layout()
GetBuffer().Defragment(); GetBuffer().Defragment();
GetBuffer().UpdateRanges(); // If items were deleted, ranges need recalculation 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); GetBuffer().SetDirty(false);
if (!IsFrozen()) if (!IsFrozen())
@@ -2354,7 +2392,7 @@ bool wxRichTextCtrl::ApplyUnderlineToSelection()
{ {
wxRichTextAttr attr; wxRichTextAttr attr;
attr.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE); attr.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE);
attr.SetFontWeight(!IsSelectionUnderlined()); attr.SetFontUnderlined(!IsSelectionUnderlined());
if (HasSelection()) if (HasSelection())
return SetStyle(GetSelectionRange(), attr); return SetStyle(GetSelectionRange(), attr);
@@ -2415,6 +2453,16 @@ bool wxRichTextCtrl::SetDefaultStyleToCursorStyle()
return false; 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 #endif
// wxUSE_RICHTEXT // wxUSE_RICHTEXT