// Switch off if the platform doesn't like it for some reason
#define wxRICHTEXT_USE_OPTIMIZED_DRAWING 1
+// Use GetPartialTextExtents for platforms that support it natively
+#define wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS 1
+
const wxChar wxRichTextLineBreakChar = (wxChar) 29;
// Helpers for efficiency
node = node->GetNext();
}
- return wxRICHTEXT_HITTEST_NONE;
+ textPosition = GetRange().GetEnd()-1;
+ return wxRICHTEXT_HITTEST_AFTER|wxRICHTEXT_HITTEST_OUTSIDE;
}
/// Finds the absolute position and row height for the given character position
}
/// Recursively merge all pieces that can be merged.
-bool wxRichTextCompositeObject::Defragment()
+bool wxRichTextCompositeObject::Defragment(const wxRichTextRange& range)
{
wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
while (node)
{
wxRichTextObject* child = node->GetData();
- wxRichTextCompositeObject* composite = wxDynamicCast(child, wxRichTextCompositeObject);
- if (composite)
- composite->Defragment();
-
- if (node->GetNext())
+ if (!child->GetRange().IsOutside(range))
{
- wxRichTextObject* nextChild = node->GetNext()->GetData();
- if (child->CanMerge(nextChild) && child->Merge(nextChild))
+ wxRichTextCompositeObject* composite = wxDynamicCast(child, wxRichTextCompositeObject);
+ if (composite)
+ composite->Defragment();
+
+ if (node->GetNext())
{
- nextChild->Dereference();
- m_children.Erase(node->GetNext());
+ wxRichTextObject* nextChild = node->GetNext()->GetData();
+ if (child->CanMerge(nextChild) && child->Merge(nextChild))
+ {
+ nextChild->Dereference();
+ m_children.Erase(node->GetNext());
- // Don't set node -- we'll see if we can merge again with the next
- // child.
+ // Don't set node -- we'll see if we can merge again with the next
+ // child.
+ }
+ else
+ node = node->GetNext();
}
else
node = node->GetNext();
}
/// Get/set the size for the given range. Assume only has one child.
-bool wxRichTextBox::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position) const
+bool wxRichTextBox::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position, wxArrayInt* partialExtents) const
{
wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
if (node)
{
wxRichTextObject* child = node->GetData();
- return child->GetRangeSize(range, size, descent, dc, flags, position);
+ return child->GetRangeSize(range, size, descent, dc, flags, position, partialExtents);
}
else
return false;
}
/// Get/set the size for the given range.
-bool wxRichTextParagraphLayoutBox::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position) const
+bool wxRichTextParagraphLayoutBox::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position, wxArrayInt* WXUNUSED(partialExtents)) const
{
wxSize sz;
wxTextAttr defaultCharStyle;
wxTextAttr defaultParaStyle;
- wxRichTextSplitParaCharStyles(GetDefaultStyle(), defaultParaStyle, defaultCharStyle);
+ // If the default style is a named paragraph style, don't apply any character formatting
+ // to the initial text string.
+ if (GetDefaultStyle().HasParagraphStyleName() && GetStyleSheet())
+ {
+ wxRichTextParagraphStyleDefinition* def = GetStyleSheet()->FindParagraphStyle(GetDefaultStyle().GetParagraphStyleName());
+ if (def)
+ defaultParaStyle = def->GetStyleMergedWithBase(GetStyleSheet());
+ }
+ else
+ wxRichTextSplitParaCharStyles(GetDefaultStyle(), defaultParaStyle, defaultCharStyle);
+
wxTextAttr* pStyle = paraStyle ? paraStyle : (wxTextAttr*) & defaultParaStyle;
wxTextAttr* cStyle = & defaultCharStyle;
wxTextAttr defaultCharStyle;
wxTextAttr defaultParaStyle;
- wxRichTextSplitParaCharStyles(GetDefaultStyle(), defaultParaStyle, defaultCharStyle);
+
+ // If the default style is a named paragraph style, don't apply any character formatting
+ // to the initial text string.
+ if (GetDefaultStyle().HasParagraphStyleName() && GetStyleSheet())
+ {
+ wxRichTextParagraphStyleDefinition* def = GetStyleSheet()->FindParagraphStyle(GetDefaultStyle().GetParagraphStyleName());
+ if (def)
+ defaultParaStyle = def->GetStyleMergedWithBase(GetStyleSheet());
+ }
+ else
+ wxRichTextSplitParaCharStyles(GetDefaultStyle(), defaultParaStyle, defaultCharStyle);
wxTextAttr* pStyle = paraStyle ? paraStyle : (wxTextAttr*) & defaultParaStyle;
wxTextAttr* cStyle = & defaultCharStyle;
wxTextAttr defaultCharStyle;
wxTextAttr defaultParaStyle;
- wxRichTextSplitParaCharStyles(GetDefaultStyle(), defaultParaStyle, defaultCharStyle);
+
+ // If the default style is a named paragraph style, don't apply any character formatting
+ // to the initial text string.
+ if (GetDefaultStyle().HasParagraphStyleName() && GetStyleSheet())
+ {
+ wxRichTextParagraphStyleDefinition* def = GetStyleSheet()->FindParagraphStyle(GetDefaultStyle().GetParagraphStyleName());
+ if (def)
+ defaultParaStyle = def->GetStyleMergedWithBase(GetStyleSheet());
+ }
+ else
+ wxRichTextSplitParaCharStyles(GetDefaultStyle(), defaultParaStyle, defaultCharStyle);
wxTextAttr* pStyle = paraStyle ? paraStyle : (wxTextAttr*) & defaultParaStyle;
wxTextAttr* cStyle = & defaultCharStyle;
wxRichTextParagraph* firstPara = wxDynamicCast(firstParaNode->GetData(), wxRichTextParagraph);
wxASSERT(firstPara != NULL);
- para->SetAttributes(firstPara->GetAttributes());
+ if (!(fragment.GetAttributes().GetFlags() & wxTEXT_ATTR_KEEP_FIRST_PARA_STYLE))
+ para->SetAttributes(firstPara->GetAttributes());
// Save empty paragraph attributes for appending later
// These are character attributes deliberately set for a new paragraph. Without this,
}
}
- if (finalPara && finalPara != para)
+ if ((fragment.GetAttributes().GetFlags() & wxTEXT_ATTR_KEEP_FIRST_PARA_STYLE) && firstPara)
+ finalPara->SetAttributes(firstPara->GetAttributes());
+ else if (finalPara && finalPara != para)
finalPara->SetAttributes(originalAttr);
return true;
obj->DeleteRange(range);
wxRichTextRange thisRange = obj->GetRange();
+ wxTextAttrEx thisAttr = obj->GetAttributes();
// If the whole paragraph is within the range to delete,
// delete the whole thing.
wxTextAttrEx nextParaAttr;
if (applyFinalParagraphStyle)
- nextParaAttr = nextParagraph->GetAttributes();
+ {
+ // Special case when deleting the end of a paragraph - use _this_ paragraph's style,
+ // not the next one.
+ if (range.GetStart() == range.GetEnd() && range.GetStart() == thisRange.GetEnd())
+ nextParaAttr = thisAttr;
+ else
+ nextParaAttr = nextParagraph->GetAttributes();
+ }
if (firstPara && nextParagraph && firstPara != nextParagraph)
{
{
wxRichTextObject* obj1 = node1->GetData();
- // If the object is empty, optimise it out
- if (obj1->IsEmpty())
- {
- delete obj1;
- }
- else
- {
- firstPara->AppendChild(obj1);
- }
+ firstPara->AppendChild(obj1);
wxRichTextObjectList::compatibility_iterator next1 = node1->GetNext();
nextParagraph->GetChildren().Erase(node1);
RemoveChild(nextParagraph, true);
}
+ // Avoid empty paragraphs
+ if (firstPara && firstPara->GetChildren().GetCount() == 0)
+ {
+ wxRichTextPlainText* text = new wxRichTextPlainText(wxEmptyString);
+ firstPara->AppendChild(text);
+ }
+
if (applyFinalParagraphStyle)
firstPara->SetAttributes(nextParaAttr);
splitPoint ++;
// Find last object
- if (splitPoint == newPara->GetRange().GetEnd() || splitPoint == (newPara->GetRange().GetEnd() - 1))
+ if (splitPoint == newPara->GetRange().GetEnd())
lastObject = newPara->GetChildren().GetLast()->GetData();
else
// lastObject is set as a side-effect of splitting. It's
// Loop through objects until we get to the one within range
wxRichTextObjectList::compatibility_iterator node2 = m_children.GetFirst();
+
+ int i = 0;
while (node2)
{
wxRichTextObject* child = node2->GetData();
objectRange.LimitTo(lineRange);
wxSize objectSize;
- int descent = 0;
- child->GetRangeSize(objectRange, objectSize, descent, dc, wxRICHTEXT_UNFORMATTED, objectPosition);
+#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
+#endif
+ {
+ 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
int lineCount = 0;
- wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
+ wxRichTextObjectList::compatibility_iterator node;
+
+#if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS
+ wxUnusedVar(style);
+ wxArrayInt partialExtents;
+
+ wxSize paraSize;
+ int paraDescent;
+
+ // This calculates the partial text extents
+ GetRangeSize(GetRange(), paraSize, paraDescent, dc, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_CACHE_SIZE, wxPoint(0,0), & partialExtents);
+#else
+ node = m_children.GetFirst();
while (node)
{
wxRichTextObject* child = node->GetData();
node = node->GetNext();
}
+#endif
+
// Split up lines
// We may need to go back to a previous child, in which case create the new line,
// Find a place to wrap. This may walk back to previous children,
// for example if a word spans several objects.
- if (!FindWrapPosition(wxRichTextRange(lastCompletedEndPos+1, child->GetRange().GetEnd()), dc, availableSpaceForText, wrapPosition))
+ if (!FindWrapPosition(wxRichTextRange(lastCompletedEndPos+1, child->GetRange().GetEnd()), dc, availableSpaceForText, wrapPosition, & partialExtents))
{
// If the function failed, just cut it off at the end of this child.
wrapPosition = child->GetRange().GetEnd();
m_dirty = false;
+#if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS
+#if wxRICHTEXT_USE_OPTIMIZED_LINE_DRAWING
+ // Use the text extents to calculate the size of each fragment in each line
+ wxRichTextLineList::compatibility_iterator lineNode = m_cachedLines.GetFirst();
+ while (lineNode)
+ {
+ wxRichTextLine* line = lineNode->GetData();
+ wxRichTextRange lineRange = line->GetAbsoluteRange();
+
+ // Loop through objects until we get to the one within range
+ wxRichTextObjectList::compatibility_iterator node2 = m_children.GetFirst();
+
+ while (node2)
+ {
+ wxRichTextObject* child = node2->GetData();
+
+ if (!child->GetRange().IsOutside(lineRange))
+ {
+ wxRichTextRange rangeToUse = lineRange;
+ rangeToUse.LimitTo(child->GetRange());
+
+ // Find the size of the child from the text extents, and store in an array
+ // for drawing later
+ int left = 0;
+ if (rangeToUse.GetStart() > GetRange().GetStart())
+ left = partialExtents[(rangeToUse.GetStart()-1) - GetRange().GetStart()];
+ int right = partialExtents[rangeToUse.GetEnd() - GetRange().GetStart()];
+ int sz = right - left;
+ line->GetObjectSizes().Add(sz);
+ }
+ 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();
+ }
+
+ lineNode = lineNode->GetNext();
+ }
+#endif
+#endif
+
return true;
}
/// Get/set the object size for the given range. Returns false if the range
/// is invalid for this object.
-bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position) const
+bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position, wxArrayInt* partialExtents) const
{
if (!range.IsWithin(GetRange()))
return false;
wxSize sz;
+ wxArrayInt childExtents;
+ wxArrayInt* p;
+ if (partialExtents)
+ p = & childExtents;
+ else
+ p = NULL;
+
wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
while (node)
{
+
wxRichTextObject* child = node->GetData();
if (!child->GetRange().IsOutside(range))
{
rangeToUse.LimitTo(child->GetRange());
int childDescent = 0;
- if (child->GetRangeSize(rangeToUse, childSize, childDescent, dc, flags, wxPoint(position.x + sz.x, position.y)))
+ if (child->GetRangeSize(rangeToUse, childSize, childDescent, dc, flags, wxPoint(position.x + sz.x, position.y), p))
{
sz.y = wxMax(sz.y, childSize.y);
sz.x += childSize.x;
descent = wxMax(descent, childDescent);
+
+ if ((flags & wxRICHTEXT_CACHE_SIZE) && (rangeToUse == child->GetRange()))
+ {
+ child->SetCachedSize(childSize);
+ child->SetDescent(childDescent);
+ }
+
+ if (partialExtents)
+ {
+ int lastSize;
+ if (partialExtents->GetCount() > 0)
+ lastSize = (*partialExtents)[partialExtents->GetCount()-1];
+ else
+ lastSize = 0;
+
+ size_t i;
+ for (i = 0; i < childExtents.GetCount(); i++)
+ {
+ partialExtents->Add(childExtents[i] + lastSize);
+ }
+ }
}
+
+ if (p)
+ p->Clear();
}
node = node->GetNext();
wxSize lineSize = line->GetSize();
wxRichTextRange lineRange = line->GetAbsoluteRange();
- if (pt.y >= linePos.y && pt.y <= linePos.y + lineSize.y)
+ if (pt.y <= linePos.y + lineSize.y)
{
if (pt.x < linePos.x)
{
}
else
{
+#if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS
+ wxArrayInt partialExtents;
+
+ wxSize paraSize;
+ int paraDescent;
+
+ // This calculates the partial text extents
+ GetRangeSize(lineRange, paraSize, paraDescent, dc, wxRICHTEXT_UNFORMATTED, wxPoint(0,0), & partialExtents);
+
+ int lastX = linePos.x;
+ size_t i;
+ for (i = 0; i < partialExtents.GetCount(); i++)
+ {
+ int nextX = partialExtents[i] + linePos.x;
+
+ if (pt.x >= lastX && pt.x <= nextX)
+ {
+ textPosition = i + lineRange.GetStart(); // minus 1?
+
+ // So now we know it's between i-1 and i.
+ // Let's see if we can be more precise about
+ // which side of the position it's on.
+
+ int midPoint = (nextX - lastX)/2 + lastX;
+ if (pt.x >= midPoint)
+ return wxRICHTEXT_HITTEST_AFTER;
+ else
+ return wxRICHTEXT_HITTEST_BEFORE;
+ }
+
+ lastX = nextX;
+ }
+#else
long i;
int lastX = linePos.x;
for (i = lineRange.GetStart(); i <= lineRange.GetEnd(); i++)
lastX = nextX;
}
}
+#endif
}
}
}
/// Find a suitable wrap position.
-bool wxRichTextParagraph::FindWrapPosition(const wxRichTextRange& range, wxDC& dc, int availableSpace, long& wrapPosition)
+bool wxRichTextParagraph::FindWrapPosition(const wxRichTextRange& range, wxDC& dc, int availableSpace, long& wrapPosition, wxArrayInt* partialExtents)
{
+ if (range.GetLength() <= 0)
+ return false;
+
// Find the first position where the line exceeds the available space.
wxSize sz;
long breakPosition = range.GetEnd();
- // Binary chop for speed
- long minPos = range.GetStart();
- long maxPos = range.GetEnd();
- while (true)
+#if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS
+ if (partialExtents && partialExtents->GetCount() >= (size_t) (GetRange().GetLength()-1)) // the final position in a paragraph is the newline
{
- if (minPos == maxPos)
- {
- int descent = 0;
- GetRangeSize(wxRichTextRange(range.GetStart(), minPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
+ int widthBefore;
- if (sz.x > availableSpace)
- breakPosition = minPos - 1;
- break;
- }
- else if ((maxPos - minPos) == 1)
+ if (range.GetStart() > GetRange().GetStart())
+ widthBefore = (*partialExtents)[range.GetStart() - GetRange().GetStart() - 1];
+ else
+ widthBefore = 0;
+
+ size_t i;
+ for (i = (size_t) range.GetStart(); i < (size_t) range.GetEnd(); i++)
{
- int descent = 0;
- GetRangeSize(wxRichTextRange(range.GetStart(), minPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
+ int widthFromStartOfThisRange = (*partialExtents)[i - GetRange().GetStart()] - widthBefore;
- if (sz.x > availableSpace)
- breakPosition = minPos - 1;
- else
+ if (widthFromStartOfThisRange > availableSpace)
{
- GetRangeSize(wxRichTextRange(range.GetStart(), maxPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
- if (sz.x > availableSpace)
- breakPosition = maxPos-1;
+ breakPosition = i-1;
+ break;
}
- break;
}
- else
+ }
+ else
+#endif
+ {
+ // Binary chop for speed
+ long minPos = range.GetStart();
+ long maxPos = range.GetEnd();
+ while (true)
{
- long nextPos = minPos + ((maxPos - minPos) / 2);
-
- int descent = 0;
- GetRangeSize(wxRichTextRange(range.GetStart(), nextPos), 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)
{
- maxPos = nextPos;
+ 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
{
- minPos = nextPos;
+ 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;
+ }
}
}
}
m_pos = wxPoint(0, 0);
m_size = wxSize(0, 0);
m_descent = 0;
+#if wxRICHTEXT_USE_OPTIMIZED_LINE_DRAWING
+ m_objectSizes.Clear();
+#endif
}
/// Copy
void wxRichTextLine::Copy(const wxRichTextLine& obj)
{
m_range = obj.m_range;
+#if wxRICHTEXT_USE_OPTIMIZED_LINE_DRAWING
+ m_objectSizes = obj.m_objectSizes;
+#endif
}
/// Get the absolute object position
long len = range.GetLength();
wxString stringChunk = str.Mid(range.GetStart() - offset, (size_t) len);
- int charHeight = dc.GetCharHeight();
-
- int x = rect.x;
- int y = rect.y + (rect.height - charHeight - (descent - m_descent));
-
// Test for the optimized situations where all is selected, or none
// is selected.
- wxFont font(GetBuffer()->GetFontTable().FindFont(textAttr));
- wxCheckSetFont(dc, font);
+ wxFont textFont(GetBuffer()->GetFontTable().FindFont(textAttr));
+ wxCheckSetFont(dc, textFont);
+ int charHeight = dc.GetCharHeight();
+
+ int x, y;
+ if ( textFont.Ok() )
+ {
+ if ( textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUPERSCRIPT) )
+ {
+ double size = static_cast<double>(textFont.GetPointSize()) / wxSCRIPT_MUL_FACTOR;
+ textFont.SetPointSize( static_cast<int>(size) );
+ x = rect.x;
+ y = rect.y;
+ wxCheckSetFont(dc, textFont);
+ }
+ else if ( textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUBSCRIPT) )
+ {
+ double size = static_cast<double>(textFont.GetPointSize()) / wxSCRIPT_MUL_FACTOR;
+ textFont.SetPointSize( static_cast<int>(size) );
+ x = rect.x;
+ int sub_height = static_cast<int>( static_cast<double>(charHeight) / wxSCRIPT_MUL_FACTOR);
+ y = rect.y + (rect.height - sub_height + (descent - m_descent));
+ wxCheckSetFont(dc, textFont);
+ }
+ else
+ {
+ x = rect.x;
+ y = rect.y + (rect.height - charHeight - (descent - m_descent));
+ }
+ }
+ else
+ {
+ x = rect.x;
+ y = rect.y + (rect.height - charHeight - (descent - m_descent));
+ }
// (a) All selected.
if (selectionRange.GetStart() <= range.GetStart() && selectionRange.GetEnd() >= range.GetEnd())
// (c) Part selected, part not
// Let's draw unselected chunk, selected chunk, then unselected chunk.
- dc.SetBackgroundMode(wxTRANSPARENT);
+ dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
// 1. Initial unselected chunk, if any, up until start of selection.
if (selectionRange.GetStart() > range.GetStart() && selectionRange.GetStart() <= range.GetEnd())
wxCheckSetBrush(dc, wxBrush(highlightColour));
wxCheckSetPen(dc, wxPen(highlightColour));
dc.SetTextForeground(highlightTextColour);
- dc.SetBackgroundMode(wxTRANSPARENT);
+ dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
}
else
{
if (attr.HasFlag(wxTEXT_ATTR_BACKGROUND_COLOUR) && attr.GetBackgroundColour().IsOk())
{
- dc.SetBackgroundMode(wxSOLID);
+ dc.SetBackgroundMode(wxBRUSHSTYLE_SOLID);
dc.SetTextBackground(attr.GetBackgroundColour());
}
else
- dc.SetBackgroundMode(wxTRANSPARENT);
+ dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
}
while (hasTabs)
/// Get/set the object size for the given range. Returns false if the range
/// is invalid for this object.
-bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int WXUNUSED(flags), wxPoint position) const
+bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int WXUNUSED(flags), wxPoint position, wxArrayInt* partialExtents) const
{
if (!range.IsWithin(GetRange()))
return false;
// of line breaks - and we don't need it, since we'll calculate size within
// formatted text by doing it in chunks according to the line ranges
+ bool bScript(false);
wxFont font(GetBuffer()->GetFontTable().FindFont(textAttr));
- wxCheckSetFont(dc, font);
+ if (font.Ok())
+ {
+ if ( textAttr.HasTextEffects() && ( (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUPERSCRIPT)
+ || (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUBSCRIPT) ) )
+ {
+ wxFont textFont = font;
+ double size = static_cast<double>(textFont.GetPointSize()) / wxSCRIPT_MUL_FACTOR;
+ textFont.SetPointSize( static_cast<int>(size) );
+ wxCheckSetFont(dc, textFont);
+ bScript = true;
+ }
+ else
+ {
+ wxCheckSetFont(dc, font);
+ }
+ }
+ bool haveDescent = false;
int startPos = range.GetStart() - GetRange().GetStart();
long len = range.GetLength();
while (stringChunk.Find(wxT('\t')) >= 0)
{
+ int absoluteWidth = 0;
+
// the string has a tab
// break up the string at the Tab
wxString stringFragment = stringChunk.BeforeFirst(wxT('\t'));
stringChunk = stringChunk.AfterFirst(wxT('\t'));
- dc.GetTextExtent(stringFragment, & w, & h);
- width += w;
- int absoluteWidth = width + position.x;
+
+ if (partialExtents)
+ {
+ int oldWidth;
+ if (partialExtents->GetCount() > 0)
+ oldWidth = (*partialExtents)[partialExtents->GetCount()-1];
+ else
+ oldWidth = 0;
+
+ // Add these partial extents
+ wxArrayInt p;
+ dc.GetPartialTextExtents(stringFragment, p);
+ size_t j;
+ for (j = 0; j < p.GetCount(); j++)
+ partialExtents->Add(oldWidth + p[j]);
+
+ if (partialExtents->GetCount() > 0)
+ absoluteWidth = (*partialExtents)[(*partialExtents).GetCount()-1] + position.x;
+ else
+ absoluteWidth = position.x;
+ }
+ else
+ {
+ dc.GetTextExtent(stringFragment, & w, & h);
+ width += w;
+ absoluteWidth = width + position.x;
+ haveDescent = true;
+ }
bool notFound = true;
for (int i = 0; i < tabCount && notFound; ++i)
notFound = false;
width = nextTabPos - position.x;
+
+ if (partialExtents)
+ partialExtents->Add(width);
}
}
}
}
- dc.GetTextExtent(stringChunk, & w, & h, & descent);
- width += w;
- size = wxSize(width, dc.GetCharHeight());
+
+ if (!stringChunk.IsEmpty())
+ {
+ if (partialExtents)
+ {
+ int oldWidth;
+ if (partialExtents->GetCount() > 0)
+ oldWidth = (*partialExtents)[partialExtents->GetCount()-1];
+ else
+ oldWidth = 0;
+
+ // Add these partial extents
+ wxArrayInt p;
+ dc.GetPartialTextExtents(stringChunk, p);
+ size_t j;
+ for (j = 0; j < p.GetCount(); j++)
+ partialExtents->Add(oldWidth + p[j]);
+ }
+ else
+ {
+ dc.GetTextExtent(stringChunk, & w, & h, & descent);
+ width += w;
+ haveDescent = true;
+ }
+ }
+
+ if (partialExtents)
+ {
+ int charHeight = dc.GetCharHeight();
+ if ((*partialExtents).GetCount() > 0)
+ w = (*partialExtents)[partialExtents->GetCount()-1];
+ else
+ w = 0;
+ size = wxSize(w, charHeight);
+ }
+ else
+ {
+ size = wxSize(width, dc.GetCharHeight());
+ }
+
+ if (!haveDescent)
+ dc.GetTextExtent(wxT("X"), & w, & h, & descent);
+
+ if ( bScript )
+ dc.SetFont(font);
return true;
}
wxRichTextParagraph* para = GetParagraphAtPosition(pos, false);
long pos1 = pos;
+ if (p)
+ newPara->SetAttributes(*p);
+
if (flags & wxRICHTEXT_INSERT_INTERACTIVE)
{
if (para && para->GetRange().GetEnd() == pos)
pos1 ++;
+ if (newPara->GetAttributes().HasBulletNumber())
+ newPara->GetAttributes().SetBulletNumber(newPara->GetAttributes().GetBulletNumber()+1);
}
action->SetPosition(pos);
- if (p)
- newPara->SetAttributes(*p);
-
// Use the default character style
// Use the default character style
if (!GetDefaultStyle().IsDefault() && newPara->GetChildren().GetFirst())
// Copy the fragment that we'll need to restore in Undo
CopyFragment(range, action->GetOldParagraphs());
- // Special case: if there is only one (non-partial) paragraph,
- // we must save the *next* paragraph's style, because that
- // is the style we must apply when inserting the content back
- // when undoing the delete. (This is because we're merging the
- // paragraph with the previous paragraph and throwing away
- // the style, and we need to restore it.)
- if (!action->GetOldParagraphs().GetPartialParagraph() && action->GetOldParagraphs().GetChildCount() == 1)
+ // See if we're deleting a paragraph marker, in which case we need to
+ // make a note not to copy the attributes from the 2nd paragraph to the 1st.
+ if (range.GetStart() == range.GetEnd())
{
- wxRichTextParagraph* lastPara = GetParagraphAtPosition(range.GetStart());
- if (lastPara)
+ wxRichTextParagraph* para = GetParagraphAtPosition(range.GetStart());
+ if (para && para->GetRange().GetEnd() == range.GetEnd())
{
- wxRichTextParagraph* nextPara = GetParagraphAtPosition(range.GetEnd()+1);
- if (nextPara)
+ wxRichTextParagraph* nextPara = GetParagraphAtPosition(range.GetStart()+1);
+ if (nextPara && nextPara != para)
{
- wxRichTextParagraph* para = (wxRichTextParagraph*) action->GetOldParagraphs().GetChild(0);
- para->SetAttributes(nextPara->GetAttributes());
+ action->GetOldParagraphs().GetChildren().GetFirst()->GetData()->SetAttributes(nextPara->GetAttributes());
+ action->GetOldParagraphs().GetAttributes().SetFlags(action->GetOldParagraphs().GetAttributes().GetFlags() | wxTEXT_ATTR_KEEP_FIRST_PARA_STYLE);
}
}
}
if (richTextBuffer)
{
InsertParagraphsWithUndo(position+1, *richTextBuffer, GetRichTextCtrl(), wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE);
+ if (GetRichTextCtrl())
+ GetRichTextCtrl()->ShowPosition(position + richTextBuffer->GetRange().GetEnd());
delete richTextBuffer;
}
}
#endif
InsertTextWithUndo(position+1, text2, GetRichTextCtrl());
+ if (GetRichTextCtrl())
+ GetRichTextCtrl()->ShowPosition(position + text2.Length());
+
success = true;
}
else if (wxTheClipboard->IsSupported(wxDF_BITMAP))
if (attr.GetTextColour().Ok())
dc.SetTextForeground(attr.GetTextColour());
- dc.SetBackgroundMode(wxTRANSPARENT);
+ dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
int charHeight = dc.GetCharHeight();
wxCoord tw, th;
m_buffer->InsertFragment(GetRange().GetStart(), m_newParagraphs);
m_buffer->UpdateRanges();
- m_buffer->Invalidate(wxRichTextRange(GetRange().GetStart()-1, GetRange().GetEnd()));
+ m_buffer->Invalidate(wxRichTextRange(wxMax(0, GetRange().GetStart()-1), GetRange().GetEnd()));
long newCaretPosition = GetPosition() + m_newParagraphs.GetRange().GetLength();
m_buffer->UpdateRanges();
m_buffer->Invalidate(wxRichTextRange(GetRange().GetStart(), GetRange().GetStart()));
- UpdateAppearance(GetRange().GetStart()-1, true /* send update event */);
+ long caretPos = GetRange().GetStart()-1;
+ if (caretPos >= m_buffer->GetRange().GetEnd())
+ caretPos --;
+
+ UpdateAppearance(caretPos, true /* send update event */);
wxRichTextEvent cmdEvent(
wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED,
if (!m_ctrl->IsFrozen())
{
m_ctrl->LayoutContent();
- m_ctrl->PositionCaret();
#if wxRICHTEXT_USE_OPTIMIZED_DRAWING
// Find refresh rectangle if we are in a position to optimise refresh
/// Get/set the object size for the given range. Returns false if the range
/// is invalid for this object.
-bool wxRichTextImage::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& WXUNUSED(descent), wxDC& WXUNUSED(dc), int WXUNUSED(flags), wxPoint WXUNUSED(position)) const
+bool wxRichTextImage::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& WXUNUSED(descent), wxDC& WXUNUSED(dc), int WXUNUSED(flags), wxPoint WXUNUSED(position), wxArrayInt* partialExtents) const
{
if (!range.IsWithin(GetRange()))
return false;
+ if (partialExtents)
+ {
+ if (m_image.Ok())
+ partialExtents->Add(m_image.GetWidth());
+ else
+ partialExtents->Add(0);
+ }
+
if (!m_image.Ok())
return false;