// Copyright: (c) Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
-wxRICHTEXT_NONE
+
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
// Get floating objects
bool GetFloatingObjects(wxRichTextObjectList& objects) const;
+ // Delete a float
+ bool DeleteFloat(wxRichTextObject* obj);
+
+ // Do we have this float already?
+ bool HasFloat(wxRichTextObject* obj);
+
+ bool HasFloats() const { return m_left.GetCount() >0 || m_right.GetCount() > 0; }
+
static int SearchAdjacentRect(const wxRichTextFloatRectMapArray& array, int point);
static int GetWidthFromFloatRect(const wxRichTextFloatRectMapArray& array, int index, int startY, int endY);
wxRichTextParagraph* m_para;
};
+// Delete a float
+bool wxRichTextFloatCollector::DeleteFloat(wxRichTextObject* obj)
+{
+ size_t i;
+ for (i = 0; i < m_left.GetCount(); i++)
+ {
+ if (m_left[i]->anchor == obj)
+ {
+ m_left.RemoveAt(i);
+ return true;
+ }
+ }
+ for (i = 0; i < m_right.GetCount(); i++)
+ {
+ if (m_right[i]->anchor == obj)
+ {
+ m_right.RemoveAt(i);
+ return true;
+ }
+ }
+ return false;
+}
+
+// Do we have this float already?
+bool wxRichTextFloatCollector::HasFloat(wxRichTextObject* obj)
+{
+ size_t i;
+ for (i = 0; i < m_left.GetCount(); i++)
+ {
+ if (m_left[i]->anchor == obj)
+ {
+ return true;
+ }
+ }
+ for (i = 0; i < m_right.GetCount(); i++)
+ {
+ if (m_right[i]->anchor == obj)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
// Get floating objects
bool wxRichTextFloatCollector::GetFloatingObjects(wxRichTextObjectList& objects) const
{
// If a paragraph, align the whole paragraph.
// Problem with this: if we're limited by a floating object, a line may be centered
// w.r.t. the smaller resulting box rather than the actual available width.
- if (attr.HasAlignment())
+ if (attr.HasAlignment() && !GetContainer()->GetFloatCollector()->HasFloats()) // FIXME: aligning whole paragraph not compatible with floating objects
{
// centering, right-justification
if (GetAttributes().GetAlignment() == wxTEXT_ALIGNMENT_CENTRE)
m_defaultAttributes = obj.m_defaultAttributes;
}
-// Gather information about floating objects
+// Gather information about floating objects; only gather floats for those paragraphs that
+// will not be formatted again due to optimization, after which floats will be gathered per-paragraph
+// during layout.
bool wxRichTextParagraphLayoutBox::UpdateFloatingObjects(const wxRect& availableRect, wxRichTextObject* untilObj)
{
if (m_floatCollector != NULL)
delete m_floatCollector;
m_floatCollector = new wxRichTextFloatCollector(availableRect);
wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
- while (node && node->GetData() != untilObj)
+ // Only gather floats up to the point we'll start formatting paragraphs.
+ while (untilObj && node && node->GetData() != untilObj)
{
wxRichTextParagraph* child = wxDynamicCast(node->GetData(), wxRichTextParagraph);
wxASSERT (child != NULL);
return wxRICHTEXT_HITTEST_NONE;
int ret = wxRICHTEXT_HITTEST_NONE;
- if (m_floatCollector)
+ if (m_floatCollector && (flags & wxRICHTEXT_HITTEST_NO_FLOATING_OBJECTS) == 0)
ret = m_floatCollector->HitTest(dc, pt, textPosition, obj, flags);
if (ret == wxRICHTEXT_HITTEST_NONE)
}
}
+ // Gather information about only those floating objects that will not be formatted,
+ // after which floats will be gathered per-paragraph during layout.
UpdateFloatingObjects(availableSpace, node ? node->GetData() : (wxRichTextObject*) NULL);
// A way to force speedy rest-of-buffer layout (the 'else' below)
// Assume this box only contains paragraphs
wxRichTextParagraph* child = wxDynamicCast(node->GetData(), wxRichTextParagraph);
- wxCHECK_MSG( child, false, wxT("Unknown object in layout") );
+ // Unsure if this is needed
+ // wxCHECK_MSG( child, false, wxT("Unknown object in layout") );
if (child && child->IsShown())
{
// Now top and tail the first and last paragraphs in our new fragment (which might be the same).
if (!fragment.IsEmpty())
{
- wxRichTextRange topTailRange(range);
-
wxRichTextParagraph* firstPara = wxDynamicCast(fragment.GetChildren().GetFirst()->GetData(), wxRichTextParagraph);
wxASSERT( firstPara != NULL );
+ wxRichTextParagraph* lastPara = wxDynamicCast(fragment.GetChildren().GetLast()->GetData(), wxRichTextParagraph);
+ wxASSERT( lastPara != NULL );
+
+ if (!firstPara || !lastPara)
+ return false;
+
+ bool isFragment = (range.GetEnd() < lastPara->GetRange().GetEnd());
+
+ long firstPos = firstPara->GetRange().GetStart();
+
+ // Adjust for renumbering from zero
+ wxRichTextRange topTailRange(range.GetStart() - firstPos, range.GetEnd() - firstPos);
+
+ long end;
+ fragment.CalculateRange(0, end);
+
// Chop off the start of the paragraph
- if (topTailRange.GetStart() > firstPara->GetRange().GetStart())
+ if (topTailRange.GetStart() > 0)
{
- wxRichTextRange r(firstPara->GetRange().GetStart(), topTailRange.GetStart()-1);
+ wxRichTextRange r(0, topTailRange.GetStart()-1);
firstPara->DeleteRange(r);
// Make sure the numbering is correct
- long end;
- fragment.CalculateRange(firstPara->GetRange().GetStart(), end);
+ fragment.CalculateRange(0, end);
// Now, we've deleted some positions, so adjust the range
// accordingly.
- topTailRange.SetEnd(topTailRange.GetEnd() - r.GetLength());
+ topTailRange.SetStart(range.GetLength());
+ topTailRange.SetEnd(fragment.GetOwnRange().GetEnd());
+ }
+ else
+ {
+ topTailRange.SetStart(range.GetLength());
+ topTailRange.SetEnd(fragment.GetOwnRange().GetEnd());
}
- wxRichTextParagraph* lastPara = wxDynamicCast(fragment.GetChildren().GetLast()->GetData(), wxRichTextParagraph);
- wxASSERT( lastPara != NULL );
-
- if (topTailRange.GetEnd() < (lastPara->GetRange().GetEnd()-1))
+ if (topTailRange.GetStart() < (lastPara->GetRange().GetEnd()-1))
{
- wxRichTextRange r(topTailRange.GetEnd()+1, lastPara->GetRange().GetEnd()-1); /* -1 since actual text ends 1 position before end of para marker */
- lastPara->DeleteRange(r);
+ lastPara->DeleteRange(topTailRange);
// Make sure the numbering is correct
long end;
- fragment.CalculateRange(firstPara->GetRange().GetStart(), end);
+ fragment.CalculateRange(0, end);
// We only have part of a paragraph at the end
fragment.SetPartialParagraph(true);
}
else
{
- if (topTailRange.GetEnd() == (lastPara->GetRange().GetEnd() - 1))
- // We have a partial paragraph (don't save last new paragraph marker)
- fragment.SetPartialParagraph(true);
- else
- // We have a complete paragraph
- fragment.SetPartialParagraph(false);
+ // We have a partial paragraph (don't save last new paragraph marker)
+ // or complete paragraph
+ fragment.SetPartialParagraph(isFragment);
}
}
/// Get all the text
wxString wxRichTextParagraphLayoutBox::GetText() const
{
- return GetTextForRange(GetRange());
+ return GetTextForRange(GetOwnRange());
}
/// Get the paragraph by number
// Deal with floating objects firstly before the normal layout
wxRichTextBuffer* buffer = GetBuffer();
wxASSERT(buffer);
- wxRichTextFloatCollector* collector = buffer->GetFloatCollector();
+ wxRichTextFloatCollector* collector = GetContainer()->GetFloatCollector();
wxASSERT(collector);
LayoutFloat(dc, rect, style, collector);
int lineSpacing = 0;
// Let's assume line spacing of 10 is normal, 15 is 1.5, 20 is 2, etc.
- if (attr.HasLineSpacing() && attr.GetLineSpacing() > 0 && attr.GetFont().Ok())
+ if (attr.HasLineSpacing() && attr.GetLineSpacing() > 0 && attr.GetFont().IsOk())
{
wxCheckSetFont(dc, attr.GetFont());
lineSpacing = (int) (double(dc.GetCharHeight()) * (double(attr.GetLineSpacing())/10.0 - 1.0));
wxRichTextObjectList::compatibility_iterator node;
#if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS
-#if 0
- node = m_children.GetFirst();
- while (node)
- {
- wxRichTextObject* child = node->GetData();
- if (child->IsTopLevel())
- {
- //child->SetCachedSize(wxDefaultSize);
- wxRect availableChildRect = AdjustAvailableSpace(dc, GetBuffer(), GetAttributes(), child->GetAttributes(), rect);
-
- // Hm, can't do this here, we surely need to take into account indents, margins, floating images etc.
- // So need to call layout lower down.
- child->Layout(dc, availableChildRect, style);
- }
-
- node = node->GetNext();
- }
-#endif
-
wxUnusedVar(style);
wxArrayInt partialExtents;
int paraDescent = 0;
// This calculates the partial text extents
- GetRangeSize(GetRange(), paraSize, paraDescent, dc, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_CACHE_SIZE, wxPoint(0,0), & partialExtents);
+ GetRangeSize(GetRange(), paraSize, paraDescent, dc, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_CACHE_SIZE, rect.GetPosition(), & partialExtents);
#else
node = m_children.GetFirst();
while (node)
// lays out the object again using the minimum size
// The position will be determined by its location in its line,
// and not by the child's actual position.
- child->LayoutToBestSize(dc, GetBuffer(),
+ child->LayoutToBestSize(dc, buffer,
GetAttributes(), child->GetAttributes(), availableRect, style);
if (oldSize != child->GetCachedSize())
// Lays out the object first with a given amount of space, and then if no width was specified in attr,
// lays out the object again using the minimum size
child->Invalidate(wxRICHTEXT_ALL);
- child->LayoutToBestSize(dc, GetBuffer(),
+ child->LayoutToBestSize(dc, buffer,
GetAttributes(), child->GetAttributes(), availableRect, style);
childSize = child->GetCachedSize();
childDescent = child->GetDescent();
maxAscent = wxMax(actualSize.y-childDescent, maxAscent);
lineHeight = maxDescent + maxAscent;
- if (lineHeight == 0 && GetBuffer())
+ if (lineHeight == 0 && buffer)
{
- wxFont font(GetBuffer()->GetFontTable().FindFont(attr));
+ wxFont font(buffer->GetFontTable().FindFont(attr));
wxCheckSetFont(dc, font);
lineHeight = dc.GetCharHeight();
}
}
}
- wxASSERT(!(lastCompletedEndPos != -1 && lastCompletedEndPos < GetRange().GetEnd()-1));
-
-#if 0
- // Add the last line - it's the current pos -> last para pos
- // Substract -1 because the last position is always the end-paragraph position.
- if (lastCompletedEndPos <= GetRange().GetEnd()-1)
- {
- currentPosition.x = availableRect.x - rect.x;
-
- wxRichTextLine* line = AllocateLine(lineCount);
-
- wxRichTextRange actualRange(lastCompletedEndPos+1, GetRange().GetEnd()-1);
-
- // Set relative range so we won't have to change line ranges when paragraphs are moved
- line->SetRange(wxRichTextRange(actualRange.GetStart() - GetRange().GetStart(), actualRange.GetEnd() - GetRange().GetStart()));
-
- line->SetPosition(currentPosition);
-
- if (lineHeight == 0 && GetBuffer())
- {
- wxFont font(GetBuffer()->GetFontTable().FindFont(attr));
- wxCheckSetFont(dc, font);
- lineHeight = dc.GetCharHeight();
- }
- if (maxDescent == 0)
- {
- int w, h;
- dc.GetTextExtent(wxT("X"), & w, &h, & maxDescent);
- }
-
- line->SetSize(wxSize(currentWidth, lineHeight));
- line->SetDescent(maxDescent);
- maxWidth = wxMax(maxWidth, currentWidth+startOffset);
- currentPosition.y += lineHeight;
- currentPosition.y += lineSpacing;
- lineCount ++;
- }
-#endif
+ //wxASSERT(!(lastCompletedEndPos != -1 && lastCompletedEndPos < GetRange().GetEnd()-1));
// Remove remaining unused line objects, if any
ClearUnusedLines(lineCount);
{
wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect;
contentRect = wxRect(wxPoint(0, 0), wxSize(maxWidth, currentPosition.y + spaceAfterPara));
- GetBoxRects(dc, GetBuffer(), GetAttributes(), marginRect, borderRect, contentRect, paddingRect, outlineRect);
+ GetBoxRects(dc, buffer, GetAttributes(), marginRect, borderRect, contentRect, paddingRect, outlineRect);
SetCachedSize(marginRect.GetSize());
}
{
wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect;
contentRect = wxRect(wxPoint(0, 0), wxSize(paraSize.x, currentPosition.y + spaceAfterPara));
- GetBoxRects(dc, GetBuffer(), GetAttributes(), marginRect, borderRect, contentRect, paddingRect, outlineRect);
+ GetBoxRects(dc, buffer, GetAttributes(), marginRect, borderRect, contentRect, paddingRect, outlineRect);
SetMaxSize(marginRect.GetSize());
}
wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect;
contentRect = wxRect(wxPoint(0, 0), wxSize(minWidth, currentPosition.y + spaceAfterPara));
- GetBoxRects(dc, GetBuffer(), GetAttributes(), marginRect, borderRect, contentRect, paddingRect, outlineRect);
+ GetBoxRects(dc, buffer, GetAttributes(), marginRect, borderRect, contentRect, paddingRect, outlineRect);
SetMinSize(marginRect.GetSize());
}
return true;
}
-#if 0
-/// Apply paragraph styles, such as centering, to wrapped lines
-/// TODO: take into account box attributes
-void wxRichTextParagraph::ApplyParagraphStyle(const wxRichTextAttr& attr, const wxRect& rect, wxDC& dc)
-{
- if (!attr.HasAlignment())
- return;
-
- wxRichTextLineList::compatibility_iterator node = m_cachedLines.GetFirst();
- while (node)
- {
- wxRichTextLine* line = node->GetData();
-
- wxPoint pos = line->GetPosition();
- wxSize size = line->GetSize();
-
- // centering, right-justification
- if (attr.HasAlignment() && GetAttributes().GetAlignment() == wxTEXT_ALIGNMENT_CENTRE)
- {
- int rightIndent = ConvertTenthsMMToPixels(dc, attr.GetRightIndent());
- // Subtract paragraph position because lines are relative to
- // the paragraph.
- pos.x = rect.x - GetPosition().x + (rect.GetWidth() - rightIndent - size.x)/2;
- line->SetPosition(pos);
- }
- else if (attr.HasAlignment() && GetAttributes().GetAlignment() == wxTEXT_ALIGNMENT_RIGHT)
- {
- int rightIndent = ConvertTenthsMMToPixels(dc, attr.GetRightIndent());
- // Subtract paragraph position because lines are relative to
- // the paragraph.
- pos.x = (rect.x - GetPosition().x) + rect.GetWidth() - size.x - rightIndent;
- line->SetPosition(pos);
- }
-
- node = node->GetNext();
- }
-}
-#endif
-
/// Apply paragraph styles, such as centering, to wrapped lines
/// TODO: take into account box attributes, possibly
void wxRichTextParagraph::ApplyParagraphStyle(wxRichTextLine* line, const wxRichTextAttr& attr, const wxRect& rect, wxDC& dc)
int paraDescent;
// This calculates the partial text extents
- GetRangeSize(lineRange, paraSize, paraDescent, dc, wxRICHTEXT_UNFORMATTED, wxPoint(0,0), & partialExtents);
+ GetRangeSize(lineRange, paraSize, paraDescent, dc, wxRICHTEXT_UNFORMATTED, linePos, & partialExtents);
int lastX = linePos.x;
size_t i;
while (node)
{
wxRichTextObject* anchored = node->GetData();
- if (anchored && anchored->IsFloating())
+ if (anchored && anchored->IsFloating() && !floatCollector->HasFloat(anchored))
{
wxSize size;
int descent, x = 0;
int charHeight = dc.GetCharHeight();
int x, y;
- if ( textFont.Ok() )
+ if ( textFont.IsOk() )
{
if ( textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUPERSCRIPT) )
{
bool bScript(false);
wxFont font(GetBuffer()->GetFontTable().FindFont(textAttr));
- if (font.Ok())
+ if (font.IsOk())
{
if ( textAttr.HasTextEffects() && ( (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUPERSCRIPT)
|| (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUBSCRIPT) ) )
}
/// Submit command to insert paragraphs
-bool wxRichTextParagraphLayoutBox::InsertParagraphsWithUndo(long pos, const wxRichTextParagraphLayoutBox& paragraphs, wxRichTextCtrl* ctrl, wxRichTextBuffer* buffer, int flags)
+bool wxRichTextParagraphLayoutBox::InsertParagraphsWithUndo(long pos, const wxRichTextParagraphLayoutBox& paragraphs, wxRichTextCtrl* ctrl, wxRichTextBuffer* buffer, int WXUNUSED(flags))
{
wxRichTextAction* action = new wxRichTextAction(NULL, _("Insert Text"), wxRICHTEXT_INSERT, buffer, this, ctrl, false);
- wxRichTextAttr attr(buffer->GetDefaultStyle());
-
- wxRichTextAttr* p = NULL;
- wxRichTextAttr paraAttr;
- if (flags & wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE)
- {
- paraAttr = GetStyleForNewParagraph(buffer, pos);
- if (!paraAttr.IsDefault())
- p = & paraAttr;
- }
- else
- p = & attr;
-
action->GetNewParagraphs() = paragraphs;
- if (p && !p->IsDefault())
- {
- for (wxRichTextObjectList::compatibility_iterator node = action->GetNewParagraphs().GetChildren().GetFirst(); node; node = node->GetNext())
- {
- wxRichTextObject* child = node->GetData();
- child->SetAttributes(*p);
- }
- }
-
action->SetPosition(pos);
wxRichTextRange range = wxRichTextRange(pos, pos + paragraphs.GetOwnRange().GetEnd() - 1);
int length = action->GetNewParagraphs().GetOwnRange().GetLength();
- if (text.length() > 0 && text.Last() != wxT('\n'))
+ if (!text.empty() && text.Last() != wxT('\n'))
{
// Don't count the newline when undoing
length --;
action->GetNewParagraphs().SetPartialParagraph(true);
}
- else if (text.length() > 0 && text.Last() == wxT('\n'))
+ else if (!text.empty() && text.Last() == wxT('\n'))
length --;
action->SetPosition(pos);
{
wxRichTextStyleSheet* oldSheet = GetStyleSheet();
- wxWindowID id = wxID_ANY;
+ wxWindowID winid = wxID_ANY;
if (GetRichTextCtrl())
- id = GetRichTextCtrl()->GetId();
+ winid = GetRichTextCtrl()->GetId();
- wxRichTextEvent event(wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACING, id);
+ wxRichTextEvent event(wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACING, winid);
event.SetEventObject(GetRichTextCtrl());
event.SetContainer(GetRichTextCtrl()->GetFocusObject());
event.SetOldStyleSheet(oldSheet);
bool wxRichTextStdRenderer::DrawStandardBullet(wxRichTextParagraph* paragraph, wxDC& dc, const wxRichTextAttr& bulletAttr, const wxRect& rect)
{
- if (bulletAttr.GetTextColour().Ok())
+ if (bulletAttr.GetTextColour().IsOk())
{
wxCheckSetPen(dc, wxPen(bulletAttr.GetTextColour()));
wxCheckSetBrush(dc, wxBrush(bulletAttr.GetTextColour()));
wxCheckSetFont(dc, font);
- if (attr.GetTextColour().Ok())
+ if (attr.GetTextColour().IsOk())
dc.SetTextForeground(attr.GetTextColour());
dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
wxRichTextCell* cell = GetCell(j, i);
if (cell->IsShown())
{
- wxASSERT(colWidths[i] > 0);
-
// Get max specified cell height
// Don't handle percentages for height
if (cell->GetAttributes().GetTextBoxAttr().GetHeight().IsValid() && cell->GetAttributes().GetTextBoxAttr().GetHeight().GetUnits() != wxTEXT_ATTR_UNITS_PERCENTAGE)
return wxDynamicCast(obj, wxRichTextCell);
}
else
- return false;
+ return NULL;
}
// Returns a selection object specifying the selections between start and end character positions.
m_ctrl->Refresh(false);
m_ctrl->PositionCaret();
- m_ctrl->SetDefaultStyleToCursorStyle();
+
+ // This causes styles to persist when doing programmatic
+ // content creation except when Freeze/Thaw is used, so
+ // disable this and check for the consequences.
+ // m_ctrl->SetDefaultStyleToCursorStyle();
if (sendUpdateEvent)
wxTextCtrl::SendTextUpdatedEvent(m_ctrl);
bool wxRichTextFileHandler::LoadFile(wxRichTextBuffer *buffer, const wxString& filename)
{
wxFFileInputStream stream(filename);
- if (stream.Ok())
+ if (stream.IsOk())
return LoadFile(buffer, stream);
return false;
bool wxRichTextFileHandler::SaveFile(wxRichTextBuffer *buffer, const wxString& filename)
{
wxFFileOutputStream stream(filename);
- if (stream.Ok())
+ if (stream.IsOk())
return SaveFile(buffer, stream);
return false;
// Write data in hex to a stream
bool wxRichTextImageBlock::WriteHex(wxOutputStream& stream)
{
- const int bufSize = 512;
- char buf[bufSize+1];
+ if (m_dataSize == 0)
+ return true;
+
+ int bufSize = 100000;
+ if (int(2*m_dataSize) < bufSize)
+ bufSize = 2*m_dataSize;
+ char* buf = new char[bufSize+1];
int left = m_dataSize;
int n, i, j;
buf[n] = 0;
stream.Write((const char*) buf, n);
}
+ delete[] buf;
return true;
}
unsigned char* wxRichTextImageBlock::ReadBlock(const wxString& filename, size_t size)
{
wxFileInputStream stream(filename);
- if (!stream.Ok())
+ if (!stream.IsOk())
return NULL;
return ReadBlock(stream, size);
bool wxRichTextImageBlock::WriteBlock(const wxString& filename, unsigned char* block, size_t size)
{
wxFileOutputStream outStream(filename);
- if (!outStream.Ok())
+ if (!outStream.IsOk())
return false;
return WriteBlock(outStream, block, size);