Further wxRichTextCtrl performance improvements
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@53382 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -589,7 +589,7 @@ bool wxRichTextParagraphLayoutBox::Draw(wxDC& dc, const wxRichTextRange& range,
|
||||
// Skip
|
||||
}
|
||||
else
|
||||
child->Draw(dc, range, selectionRange, childRect, descent, style);
|
||||
child->Draw(dc, range, selectionRange, rect, descent, style);
|
||||
}
|
||||
|
||||
node = node->GetNext();
|
||||
@@ -857,25 +857,29 @@ wxRichTextLine* wxRichTextParagraphLayoutBox::GetLineAtPosition(long pos, bool c
|
||||
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);
|
||||
|
||||
wxRichTextRange range = line->GetAbsoluteRange();
|
||||
wxRichTextLineList::compatibility_iterator node2 = child->GetLines().GetFirst();
|
||||
while (node2)
|
||||
{
|
||||
wxRichTextLine* line = node2->GetData();
|
||||
|
||||
if (range.Contains(pos) ||
|
||||
wxRichTextRange range = line->GetAbsoluteRange();
|
||||
|
||||
// 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 (range.Contains(pos) ||
|
||||
|
||||
node2 = node2->GetNext();
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
||||
node = node->GetNext();
|
||||
@@ -3105,7 +3109,7 @@ wxRichTextParagraph::~wxRichTextParagraph()
|
||||
}
|
||||
|
||||
/// 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();
|
||||
|
||||
@@ -3184,52 +3188,56 @@ bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
|
||||
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();
|
||||
|
||||
if (!child->GetRange().IsOutside(lineRange) && !lineRange.IsOutside(range))
|
||||
// Loop through objects until we get to the one within range
|
||||
wxRichTextObjectList::compatibility_iterator node2 = m_children.GetFirst();
|
||||
|
||||
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 (!child->GetRange().IsOutside(lineRange) && !lineRange.IsOutside(range))
|
||||
{
|
||||
// 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
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
// 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 ++;
|
||||
node2 = node2->GetNext();
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
node = node->GetNext();
|
||||
@@ -5548,8 +5556,6 @@ bool wxRichTextBuffer::BeginStyle(const wxTextAttr& style)
|
||||
|
||||
SetDefaultStyle(newStyle);
|
||||
|
||||
// wxLogDebug("Default style size = %d", GetDefaultStyle().GetFont().GetPointSize());
|
||||
|
||||
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);
|
||||
@@ -6532,49 +6590,7 @@ bool wxRichTextAction::Do()
|
||||
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);
|
||||
@@ -6599,10 +6615,7 @@ bool wxRichTextAction::Do()
|
||||
|
||||
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,
|
||||
@@ -6617,6 +6630,13 @@ bool wxRichTextAction::Do()
|
||||
}
|
||||
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()));
|
||||
@@ -6625,7 +6645,7 @@ bool wxRichTextAction::Do()
|
||||
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,
|
||||
@@ -6671,13 +6691,20 @@ bool wxRichTextAction::Undo()
|
||||
{
|
||||
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,
|
||||
@@ -6692,11 +6719,18 @@ bool wxRichTextAction::Undo()
|
||||
}
|
||||
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,
|
||||
@@ -6735,7 +6769,7 @@ bool wxRichTextAction::Undo()
|
||||
}
|
||||
|
||||
/// 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)
|
||||
{
|
||||
@@ -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 (m_cmdId == wxRICHTEXT_INSERT && optimizationLineCharPositions && optimizationLineCharPositions->GetCount() > 0)
|
||||
if ((m_cmdId == wxRICHTEXT_INSERT || m_cmdId == wxRICHTEXT_DELETE) && optimizationLineCharPositions)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
@@ -6757,17 +6791,57 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent
|
||||
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)
|
||||
{
|
||||
@@ -6787,14 +6861,19 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent
|
||||
node2 = wxRichTextLineList::compatibility_iterator();
|
||||
node = wxRichTextObjectList::compatibility_iterator();
|
||||
}
|
||||
// Detect last line in the buffer
|
||||
else if (!node2->GetNext() && para->GetRange().Contains(m_buffer->GetRange().GetEnd()))
|
||||
{
|
||||
foundEnd = true;
|
||||
lastY = pt.y + line->GetSize().y;
|
||||
|
||||
node2 = wxRichTextLineList::compatibility_iterator();
|
||||
node = wxRichTextObjectList::compatibility_iterator();
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!foundStart)
|
||||
{
|
||||
firstY = pt.y - firstVisiblePt.y;
|
||||
foundStart = true;
|
||||
}
|
||||
|
||||
// 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;
|
||||
lastY = pt.y - firstVisiblePt.y;
|
||||
|
||||
lastY = pt.y;
|
||||
|
||||
node2 = wxRichTextLineList::compatibility_iterator();
|
||||
node = wxRichTextObjectList::compatibility_iterator();
|
||||
@@ -6821,17 +6901,13 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent
|
||||
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
|
||||
|
Reference in New Issue
Block a user