const wxChar wxRichTextLineBreakChar = (wxChar) 29;
+// Helpers for efficiency
+
+inline void wxCheckSetFont(wxDC& dc, const wxFont& font)
+{
+ const wxFont& font1 = dc.GetFont();
+ if (font1.IsOk() && font.IsOk())
+ {
+ if (font1.GetPointSize() == font.GetPointSize() &&
+ font1.GetFamily() == font.GetFamily() &&
+ font1.GetStyle() == font.GetStyle() &&
+ font1.GetWeight() == font.GetWeight() &&
+ font1.GetFaceName() == font.GetFaceName())
+ return;
+ }
+ dc.SetFont(font);
+}
+
+inline void wxCheckSetPen(wxDC& dc, const wxPen& pen)
+{
+ const wxPen& pen1 = dc.GetPen();
+ if (pen1.IsOk() && pen.IsOk())
+ {
+ if (pen1.GetWidth() == pen.GetWidth() &&
+ pen1.GetStyle() == pen.GetStyle() &&
+ pen1.GetColour() == pen.GetColour())
+ return;
+ }
+ dc.SetPen(pen);
+}
+
+inline void wxCheckSetBrush(wxDC& dc, const wxBrush& brush)
+{
+ const wxBrush& brush1 = dc.GetBrush();
+ if (brush1.IsOk() && brush.IsOk())
+ {
+ if (brush1.GetStyle() == brush.GetStyle() &&
+ brush1.GetColour() == brush.GetColour())
+ return;
+ }
+ dc.SetBrush(brush);
+}
+
/*!
* wxRichTextObject
* This is the base for drawable objects.
else
font = (*wxNORMAL_FONT);
- dc.SetFont(font);
+ wxCheckSetFont(dc, font);
lineHeight = dc.GetCharHeight();
linePos = GetPosition();
if (attr.GetLineSpacing() != 10 && GetBuffer())
{
wxFont font(GetBuffer()->GetFontTable().FindFont(attr));
- dc.SetFont(font);
+ wxCheckSetFont(dc, font);
lineSpacing = (ConvertTenthsMMToPixels(dc, dc.GetCharHeight()) * attr.GetLineSpacing())/10;
}
int lineCount = 0;
+ wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
+ while (node)
+ {
+ wxRichTextObject* child = node->GetData();
+
+ child->SetCachedSize(wxDefaultSize);
+ child->Layout(dc, rect, style);
+
+ node = node->GetNext();
+ }
+
// Split up lines
// We may need to go back to a previous child, in which case create the new line,
// find the child corresponding to the start position of the string, and
// continue.
- wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
+ node = m_children.GetFirst();
while (node)
{
wxRichTextObject* child = node->GetData();
// can't tell the position until the size is determined. So possibly introduce
// another layout phase.
- // TODO: can't this be called only once per child?
- child->Layout(dc, rect, style);
-
// Available width depends on whether we're on the first or subsequent lines
int availableSpaceForText = (lineCount == 0 ? availableTextSpaceFirstLine : availableTextSpaceSubsequentLines);
if (lineHeight == 0 && GetBuffer())
{
wxFont font(GetBuffer()->GetFontTable().FindFont(attr));
- dc.SetFont(font);
+ wxCheckSetFont(dc, font);
lineHeight = dc.GetCharHeight();
}
if (maxDescent == 0)
{
// Find the first position where the line exceeds the available space.
wxSize sz;
- long i;
long breakPosition = range.GetEnd();
- for (i = range.GetStart(); i <= range.GetEnd(); i++)
+
+ // Binary chop for speed
+ long minPos = range.GetStart();
+ long maxPos = range.GetEnd();
+ while (true)
{
- int descent = 0;
- GetRangeSize(wxRichTextRange(range.GetStart(), i), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
+ if (minPos == maxPos)
+ {
+ int descent = 0;
+ GetRangeSize(wxRichTextRange(range.GetStart(), minPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
- if (sz.x > availableSpace)
+ if (sz.x > availableSpace)
+ breakPosition = minPos - 1;
+ break;
+ }
+ else if ((maxPos - minPos) == 1)
{
- breakPosition = i-1;
+ int descent = 0;
+ GetRangeSize(wxRichTextRange(range.GetStart(), minPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
+
+ if (sz.x > availableSpace)
+ breakPosition = minPos - 1;
+ else
+ {
+ GetRangeSize(wxRichTextRange(range.GetStart(), maxPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
+ if (sz.x > availableSpace)
+ breakPosition = maxPos-1;
+ }
break;
}
+ else
+ {
+ long nextPos = minPos + ((maxPos - minPos) / 2);
+
+ int descent = 0;
+ GetRangeSize(wxRichTextRange(range.GetStart(), nextPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
+
+ if (sz.x > availableSpace)
+ {
+ maxPos = nextPos;
+ }
+ else
+ {
+ minPos = nextPos;
+ }
+ }
}
// Now we know the last position on the line.
// is selected.
wxFont font(GetBuffer()->GetFontTable().FindFont(textAttr));
- dc.SetFont(font);
+ wxCheckSetFont(dc, font);
// (a) All selected.
if (selectionRange.GetStart() <= range.GetStart() && selectionRange.GetEnd() >= range.GetEnd())
wxColour highlightColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT));
wxColour highlightTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
- dc.SetBrush(wxBrush(highlightColour));
- dc.SetPen(wxPen(highlightColour));
+ wxCheckSetBrush(dc, wxBrush(highlightColour));
+ wxCheckSetPen(dc, wxPen(highlightColour));
dc.SetTextForeground(highlightTextColour);
dc.SetBackgroundMode(wxTRANSPARENT);
}
if (attr.HasTextEffects() && (attr.GetTextEffects() & wxTEXT_ATTR_EFFECT_STRIKETHROUGH))
{
wxPen oldPen = dc.GetPen();
- dc.SetPen(wxPen(attr.GetTextColour(), 1));
+ wxCheckSetPen(dc, wxPen(attr.GetTextColour(), 1));
dc.DrawLine(x, (int) (y+(h/2)+0.5), x+w, (int) (y+(h/2)+0.5));
- dc.SetPen(oldPen);
+ wxCheckSetPen(dc, oldPen);
}
x = nextTabPos;
if (attr.HasTextEffects() && (attr.GetTextEffects() & wxTEXT_ATTR_EFFECT_STRIKETHROUGH))
{
wxPen oldPen = dc.GetPen();
- dc.SetPen(wxPen(attr.GetTextColour(), 1));
+ wxCheckSetPen(dc, wxPen(attr.GetTextColour(), 1));
dc.DrawLine(x, (int) (y+(h/2)+0.5), x+w, (int) (y+(h/2)+0.5));
- dc.SetPen(oldPen);
+ wxCheckSetPen(dc, oldPen);
}
x += w;
/// Lay the item out
bool wxRichTextPlainText::Layout(wxDC& dc, const wxRect& WXUNUSED(rect), int WXUNUSED(style))
{
- GetRangeSize(GetRange(), m_size, m_descent, dc, 0, wxPoint(0, 0));
+ // Only lay out if we haven't already cached the size
+ if (m_size.x == -1)
+ GetRangeSize(GetRange(), m_size, m_descent, dc, 0, wxPoint(0, 0));
return true;
}
// formatted text by doing it in chunks according to the line ranges
wxFont font(GetBuffer()->GetFontTable().FindFont(textAttr));
- dc.SetFont(font);
+ wxCheckSetFont(dc, font);
int startPos = range.GetStart() - GetRange().GetStart();
long len = range.GetLength();
{
if (bulletAttr.GetTextColour().Ok())
{
- dc.SetPen(wxPen(bulletAttr.GetTextColour()));
- dc.SetBrush(wxBrush(bulletAttr.GetTextColour()));
+ wxCheckSetPen(dc, wxPen(bulletAttr.GetTextColour()));
+ wxCheckSetBrush(dc, wxBrush(bulletAttr.GetTextColour()));
}
else
{
- dc.SetPen(*wxBLACK_PEN);
- dc.SetBrush(*wxBLACK_BRUSH);
+ wxCheckSetPen(dc, *wxBLACK_PEN);
+ wxCheckSetBrush(dc, *wxBLACK_BRUSH);
}
wxFont font;
else
font = (*wxNORMAL_FONT);
- dc.SetFont(font);
+ wxCheckSetFont(dc, font);
int charHeight = dc.GetCharHeight();
else
font = (*wxNORMAL_FONT);
- dc.SetFont(font);
+ wxCheckSetFont(dc, font);
if (attr.GetTextColour().Ok())
dc.SetTextForeground(attr.GetTextColour());
if (selectionRange.Contains(range.GetStart()))
{
- dc.SetBrush(*wxBLACK_BRUSH);
- dc.SetPen(*wxBLACK_PEN);
+ wxCheckSetBrush(dc, *wxBLACK_BRUSH);
+ wxCheckSetPen(dc, *wxBLACK_PEN);
dc.SetLogicalFunction(wxINVERT);
dc.DrawRectangle(rect);
dc.SetLogicalFunction(wxCOPY);
* Manages quick access to a pool of fonts for rendering rich text
*/
-WX_DECLARE_EXPORTED_STRING_HASH_MAP(wxFont, wxRichTextFontTableHashMap);
+WX_DECLARE_STRING_HASH_MAP_WITH_DECL(wxFont, wxRichTextFontTableHashMap, class WXDLLIMPEXP_RICHTEXT);
class wxRichTextFontTableData: public wxObjectRefData
{