// Switch off if the platform doesn't like it for some reason
#define wxRICHTEXT_USE_OPTIMIZED_DRAWING 1
+const wxChar wxRichTextLineBreakChar = (wxChar) 29;
+
/*!
* wxRichTextObject
* This is the base for drawable objects.
// 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
// We may only be looking at part of a child, if we searched back for wrapping
// and found a suitable point some way into the child. So get the size for the fragment
// if necessary.
+
+ long nextBreakPos = GetFirstLineBreakPosition(lastEndPos+1);
+ long lastPosToUse = child->GetRange().GetEnd();
+ bool lineBreakInThisObject = (nextBreakPos > -1 && nextBreakPos <= child->GetRange().GetEnd());
+
+ if (lineBreakInThisObject)
+ lastPosToUse = nextBreakPos;
wxSize childSize;
int childDescent = 0;
- if (lastEndPos == child->GetRange().GetStart() - 1)
+
+ if ((nextBreakPos == -1) && (lastEndPos == child->GetRange().GetStart() - 1)) // i.e. we want to get the whole thing
{
childSize = child->GetCachedSize();
childDescent = child->GetDescent();
}
else
- GetRangeSize(wxRichTextRange(lastEndPos+1, child->GetRange().GetEnd()), childSize, childDescent, dc, wxRICHTEXT_UNFORMATTED,rect.GetPosition());
+ GetRangeSize(wxRichTextRange(lastEndPos+1, lastPosToUse), childSize, childDescent, dc, wxRICHTEXT_UNFORMATTED, rect.GetPosition());
+
+ // Cases:
+ // 1) There was a line break BEFORE the natural break
+ // 2) There was a line break AFTER the natural break
+ // 3) The child still fits (carry on)
- if (childSize.x + currentWidth > availableSpaceForText)
+ if ((lineBreakInThisObject && (childSize.x + currentWidth <= availableSpaceForText)) ||
+ (childSize.x + currentWidth > availableSpaceForText))
{
long wrapPosition = 0;
wxString plainText;
if (GetContiguousPlainText(plainText, wxRichTextRange(range.GetStart(), breakPosition), false))
{
- int spacePos = plainText.Find(wxT(' '), true);
- if (spacePos != wxNOT_FOUND)
+ int newLinePos = plainText.Find(wxRichTextLineBreakChar);
+ if (newLinePos != wxNOT_FOUND)
{
- int positionsFromEndOfString = plainText.length() - spacePos - 1;
- breakPosition = breakPosition - positionsFromEndOfString;
+ breakPosition = wxMax(0, range.GetStart() + newLinePos);
+ }
+ else
+ {
+ int spacePos = plainText.Find(wxT(' '), true);
+ if (spacePos != wxNOT_FOUND)
+ {
+ int positionsFromEndOfString = plainText.length() - spacePos - 1;
+ breakPosition = breakPosition - positionsFromEndOfString;
+ }
}
}
sm_defaultTabs.Clear();
}
+/// Get the first position from pos that has a line break character.
+long wxRichTextParagraph::GetFirstLineBreakPosition(long pos)
+{
+ wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
+ while (node)
+ {
+ wxRichTextObject* obj = node->GetData();
+ if (pos >= obj->GetRange().GetStart() && pos <= obj->GetRange().GetEnd())
+ {
+ wxRichTextPlainText* textObj = wxDynamicCast(obj, wxRichTextPlainText);
+ if (textObj)
+ {
+ long breakPos = textObj->GetFirstLineBreakPosition(pos);
+ if (breakPos > -1)
+ return breakPos;
+ }
+ }
+ node = node->GetNext();
+ }
+ return -1;
+}
/*!
* wxRichTextLine
int offset = GetRange().GetStart();
+ // Replace line break characters with spaces
+ wxString str = m_text;
+ wxString toRemove = wxRichTextLineBreakChar;
+ str.Replace(toRemove, wxT(" "));
+
long len = range.GetLength();
- wxString stringChunk = m_text.Mid(range.GetStart() - offset, (size_t) len);
+ wxString stringChunk = str.Mid(range.GetStart() - offset, (size_t) len);
if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS))
stringChunk.MakeUpper();
int fragmentLen = s1 - r1 + 1;
if (fragmentLen < 0)
wxLogDebug(wxT("Mid(%d, %d"), (int)(r1 - offset), (int)fragmentLen);
- wxString stringFragment = m_text.Mid(r1 - offset, fragmentLen);
+ wxString stringFragment = str.Mid(r1 - offset, fragmentLen);
DrawTabbedString(dc, textAttr, rect, stringFragment, x, y, false);
if (stringChunk.Find(wxT("\t")) == wxNOT_FOUND)
{
// Compensate for kerning difference
- wxString stringFragment2(m_text.Mid(r1 - offset, fragmentLen+1));
- wxString stringFragment3(m_text.Mid(r1 - offset + fragmentLen, 1));
+ wxString stringFragment2(str.Mid(r1 - offset, fragmentLen+1));
+ wxString stringFragment3(str.Mid(r1 - offset + fragmentLen, 1));
wxCoord w1, h1, w2, h2, w3, h3;
dc.GetTextExtent(stringFragment, & w1, & h1);
int fragmentLen = s2 - s1 + 1;
if (fragmentLen < 0)
wxLogDebug(wxT("Mid(%d, %d"), (int)(s1 - offset), (int)fragmentLen);
- wxString stringFragment = m_text.Mid(s1 - offset, fragmentLen);
+ wxString stringFragment = str.Mid(s1 - offset, fragmentLen);
DrawTabbedString(dc, textAttr, rect, stringFragment, x, y, true);
if (stringChunk.Find(wxT("\t")) == wxNOT_FOUND)
{
// Compensate for kerning difference
- wxString stringFragment2(m_text.Mid(s1 - offset, fragmentLen+1));
- wxString stringFragment3(m_text.Mid(s1 - offset + fragmentLen, 1));
+ wxString stringFragment2(str.Mid(s1 - offset, fragmentLen+1));
+ wxString stringFragment3(str.Mid(s1 - offset + fragmentLen, 1));
wxCoord w1, h1, w2, h2, w3, h3;
dc.GetTextExtent(stringFragment, & w1, & h1);
int fragmentLen = r2 - s2 + 1;
if (fragmentLen < 0)
wxLogDebug(wxT("Mid(%d, %d"), (int)(s2 - offset), (int)fragmentLen);
- wxString stringFragment = m_text.Mid(s2 - offset, fragmentLen);
+ wxString stringFragment = str.Mid(s2 - offset, fragmentLen);
DrawTabbedString(dc, textAttr, rect, stringFragment, x, y, false);
}
if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS))
str.MakeUpper();
+ wxString toReplace = wxRichTextLineBreakChar;
+ str.Replace(toReplace, wxT(" "));
+
wxCoord w, h;
dc.GetTextExtent(str, & w, & h, & m_descent);
m_size = wxSize(w, dc.GetCharHeight());
int startPos = range.GetStart() - GetRange().GetStart();
long len = range.GetLength();
- wxString stringChunk = m_text.Mid(startPos, (size_t) len);
+
+ wxString str(m_text);
+ wxString toReplace = wxRichTextLineBreakChar;
+ str.Replace(toReplace, wxT(" "));
+
+ wxString stringChunk = str.Mid(startPos, (size_t) len);
if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS))
stringChunk.MakeUpper();
/// the first part in 'this'.
wxRichTextObject* wxRichTextPlainText::DoSplit(long pos)
{
- int index = pos - GetRange().GetStart();
+ long index = pos - GetRange().GetStart();
+
if (index < 0 || index >= (int) m_text.length())
return NULL;
newObject->SetRange(wxRichTextRange(pos, GetRange().GetEnd()));
GetRange().SetEnd(pos-1);
-
+
return newObject;
}
stream << m_text << wxT("\n");
}
+/// Get the first position from pos that has a line break character.
+long wxRichTextPlainText::GetFirstLineBreakPosition(long pos)
+{
+ int i;
+ int len = m_text.length();
+ int startPos = pos - m_range.GetStart();
+ for (i = startPos; i < len; i++)
+ {
+ wxChar ch = m_text[i];
+ if (ch == wxRichTextLineBreakChar)
+ {
+ return i + m_range.GetStart();
+ }
+ }
+ return -1;
+}
+
/*!
* wxRichTextBuffer
* This is a kind of box, used to represent the whole buffer
return false;
wxString text = buffer->GetText();
+
+ wxString newLine = wxRichTextLineBreakChar;
+ text.Replace(newLine, wxT("\n"));
+
wxCharBuffer buf = text.ToAscii();
stream.Write((const char*) buf, text.length());