#include "wx/module.h"
#endif
+#include "wx/settings.h"
#include "wx/filename.h"
#include "wx/clipbrd.h"
#include "wx/wfstream.h"
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.
if (invalidRange == wxRICHTEXT_ALL)
layoutAll = true;
else // If we know what range is affected, start laying out from that point on.
- if (invalidRange.GetStart() > GetRange().GetStart())
+ if (invalidRange.GetStart() >= GetRange().GetStart())
{
wxRichTextParagraph* firstParagraph = GetParagraphAtPosition(invalidRange.GetStart());
if (firstParagraph)
wxRichTextObjectList::compatibility_iterator previousNode;
if ( firstNode )
previousNode = firstNode->GetPrevious();
- if (firstNode && previousNode)
+ if (firstNode)
{
- wxRichTextParagraph* previousParagraph = wxDynamicCast(previousNode->GetData(), wxRichTextParagraph);
- availableSpace.y = previousParagraph->GetPosition().y + previousParagraph->GetCachedSize().y;
+ if (previousNode)
+ {
+ wxRichTextParagraph* previousParagraph = wxDynamicCast(previousNode->GetData(), wxRichTextParagraph);
+ availableSpace.y = previousParagraph->GetPosition().y + previousParagraph->GetCachedSize().y;
+ }
// Now we're going to start iterating from the first affected paragraph.
node = firstNode;
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())
if (selected)
{
- dc.SetBrush(*wxBLACK_BRUSH);
- dc.SetPen(*wxBLACK_PEN);
- dc.SetTextForeground(*wxWHITE);
+ wxColour highlightColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT));
+ wxColour highlightTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
+
+ wxCheckSetBrush(dc, wxBrush(highlightColour));
+ wxCheckSetPen(dc, wxPen(highlightColour));
+ dc.SetTextForeground(highlightTextColour);
dc.SetBackgroundMode(wxTRANSPARENT);
}
else
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();
wxRichTextParagraphStyleDefinition* paraDef = GetStyleSheet()->FindParagraphStyle(para->GetAttributes().GetParagraphStyleName());
if (paraDef)
{
- if (!paraDef->GetNextStyle().IsEmpty())
+ // If we're not at the end of the paragraph, then we apply THIS style, and not the designated next style.
+ if (para->GetRange().GetEnd() == pos && !paraDef->GetNextStyle().IsEmpty())
{
wxRichTextParagraphStyleDefinition* nextParaDef = GetStyleSheet()->FindParagraphStyle(paraDef->GetNextStyle());
if (nextParaDef)
{
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
{