#include "wx/richtext/richtextstyles.h"
#include "wx/richtext/richtextimagedlg.h"
#include "wx/richtext/richtextsizepage.h"
+#include "wx/richtext/richtextxml.h"
#include "wx/listimpl.cpp"
#include "wx/arrimpl.cpp"
int GetLastRectBottom();
// Draw the floats inside a rect
- void Draw(wxDC& dc, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style);
+ void Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style);
// HitTest the floats
- int HitTest(wxDC& dc, const wxPoint& pt, long& textPosition, wxRichTextObject** obj, int flags);
+ int HitTest(wxDC& dc, wxRichTextDrawingContext& context, const wxPoint& pt, long& textPosition, wxRichTextObject** obj, int flags);
// Get floating object count
int GetFloatingObjectCount() const { return m_left.GetCount() + m_right.GetCount(); }
static void FreeFloatRectMapArray(wxRichTextFloatRectMapArray& array);
- static void DrawFloat(const wxRichTextFloatRectMapArray& array, wxDC& dc, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style);
+ static void DrawFloat(const wxRichTextFloatRectMapArray& array, wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style);
- static int HitTestFloat(const wxRichTextFloatRectMapArray& array, wxDC& WXUNUSED(dc), const wxPoint& pt, long& textPosition, wxRichTextObject** obj, int flags);
+ static int HitTestFloat(const wxRichTextFloatRectMapArray& array, wxDC& dc, wxRichTextDrawingContext& context, const wxPoint& pt, long& textPosition, wxRichTextObject** obj, int flags);
private:
wxRichTextFloatRectMapArray m_left;
return ret;
}
-void wxRichTextFloatCollector::DrawFloat(const wxRichTextFloatRectMapArray& array, wxDC& dc, const wxRichTextRange& WXUNUSED(range), const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
+void wxRichTextFloatCollector::DrawFloat(const wxRichTextFloatRectMapArray& array, wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& WXUNUSED(range), const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
{
int start = rect.y;
int end = rect.y + rect.height;
{
wxRichTextObject* obj = array[i]->anchor;
wxRichTextRange r = obj->GetRange();
- obj->Draw(dc, r, selection, wxRect(obj->GetPosition(), obj->GetCachedSize()), descent, style);
+ obj->Draw(dc, context, r, selection, wxRect(obj->GetPosition(), obj->GetCachedSize()), descent, style);
i++;
}
}
-void wxRichTextFloatCollector::Draw(wxDC& dc, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
+void wxRichTextFloatCollector::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
{
if (m_left.GetCount() > 0)
- DrawFloat(m_left, dc, range, selection, rect, descent, style);
+ DrawFloat(m_left, dc, context, range, selection, rect, descent, style);
if (m_right.GetCount() > 0)
- DrawFloat(m_right, dc, range, selection, rect, descent, style);
+ DrawFloat(m_right, dc, context, range, selection, rect, descent, style);
}
-int wxRichTextFloatCollector::HitTestFloat(const wxRichTextFloatRectMapArray& array, wxDC& WXUNUSED(dc), const wxPoint& pt, long& textPosition, wxRichTextObject** obj, int WXUNUSED(flags))
+int wxRichTextFloatCollector::HitTestFloat(const wxRichTextFloatRectMapArray& array, wxDC& WXUNUSED(dc), wxRichTextDrawingContext& WXUNUSED(context), const wxPoint& pt, long& textPosition, wxRichTextObject** obj, int WXUNUSED(flags))
{
int i;
if (array.GetCount() == 0)
return wxRICHTEXT_HITTEST_NONE;
}
-int wxRichTextFloatCollector::HitTest(wxDC& dc, const wxPoint& pt, long& textPosition, wxRichTextObject** obj, int flags)
+int wxRichTextFloatCollector::HitTest(wxDC& dc, wxRichTextDrawingContext& context, const wxPoint& pt, long& textPosition, wxRichTextObject** obj, int flags)
{
- int ret = HitTestFloat(m_left, dc, pt, textPosition, obj, flags);
+ int ret = HitTestFloat(m_left, dc, context, pt, textPosition, obj, flags);
if (ret == wxRICHTEXT_HITTEST_NONE)
{
- ret = HitTestFloat(m_right, dc, pt, textPosition, obj, flags);
+ ret = HitTestFloat(m_right, dc, context, pt, textPosition, obj, flags);
}
return ret;
}
// Helpers for efficiency
inline void wxCheckSetFont(wxDC& dc, const wxFont& font)
{
- // JACS: did I do this some time ago when testing? Should we re-enable it?
-#if 0
- 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.GetUnderlined() == font.GetUnderlined() &&
- font1.GetFamily() == font.GetFamily() &&
- font1.GetFaceName() == font.GetFaceName())
- return;
- }
-#endif
dc.SetFont(font);
}
// Calculate the available content space in the given rectangle, given the
// margins, border and padding specified in the object's attributes.
-wxRect wxRichTextObject::GetAvailableContentArea(wxDC& dc, const wxRect& outerRect) const
+wxRect wxRichTextObject::GetAvailableContentArea(wxDC& dc, wxRichTextDrawingContext& context, const wxRect& outerRect) const
{
wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect;
marginRect = outerRect;
- GetBoxRects(dc, GetBuffer(), GetAttributes(), marginRect, borderRect, contentRect, paddingRect, outlineRect);
+ wxRichTextAttr attr(GetAttributes());
+ context.ApplyVirtualAttributes(attr, (wxRichTextObject*) this);
+ GetBoxRects(dc, GetBuffer(), attr, marginRect, borderRect, contentRect, paddingRect, outlineRect);
return contentRect;
}
{
if (invalidRange != wxRICHTEXT_NONE)
{
- SetCachedSize(wxDefaultSize);
+ // If this is a floating object, size may not be recalculated
+ // after floats have been collected in an early stage of Layout.
+ // So avoid resetting the cache for floating objects during layout.
+ if (!IsFloating())
+ SetCachedSize(wxDefaultSize);
SetMaxSize(wxDefaultSize);
SetMinSize(wxDefaultSize);
}
// Unscale
double scale = 1.0;
if (GetBuffer())
- scale = GetBuffer()->GetScale();
+ scale = GetBuffer()->GetScale() / GetBuffer()->GetDimensionScale();
int p = ConvertTenthsMMToPixels(dc.GetPPI().x, units, scale);
return p;
wxRichTextBuffer* wxRichTextObject::GetBuffer() const
{
const wxRichTextObject* obj = this;
- while (obj && !obj->IsKindOf(CLASSINFO(wxRichTextBuffer)))
+ while (obj && !wxDynamicCast(obj, wxRichTextBuffer))
obj = obj->GetParent();
return wxDynamicCast(obj, wxRichTextBuffer);
}
// Hit-testing: returns a flag indicating hit test details, plus
// information about position
-int wxRichTextObject::HitTest(wxDC& WXUNUSED(dc), const wxPoint& pt, long& textPosition, wxRichTextObject** obj, wxRichTextObject** contextObj, int WXUNUSED(flags))
+int wxRichTextObject::HitTest(wxDC& WXUNUSED(dc), wxRichTextDrawingContext& WXUNUSED(context), const wxPoint& pt, long& textPosition, wxRichTextObject** obj, wxRichTextObject** contextObj, int WXUNUSED(flags))
{
if (!IsShown())
return wxRICHTEXT_HITTEST_NONE;
// 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 maximum ('best') size
-bool wxRichTextObject::LayoutToBestSize(wxDC& dc, wxRichTextBuffer* buffer,
+bool wxRichTextObject::LayoutToBestSize(wxDC& dc, wxRichTextDrawingContext& context, wxRichTextBuffer* buffer,
const wxRichTextAttr& parentAttr, const wxRichTextAttr& attr,
const wxRect& availableParentSpace, const wxRect& availableContainerSpace,
int style)
{
wxRect availableChildRect = AdjustAvailableSpace(dc, buffer, parentAttr, attr, availableParentSpace, availableContainerSpace);
wxRect originalAvailableRect = availableChildRect;
- Layout(dc, availableChildRect, availableContainerSpace, style);
+ Layout(dc, context, availableChildRect, availableContainerSpace, style);
wxSize maxSize = GetMaxSize();
if (attr.HasAlignment() && !GetContainer()->GetFloatCollector()->HasFloats()) // FIXME: aligning whole paragraph not compatible with floating objects
{
// centering, right-justification
- if (GetAttributes().GetAlignment() == wxTEXT_ALIGNMENT_CENTRE)
+ if (attr.GetAlignment() == wxTEXT_ALIGNMENT_CENTRE)
{
availableChildRect.x = (originalAvailableRect.GetWidth() - availableChildRect.GetWidth())/2 + availableChildRect.x;
}
- else if (GetAttributes().GetAlignment() == wxTEXT_ALIGNMENT_RIGHT)
+ else if (attr.GetAlignment() == wxTEXT_ALIGNMENT_RIGHT)
{
availableChildRect.x = availableChildRect.x + originalAvailableRect.GetWidth() - availableChildRect.GetWidth();
}
}
- Layout(dc, availableChildRect, availableContainerSpace, style);
+ Layout(dc, context, availableChildRect, availableContainerSpace, style);
}
/*
/// Hit-testing: returns a flag indicating hit test details, plus
/// information about position
-int wxRichTextCompositeObject::HitTest(wxDC& dc, const wxPoint& pt, long& textPosition, wxRichTextObject** obj, wxRichTextObject** contextObj, int flags)
+int wxRichTextCompositeObject::HitTest(wxDC& dc, wxRichTextDrawingContext& context, const wxPoint& pt, long& textPosition, wxRichTextObject** obj, wxRichTextObject** contextObj, int flags)
{
if (!IsShown())
return wxRICHTEXT_HITTEST_NONE;
if (child->IsShown() && child->IsTopLevel() && (flags & wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS))
{
// Just check if we hit the overall object
- int ret = child->wxRichTextObject::HitTest(dc, pt, textPosition, obj, contextObj, flags);
+ int ret = child->wxRichTextObject::HitTest(dc, context, pt, textPosition, obj, contextObj, flags);
if (ret != wxRICHTEXT_HITTEST_NONE)
return ret;
}
else if (child->IsShown())
{
- int ret = child->HitTest(dc, pt, textPosition, obj, contextObj, flags);
+ int ret = child->HitTest(dc, context, pt, textPosition, obj, contextObj, flags);
if (ret != wxRICHTEXT_HITTEST_NONE)
return ret;
}
}
/// Finds the absolute position and row height for the given character position
-bool wxRichTextCompositeObject::FindPosition(wxDC& dc, long index, wxPoint& pt, int* height, bool forceLineStart)
+bool wxRichTextCompositeObject::FindPosition(wxDC& dc, wxRichTextDrawingContext& context, long index, wxPoint& pt, int* height, bool forceLineStart)
{
wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
while (node)
// such as a text box, because the character position will no longer
// apply. By definition, a top-level object has its own range of
// character positions.
- if (!child->IsTopLevel() && child->FindPosition(dc, index, pt, height, forceLineStart))
+ if (!child->IsTopLevel() && child->FindPosition(dc, context, index, pt, height, forceLineStart))
return true;
node = node->GetNext();
/// Get/set the object size for the given range. Returns false if the range
/// is invalid for this object.
-bool wxRichTextCompositeObject::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position, wxArrayInt* partialExtents) const
+bool wxRichTextCompositeObject::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, wxPoint position, wxArrayInt* partialExtents) const
{
if (!range.IsWithin(GetRange()))
return false;
sz.x += childSize.x;
descent = wxMax(descent, childDescent);
}
- else if (child->GetRangeSize(rangeToUse, childSize, childDescent, dc, flags, wxPoint(position.x + sz.x, position.y), p))
+ else if (child->GetRangeSize(rangeToUse, childSize, childDescent, dc, context, flags, wxPoint(position.x + sz.x, position.y), p))
{
sz.y = wxMax(sz.y, childSize.y);
sz.x += childSize.x;
m_invalidRange = wxRICHTEXT_ALL;
- SetMargins(4);
m_partialParagraph = false;
m_floatCollector = NULL;
}
}
// HitTest
-int wxRichTextParagraphLayoutBox::HitTest(wxDC& dc, const wxPoint& pt, long& textPosition, wxRichTextObject** obj, wxRichTextObject** contextObj, int flags)
+int wxRichTextParagraphLayoutBox::HitTest(wxDC& dc, wxRichTextDrawingContext& context, const wxPoint& pt, long& textPosition, wxRichTextObject** obj, wxRichTextObject** contextObj, int flags)
{
if (!IsShown())
return wxRICHTEXT_HITTEST_NONE;
int ret = wxRICHTEXT_HITTEST_NONE;
if (m_floatCollector && (flags & wxRICHTEXT_HITTEST_NO_FLOATING_OBJECTS) == 0)
- ret = m_floatCollector->HitTest(dc, pt, textPosition, obj, flags);
+ ret = m_floatCollector->HitTest(dc, context, pt, textPosition, obj, flags);
if (ret == wxRICHTEXT_HITTEST_NONE)
- return wxRichTextCompositeObject::HitTest(dc, pt, textPosition, obj, contextObj, flags);
+ return wxRichTextCompositeObject::HitTest(dc, context, pt, textPosition, obj, contextObj, flags);
else
{
*contextObj = this;
}
/// Draw the floating objects
-void wxRichTextParagraphLayoutBox::DrawFloats(wxDC& dc, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
+void wxRichTextParagraphLayoutBox::DrawFloats(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
{
if (m_floatCollector)
- m_floatCollector->Draw(dc, range, selection, rect, descent, style);
+ m_floatCollector->Draw(dc, context, range, selection, rect, descent, style);
}
void wxRichTextParagraphLayoutBox::MoveAnchoredObjectToParagraph(wxRichTextParagraph* from, wxRichTextParagraph* to, wxRichTextObject* obj)
}
/// Draw the item
-bool wxRichTextParagraphLayoutBox::Draw(wxDC& dc, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
+bool wxRichTextParagraphLayoutBox::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
{
if (!IsShown())
return true;
wxRect thisRect(GetPosition(), GetCachedSize());
+ wxRichTextAttr attr(GetAttributes());
+ context.ApplyVirtualAttributes(attr, this);
+
int flags = style;
if (selection.IsValid() && GetParentContainer() != this && selection.WithinSelection(GetRange().GetStart(), GetParentContainer()))
flags |= wxRICHTEXT_DRAW_SELECTED;
int theseFlags = flags;
if (!GetParent())
theseFlags &= ~wxRICHTEXT_DRAW_GUIDELINES;
- DrawBoxAttributes(dc, GetBuffer(), GetAttributes(), thisRect, theseFlags);
+ DrawBoxAttributes(dc, GetBuffer(), attr, thisRect, theseFlags);
- DrawFloats(dc, range, selection, rect, descent, style);
+ DrawFloats(dc, context, range, selection, rect, descent, style);
wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
while (node)
{
// Skip
}
else
- child->Draw(dc, childRange, selection, rect, descent, style);
+ child->Draw(dc, context, childRange, selection, rect, descent, style);
}
node = node->GetNext();
}
/// Lay the item out
-bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, const wxRect& rect, const wxRect& parentRect, int style)
+bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, wxRichTextDrawingContext& context, const wxRect& rect, const wxRect& parentRect, int style)
{
SetPosition(rect.GetPosition());
wxRect availableSpace;
bool formatRect = (style & wxRICHTEXT_LAYOUT_SPECIFIED_RECT) == wxRICHTEXT_LAYOUT_SPECIFIED_RECT;
+ wxRichTextAttr attr(GetAttributes());
+ context.ApplyVirtualAttributes(attr, this);
+
// If only laying out a specific area, the passed rect has a different meaning:
// the visible part of the buffer. This is used in wxRichTextCtrl::OnSize,
// so that during a size, only the visible part will be relaid out, or
if (formatRect)
{
wxRect rect2(0, 0, rect.width, rect.height);
- availableSpace = GetAvailableContentArea(dc, rect2);
+ availableSpace = GetAvailableContentArea(dc, context, rect2);
// Invalidate the part of the buffer from the first visible line
// to the end. If other parts of the buffer are currently invalid,
}
else
{
- availableSpace = GetAvailableContentArea(dc, rect);
+ availableSpace = GetAvailableContentArea(dc, context, rect);
}
+ // Fix the width if we're at the top level
+ if (!GetParent())
+ attr.GetTextBoxAttr().GetWidth().SetValue(rect.GetWidth(), wxTEXT_ATTR_UNITS_PIXELS);
+
int leftMargin, rightMargin, topMargin, bottomMargin;
- wxRichTextObject::GetTotalMargin(dc, GetBuffer(), GetAttributes(), leftMargin, rightMargin,
+ wxRichTextObject::GetTotalMargin(dc, GetBuffer(), attr, leftMargin, rightMargin,
topMargin, bottomMargin);
int maxWidth = 0;
int maxMinWidth = 0;
// If we have vertical alignment, we must recalculate everything.
- bool hasVerticalAlignment = (GetAttributes().GetTextBoxAttr().HasVerticalAlignment() &&
- (GetAttributes().GetTextBoxAttr().GetVerticalAlignment() > wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_TOP));
+ bool hasVerticalAlignment = (attr.GetTextBoxAttr().HasVerticalAlignment() &&
+ (attr.GetTextBoxAttr().GetVerticalAlignment() > wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_TOP));
wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
{
// 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->LayoutToBestSize(dc, GetBuffer(),
- GetAttributes(), child->GetAttributes(), availableSpace, rect, style&~wxRICHTEXT_LAYOUT_SPECIFIED_RECT);
+ child->LayoutToBestSize(dc, context, GetBuffer(),
+ attr, child->GetAttributes(), availableSpace, rect, style&~wxRICHTEXT_LAYOUT_SPECIFIED_RECT);
// Layout must set the cached size
availableSpace.y += child->GetCachedSize().y;
{
// 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->LayoutToBestSize(dc, GetBuffer(),
- GetAttributes(), child->GetAttributes(), availableSpace, rect, style&~wxRICHTEXT_LAYOUT_SPECIFIED_RECT);
+ child->LayoutToBestSize(dc, context, GetBuffer(),
+ attr, child->GetAttributes(), availableSpace, rect, style&~wxRICHTEXT_LAYOUT_SPECIFIED_RECT);
//child->Layout(dc, availableChildRect, style);
}
else
maxHeight = 0; // topMargin + bottomMargin;
- if (GetAttributes().GetTextBoxAttr().GetSize().GetWidth().IsValid())
+ // Check the bottom edge of any floating object
+ if (GetFloatCollector() && GetFloatCollector()->HasFloats())
+ {
+ int bottom = GetFloatCollector()->GetLastRectBottom();
+ if (bottom > maxHeight)
+ maxHeight = bottom;
+ }
+
+ if (attr.GetTextBoxAttr().GetSize().GetWidth().IsValid())
{
- wxRect r = AdjustAvailableSpace(dc, GetBuffer(), wxRichTextAttr() /* not used */, GetAttributes(), parentRect, parentRect);
+ wxRect r = AdjustAvailableSpace(dc, GetBuffer(), wxRichTextAttr() /* not used */, attr, parentRect, parentRect);
int w = r.GetWidth();
// Convert external to content rect
maxWidth = wxMax(maxWidth, w);
maxMaxWidth = wxMax(maxMaxWidth, w);
}
+ else
+ {
+ // TODO: Make sure the layout box's position reflects
+ // the position of the children, but without
+ // breaking layout of a box within a paragraph.
+ }
// TODO: (also in para layout) should set the
// object's size to an absolute one if specified,
{
wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect;
contentRect = wxRect(wxPoint(0, 0), wxSize(maxWidth, maxHeight));
- GetBoxRects(dc, GetBuffer(), GetAttributes(), marginRect, borderRect, contentRect, paddingRect, outlineRect);
+ GetBoxRects(dc, GetBuffer(), attr, marginRect, borderRect, contentRect, paddingRect, outlineRect);
SetCachedSize(marginRect.GetSize());
}
{
wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect;
contentRect = wxRect(wxPoint(0, 0), wxSize(maxMaxWidth, maxHeight)); // Actually max height is a lie, we can't know it
- GetBoxRects(dc, GetBuffer(), GetAttributes(), marginRect, borderRect, contentRect, paddingRect, outlineRect);
+ GetBoxRects(dc, GetBuffer(), attr, marginRect, borderRect, contentRect, paddingRect, outlineRect);
SetMaxSize(marginRect.GetSize());
}
{
wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect;
contentRect = wxRect(wxPoint(0, 0), wxSize(maxMinWidth, maxHeight)); // Actually max height is a lie, we can't know it
- GetBoxRects(dc, GetBuffer(), GetAttributes(), marginRect, borderRect, contentRect, paddingRect, outlineRect);
+ GetBoxRects(dc, GetBuffer(), attr, marginRect, borderRect, contentRect, paddingRect, outlineRect);
SetMinSize(marginRect.GetSize());
}
- if (GetAttributes().GetTextBoxAttr().HasVerticalAlignment() &&
- (GetAttributes().GetTextBoxAttr().GetVerticalAlignment() > wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_TOP))
+ if (attr.GetTextBoxAttr().HasVerticalAlignment() &&
+ (attr.GetTextBoxAttr().GetVerticalAlignment() > wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_TOP))
{
int yOffset = 0;
int leftOverSpace = availableSpace.height - topMargin - bottomMargin - maxHeight;
if (leftOverSpace > 0)
{
- if (GetAttributes().GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_CENTRE)
+ if (attr.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_CENTRE)
{
yOffset = (leftOverSpace/2);
}
- else if (GetAttributes().GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_BOTTOM)
+ else if (attr.GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_BOTTOM)
{
yOffset = leftOverSpace;
}
}
/// Get/set the size for the given range.
-bool wxRichTextParagraphLayoutBox::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position, wxArrayInt* WXUNUSED(partialExtents)) const
+bool wxRichTextParagraphLayoutBox::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, wxPoint position, wxArrayInt* WXUNUSED(partialExtents)) const
{
wxSize sz;
wxSize childSize;
int childDescent = 0;
- child->GetRangeSize(rangeToFind, childSize, childDescent, dc, flags, position);
+ child->GetRangeSize(rangeToFind, childSize, childDescent, dc, context, flags, position);
descent = wxMax(childDescent, descent);
wxRichTextAttr* cStyle = & defaultCharStyle;
wxRichTextParagraph* para = new wxRichTextParagraph(text, this, pStyle, cStyle);
+ para->GetAttributes().GetTextBoxAttr().Reset();
AppendChild(para);
size_t len = text.length();
wxString line;
wxRichTextParagraph* para = new wxRichTextParagraph(wxEmptyString, this, pStyle, cStyle);
+ para->GetAttributes().GetTextBoxAttr().Reset();
AppendChild(para);
plainText->SetText(line);
para = new wxRichTextParagraph(wxEmptyString, this, pStyle, cStyle);
+ para->GetAttributes().GetTextBoxAttr().Reset();
AppendChild(para);
wxRichTextAttr* cStyle = & defaultCharStyle;
wxRichTextParagraph* para = new wxRichTextParagraph(this, pStyle);
+ para->GetAttributes().GetTextBoxAttr().Reset();
AppendChild(para);
para->AppendChild(new wxRichTextImage(image, this, cStyle));
{
// Start with the base style
style = GetAttributes();
+ style.GetTextBoxAttr().Reset();
// Apply the paragraph style
wxRichTextApplyStyle(style, obj->GetAttributes());
if (childRange.GetLength() == 0 && GetRange().GetLength() == 1)
childRange.SetEnd(childRange.GetEnd()+1);
- if (!childRange.IsOutside(range) && child->IsKindOf(CLASSINFO(wxRichTextPlainText)))
+ if (!childRange.IsOutside(range) && wxDynamicCast(child, wxRichTextPlainText))
{
foundCount ++;
wxRichTextAttr textAttr = para->GetCombinedAttributes(child->GetAttributes());
- if (wxTextAttrEqPartial(textAttr, style))
+ if (textAttr.EqPartial(style, false /* strong test - attributes must be valid in both objects */))
matchingCount ++;
}
wxRichTextApplyStyle(textAttr, para->GetAttributes());
foundCount ++;
- if (wxTextAttrEqPartial(textAttr, style))
+ if (textAttr.EqPartial(style, false /* strong test */))
matchingCount ++;
}
}
return foundCount == matchingCount && foundCount != 0;
}
+void wxRichTextParagraphLayoutBox::PrepareContent(wxRichTextParagraphLayoutBox& container)
+{
+ wxRichTextBuffer* buffer = GetBuffer();
+ if (buffer && buffer->GetRichTextCtrl())
+ buffer->GetRichTextCtrl()->PrepareContent(container);
+}
+
/// Set character or paragraph properties
bool wxRichTextParagraphLayoutBox::SetProperties(const wxRichTextRange& range, const wxRichTextProperties& properties, int flags)
{
AddParagraph(wxEmptyString);
+ PrepareContent(*this);
+
InvalidateHierarchy(wxRICHTEXT_ALL);
}
wxRichTextApplyStyle(newPara->GetAttributes(), listStyle);
// Now we need to do numbering
- if (renumber)
+ // Preserve the existing list item continuation bullet style, if any
+ if (para->GetAttributes().HasBulletStyle() && (para->GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_CONTINUATION))
+ newPara->GetAttributes().SetBulletStyle(newPara->GetAttributes().GetBulletStyle()|wxTEXT_ATTR_BULLET_STYLE_CONTINUATION);
+ else
{
- newPara->GetAttributes().SetBulletNumber(n);
- }
+ // Now we need to do numbering
+ if (renumber)
+ {
+ newPara->GetAttributes().SetBulletNumber(n);
+ }
- n ++;
+ n ++;
+ }
}
else if (!newPara->GetAttributes().GetListStyleName().IsEmpty())
{
wxRichTextAttr listStyle(defToUse->GetCombinedStyleForLevel(thisLevel, styleSheet));
wxRichTextApplyStyle(newPara->GetAttributes(), listStyle);
+ // Preserve the existing list item continuation bullet style, if any
+ if (para->GetAttributes().HasBulletStyle() && (para->GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_CONTINUATION))
+ newPara->GetAttributes().SetBulletStyle(newPara->GetAttributes().GetBulletStyle()|wxTEXT_ATTR_BULLET_STYLE_CONTINUATION);
+
// OK, we've (re)applied the style, now let's get the numbering right.
if (currentLevel == -1)
}
else
{
- levels[currentLevel] ++;
+ if (!(para->GetAttributes().HasBulletStyle() && (para->GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_CONTINUATION)))
+ levels[currentLevel] ++;
}
newPara->GetAttributes().SetBulletNumber(levels[currentLevel]);
/// position of the paragraph that it had to start looking from.
bool wxRichTextParagraphLayoutBox::FindNextParagraphNumber(wxRichTextParagraph* previousParagraph, wxRichTextAttr& attr) const
{
+ // Search for a paragraph that isn't a continuation paragraph (no bullet)
+ while (previousParagraph && previousParagraph->GetAttributes().HasBulletStyle() && previousParagraph->GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_CONTINUATION)
+ {
+ wxRichTextObjectList::compatibility_iterator node = ((wxRichTextCompositeObject*) previousParagraph->GetParent())->GetChildren().Find(previousParagraph);
+ if (node)
+ {
+ node = node->GetPrevious();
+ if (node)
+ previousParagraph = wxDynamicCast(node->GetData(), wxRichTextParagraph);
+ else
+ previousParagraph = NULL;
+ }
+ else
+ previousParagraph = NULL;
+ }
+
if (!previousParagraph->GetAttributes().HasFlag(wxTEXT_ATTR_BULLET_STYLE) || previousParagraph->GetAttributes().GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_NONE)
return false;
}
/// Draw the item
-bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int WXUNUSED(descent), int style)
+bool wxRichTextParagraph::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int WXUNUSED(descent), int style)
{
if (!IsShown())
return true;
// for all paragraphs). But generally box attributes are likely to be
// different for different objects.
wxRect paraRect = GetRect();
- DrawBoxAttributes(dc, GetBuffer(), GetAttributes(), paraRect);
-
wxRichTextAttr attr = GetCombinedAttributes();
+ context.ApplyVirtualAttributes(attr, this);
+
+ DrawBoxAttributes(dc, GetBuffer(), attr, paraRect);
// Draw the bullet, if any
- if (attr.GetBulletStyle() != wxTEXT_ATTR_BULLET_STYLE_NONE)
+ if ((attr.GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_NONE) == 0 && (attr.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_CONTINUATION) == 0)
{
if (attr.GetLeftSubIndent() != 0)
{
int spaceBeforePara = ConvertTenthsMMToPixels(dc, attr.GetParagraphSpacingBefore());
int leftIndent = ConvertTenthsMMToPixels(dc, attr.GetLeftIndent());
- wxRichTextAttr bulletAttr(GetCombinedAttributes());
+ wxRichTextAttr bulletAttr(attr);
// Combine with the font of the first piece of content, if one is specified
if (GetChildren().GetCount() > 0)
#endif
{
int descent = 0;
- child->GetRangeSize(objectRange, objectSize, descent, dc, wxRICHTEXT_UNFORMATTED, objectPosition);
+ child->GetRangeSize(objectRange, objectSize, descent, dc, context, 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, selection, childRect, maxDescent, style);
+ child->Draw(dc, context, objectRange, selection, childRect, maxDescent, style);
objectPosition.x += objectSize.x;
i ++;
}
/// Lay the item out
-bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, const wxRect& parentRect, int style)
+bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, const wxRect& rect, const wxRect& parentRect, int style)
{
// Deal with floating objects firstly before the normal layout
wxRichTextBuffer* buffer = GetBuffer();
wxASSERT(buffer);
wxRichTextFloatCollector* collector = GetContainer()->GetFloatCollector();
wxASSERT(collector);
- LayoutFloat(dc, rect, style, collector);
+ LayoutFloat(dc, context, rect, style, collector);
wxRichTextAttr attr = GetCombinedAttributes();
+ context.ApplyVirtualAttributes(attr, this);
// ClearLines();
int paraDescent = 0;
// This calculates the partial text extents
- GetRangeSize(GetRange(), paraSize, paraDescent, dc, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_CACHE_SIZE, rect.GetPosition(), & partialExtents);
+ GetRangeSize(GetRange(), paraSize, paraDescent, dc, context, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_CACHE_SIZE, rect.GetPosition(), & partialExtents);
#else
node = m_children.GetFirst();
while (node)
wxRichTextObject* child = node->GetData();
//child->SetCachedSize(wxDefaultSize);
- child->Layout(dc, rect, style);
+ child->Layout(dc, context, rect, style);
node = node->GetNext();
}
-
#endif
// Split up lines
// 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, buffer,
- GetAttributes(), child->GetAttributes(), availableRect, parentRect, style);
+ child->LayoutToBestSize(dc, context, buffer,
+ attr, child->GetAttributes(), availableRect, parentRect, style);
if (oldSize != child->GetCachedSize())
{
partialExtents.Clear();
// Recalculate the partial text extents since the child object changed size
- GetRangeSize(GetRange(), paraSize, paraDescent, dc, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_CACHE_SIZE, wxPoint(0,0), & partialExtents);
+ GetRangeSize(GetRange(), paraSize, paraDescent, dc, context, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_CACHE_SIZE, wxPoint(0,0), & partialExtents);
}
}
{
#if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS
// Get height only, then the width using the partial extents
- GetRangeSize(wxRichTextRange(lastEndPos+1, lastPosToUse), childSize, childDescent, dc, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_HEIGHT_ONLY);
+ GetRangeSize(wxRichTextRange(lastEndPos+1, lastPosToUse), childSize, childDescent, dc, context, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_HEIGHT_ONLY);
childSize.x = wxRichTextGetRangeWidth(*this, wxRichTextRange(lastEndPos+1, lastPosToUse), partialExtents);
#else
- GetRangeSize(wxRichTextRange(lastEndPos+1, lastPosToUse), childSize, childDescent, dc, wxRICHTEXT_UNFORMATTED, rect.GetPosition());
+ GetRangeSize(wxRichTextRange(lastEndPos+1, lastPosToUse), childSize, childDescent, dc, context, wxRICHTEXT_UNFORMATTED, rect.GetPosition());
#endif
}
wxRect oldAvailableRect = availableRect;
// Available width depends on the floating objects and the line height.
- // Note: the floating objects may be placed vertically along the two side of
+ // Note: the floating objects may be placed vertically along the two sides of
// buffer, so we may have different available line widths with different
// [startY, endY]. So, we can't determine how wide the available
// space is until we know the exact line height.
- lineDescent = wxMax(childDescent, maxDescent);
- lineAscent = wxMax(childSize.y-childDescent, maxAscent);
- lineHeight = lineDescent + lineAscent;
+ if (childDescent == 0)
+ {
+ lineHeight = wxMax(lineHeight, childSize.y);
+ lineDescent = maxDescent;
+ lineAscent = maxAscent;
+ }
+ else
+ {
+ lineDescent = wxMax(childDescent, maxDescent);
+ lineAscent = wxMax(childSize.y-childDescent, maxAscent);
+ }
+ lineHeight = wxMax(lineHeight, (lineDescent + lineAscent));
wxRect floatAvailableRect = collector->GetAvailableRect(rect.y + currentPosition.y, rect.y + currentPosition.y + lineHeight);
// Adjust availableRect to the space that is available when taking floating objects into account.
{
wxSize oldSize = child->GetCachedSize();
- //child->SetCachedSize(wxDefaultSize);
// 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, buffer,
- GetAttributes(), child->GetAttributes(), availableRect, parentRect, style);
+ child->LayoutToBestSize(dc, context, buffer,
+ attr, child->GetAttributes(), availableRect, parentRect, style);
childSize = child->GetCachedSize();
childDescent = child->GetDescent();
- //child->SetPosition(availableRect.GetPosition());
if (oldSize != child->GetCachedSize())
{
partialExtents.Clear();
// Recalculate the partial text extents since the child object changed size
- GetRangeSize(GetRange(), paraSize, paraDescent, dc, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_CACHE_SIZE, wxPoint(0,0), & partialExtents);
+ GetRangeSize(GetRange(), paraSize, paraDescent, dc, context, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_CACHE_SIZE, wxPoint(0,0), & partialExtents);
}
// Go around the loop finding the available rect for the given floating objects
}
while (doLoop);
+ if (child->IsTopLevel())
+ {
+ // We can move it to the correct position at this point
+ // TODO: probably need to add margin
+ child->Move(GetPosition() + wxPoint(currentWidth + (wxMax(leftIndent, leftIndent + leftSubIndent)), currentPosition.y));
+ }
+
// Cases:
// 1) There was a line break BEFORE the natural break
// 2) There was a line break AFTER the natural break
)
{
- if (child->IsTopLevel())
- {
- // We can move it to the correct position at this point
- child->Move(GetPosition() + wxPoint(currentWidth, currentPosition.y));
- }
-
long wrapPosition = 0;
if ((childSize.x + currentWidth <= availableRect.width) && !node->GetNext() && !lineBreakInThisObject)
wrapPosition = child->GetRange().GetEnd();
// Note: one object must contains only one wxTextAtrr, so the line height will not
// change inside one object. Thus, we can pass the remain line width to the
// FindWrapPosition function.
- if (!FindWrapPosition(wxRichTextRange(lastCompletedEndPos+1, child->GetRange().GetEnd()), dc, availableRect.width, wrapPosition, & partialExtents))
+ if (!FindWrapPosition(wxRichTextRange(lastCompletedEndPos+1, child->GetRange().GetEnd()), dc, context, availableRect.width, wrapPosition, & partialExtents))
{
// If the function failed, just cut it off at the end of this child.
wrapPosition = child->GetRange().GetEnd();
// Line end position shouldn't be the same as the end, or greater.
if (wrapPosition >= GetRange().GetEnd())
- wrapPosition = GetRange().GetEnd()-1;
+ wrapPosition = wxMax(0, GetRange().GetEnd()-1);
// wxLogDebug(wxT("Split at %ld"), wrapPosition);
wxSize actualSize;
wxRichTextRange actualRange(lastCompletedEndPos+1, wrapPosition);
- /// Use previous descent, not the wrapping descent we just found, since this may be too big
- /// for the fragment we're about to add.
- childDescent = maxDescent;
+ childDescent = 0;
#if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS
if (!child->IsEmpty())
{
// Get height only, then the width using the partial extents
- GetRangeSize(actualRange, actualSize, childDescent, dc, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_HEIGHT_ONLY);
+ GetRangeSize(actualRange, actualSize, childDescent, dc, context, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_HEIGHT_ONLY);
actualSize.x = wxRichTextGetRangeWidth(*this, actualRange, partialExtents);
}
else
#endif
- GetRangeSize(actualRange, actualSize, childDescent, dc, wxRICHTEXT_UNFORMATTED);
+ GetRangeSize(actualRange, actualSize, childDescent, dc, context, wxRICHTEXT_UNFORMATTED);
currentWidth = actualSize.x;
- maxDescent = wxMax(childDescent, maxDescent);
- maxAscent = wxMax(actualSize.y-childDescent, maxAscent);
- lineHeight = maxDescent + maxAscent;
+
+ // The descent for the whole line at this point, is the correct max descent
+ maxDescent = childDescent;
+ // Maximum ascent
+ maxAscent = actualSize.y-childDescent;
+
+ // lineHeight is given by the height for the whole line, since it will
+ // take into account ascend/descend.
+ lineHeight = actualSize.y;
if (lineHeight == 0 && buffer)
{
lineCount ++;
- // TODO: account for zero-length objects, such as fields
+ // TODO: account for zero-length objects
// wxASSERT(wrapPosition > lastCompletedEndPos);
lastEndPos = wrapPosition;
{
// We still fit, so don't add a line, and keep going
currentWidth += childSize.x;
- maxDescent = wxMax(childDescent, maxDescent);
- maxAscent = wxMax(childSize.y-childDescent, maxAscent);
- lineHeight = maxDescent + maxAscent;
+
+ if (childDescent == 0)
+ {
+ // An object with a zero descend value wants to take up the whole
+ // height regardless of baseline
+ lineHeight = wxMax(lineHeight, childSize.y);
+ }
+ else
+ {
+ maxDescent = wxMax(childDescent, maxDescent);
+ maxAscent = wxMax(childSize.y-childDescent, maxAscent);
+ }
+
+ lineHeight = wxMax(lineHeight, (maxDescent + maxAscent));
maxWidth = wxMax(maxWidth, currentWidth+startOffset);
lastEndPos = child->GetRange().GetEnd();
{
wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect;
contentRect = wxRect(wxPoint(0, 0), wxSize(maxWidth, currentPosition.y + spaceAfterPara));
- GetBoxRects(dc, buffer, GetAttributes(), marginRect, borderRect, contentRect, paddingRect, outlineRect);
+ GetBoxRects(dc, buffer, attr, marginRect, borderRect, contentRect, paddingRect, outlineRect);
SetCachedSize(marginRect.GetSize());
}
{
wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect;
contentRect = wxRect(wxPoint(0, 0), wxSize(paraSize.x + wxMax(leftIndent, leftIndent + leftSubIndent) + rightIndent, currentPosition.y + spaceAfterPara));
- GetBoxRects(dc, buffer, GetAttributes(), marginRect, borderRect, contentRect, paddingRect, outlineRect);
+ GetBoxRects(dc, buffer, attr, marginRect, borderRect, contentRect, paddingRect, outlineRect);
SetMaxSize(marginRect.GetSize());
}
// If floating, ignore. We already laid out floats.
// Also ignore if empty object, except if we haven't got any
// size yet.
- if (!child->IsFloating() && child->GetRange().GetLength() != 0 && !child->IsKindOf(CLASSINFO(wxRichTextPlainText)))
+ if (!child->IsFloating() && child->GetRange().GetLength() != 0 && !wxDynamicCast(child, wxRichTextPlainText))
{
if (child->GetCachedSize().x > minWidth)
minWidth = child->GetMinSize().x;
wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect;
contentRect = wxRect(wxPoint(0, 0), wxSize(minWidth, currentPosition.y + spaceAfterPara));
- GetBoxRects(dc, buffer, GetAttributes(), marginRect, borderRect, contentRect, paddingRect, outlineRect);
+ GetBoxRects(dc, buffer, attr, marginRect, borderRect, contentRect, paddingRect, outlineRect);
SetMinSize(marginRect.GetSize());
}
-
#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
return;
wxPoint pos = line->GetPosition();
+ wxPoint originalPos = pos;
wxSize size = line->GetSize();
// centering, right-justification
- if (attr.HasAlignment() && GetAttributes().GetAlignment() == wxTEXT_ALIGNMENT_CENTRE)
+ if (attr.HasAlignment() && attr.GetAlignment() == wxTEXT_ALIGNMENT_CENTRE)
{
int rightIndent = ConvertTenthsMMToPixels(dc, attr.GetRightIndent());
pos.x = (rect.GetWidth() - rightIndent - size.x)/2 + pos.x;
line->SetPosition(pos);
}
- else if (attr.HasAlignment() && GetAttributes().GetAlignment() == wxTEXT_ALIGNMENT_RIGHT)
+ else if (attr.HasAlignment() && attr.GetAlignment() == wxTEXT_ALIGNMENT_RIGHT)
{
int rightIndent = ConvertTenthsMMToPixels(dc, attr.GetRightIndent());
pos.x = pos.x + rect.GetWidth() - size.x - rightIndent;
line->SetPosition(pos);
}
+
+ if (pos != originalPos)
+ {
+ wxPoint inc = pos - originalPos;
+
+ wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
+
+ while (node)
+ {
+ wxRichTextObject* child = node->GetData();
+ if (child->IsTopLevel() && !child->GetRange().IsOutside(line->GetAbsoluteRange()))
+ child->Move(child->GetPosition() + inc);
+
+ node = node->GetNext();
+ }
+ }
}
/// Insert text at the given position
/// 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, wxArrayInt* partialExtents) const
+bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, wxPoint position, wxArrayInt* partialExtents) const
{
if (!range.IsWithin(GetRange()))
return false;
if (flags & wxRICHTEXT_UNFORMATTED)
{
// Just use unformatted data, assume no line breaks
- // TODO: take into account line breaks
-
wxSize sz;
wxArrayInt childExtents;
else
p = NULL;
+ int maxDescent = 0;
+ int maxAscent = 0;
+ int maxLineHeight = 0;
+
wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
while (node)
{
-
wxRichTextObject* child = node->GetData();
if (!child->GetRange().IsOutside(range))
{
wxRichTextRange rangeToUse = range;
rangeToUse.LimitTo(child->GetRange());
-#if 0
- if (child->IsTopLevel())
- rangeToUse = child->GetOwnRange();
-#endif
int childDescent = 0;
- // At present wxRICHTEXT_HEIGHT_ONLY is only fast if we're already cached the size,
+ // At present wxRICHTEXT_HEIGHT_ONLY is only fast if we've already cached the size,
// but it's only going to be used after caching has taken place.
if ((flags & wxRICHTEXT_HEIGHT_ONLY) && child->GetCachedSize().y != 0)
{
childDescent = child->GetDescent();
childSize = child->GetCachedSize();
- sz.y = wxMax(sz.y, childSize.y);
+ if (childDescent == 0)
+ {
+ maxLineHeight = wxMax(maxLineHeight, childSize.y);
+ }
+ else
+ {
+ maxDescent = wxMax(maxDescent, childDescent);
+ maxAscent = wxMax(maxAscent, (childSize.y - childDescent));
+ }
+
+ maxLineHeight = wxMax(maxLineHeight, (maxAscent + maxDescent));
+
+ sz.y = wxMax(sz.y, maxLineHeight);
sz.x += childSize.x;
- descent = wxMax(descent, childDescent);
+ descent = maxDescent;
}
else if (child->IsTopLevel())
{
childDescent = child->GetDescent();
childSize = child->GetCachedSize();
- sz.y = wxMax(sz.y, childSize.y);
+ if (childDescent == 0)
+ {
+ maxLineHeight = wxMax(maxLineHeight, childSize.y);
+ }
+ else
+ {
+ maxDescent = wxMax(maxDescent, childDescent);
+ maxAscent = wxMax(maxAscent, (childSize.y - childDescent));
+ }
+
+ maxLineHeight = wxMax(maxLineHeight, (maxAscent + maxDescent));
+
+ sz.y = wxMax(sz.y, maxLineHeight);
sz.x += childSize.x;
- descent = wxMax(descent, childDescent);
+ descent = maxDescent;
+
+ // FIXME: this won't change the original values.
+ // Should we be calling GetRangeSize above instead of using cached values?
+#if 0
if ((flags & wxRICHTEXT_CACHE_SIZE) && (rangeToUse == child->GetRange()))
{
child->SetCachedSize(childSize);
child->SetDescent(childDescent);
}
+#endif
if (partialExtents)
{
partialExtents->Add(childSize.x + lastSize);
}
}
- else if (child->GetRangeSize(rangeToUse, childSize, childDescent, dc, flags, wxPoint(position.x + sz.x, position.y), p))
+ else if (child->GetRangeSize(rangeToUse, childSize, childDescent, dc, context, flags, wxPoint(position.x + sz.x, position.y), p))
{
- sz.y = wxMax(sz.y, childSize.y);
+ if (childDescent == 0)
+ {
+ maxLineHeight = wxMax(maxLineHeight, childSize.y);
+ }
+ else
+ {
+ maxDescent = wxMax(maxDescent, childDescent);
+ maxAscent = wxMax(maxAscent, (childSize.y - childDescent));
+ }
+
+ maxLineHeight = wxMax(maxLineHeight, (maxAscent + maxDescent));
+
+ sz.y = wxMax(sz.y, maxLineHeight);
sz.x += childSize.x;
- descent = wxMax(descent, childDescent);
+ descent = maxDescent;
if ((flags & wxRICHTEXT_CACHE_SIZE) && (rangeToUse == child->GetRange()))
{
wxRichTextRange lineRange = line->GetAbsoluteRange();
if (!lineRange.IsOutside(range))
{
- wxSize lineSize;
+ int maxDescent = 0;
+ int maxAscent = 0;
+ int maxLineHeight = 0;
+ int maxLineWidth = 0;
wxRichTextObjectList::compatibility_iterator node2 = m_children.GetFirst();
while (node2)
wxSize childSize;
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, context, flags, wxPoint(position.x + sz.x, position.y)))
{
- lineSize.y = wxMax(lineSize.y, childSize.y);
- lineSize.x += childSize.x;
+ if (childDescent == 0)
+ {
+ // Assume that if descent is zero, this child can occupy the full line height
+ // and does not need space for the line's maximum descent. So we influence
+ // the overall max line height only.
+ maxLineHeight = wxMax(maxLineHeight, childSize.y);
+ }
+ else
+ {
+ maxAscent = wxMax(maxAscent, (childSize.y - childDescent));
+ maxDescent = wxMax(maxAscent, childDescent);
+ }
+ maxLineHeight = wxMax(maxLineHeight, (maxAscent + maxDescent));
+ maxLineWidth += childSize.x;
}
- descent = wxMax(descent, childDescent);
}
node2 = node2->GetNext();
}
+ descent = wxMax(descent, maxDescent);
+
// Increase size by a line (TODO: paragraph spacing)
- sz.y += lineSize.y;
- sz.x = wxMax(sz.x, lineSize.x);
+ sz.y += maxLineHeight;
+ sz.x = wxMax(sz.x, maxLineWidth);
}
node = node->GetNext();
}
}
/// Finds the absolute position and row height for the given character position
-bool wxRichTextParagraph::FindPosition(wxDC& dc, long index, wxPoint& pt, int* height, bool forceLineStart)
+bool wxRichTextParagraph::FindPosition(wxDC& dc, wxRichTextDrawingContext& context, long index, wxPoint& pt, int* height, bool forceLineStart)
{
if (index == -1)
{
// then we can add this size to the line start position and
// paragraph start position to find the actual position.
- if (GetRangeSize(r, rangeSize, descent, dc, wxRICHTEXT_UNFORMATTED, line->GetPosition()+ GetPosition()))
+ if (GetRangeSize(r, rangeSize, descent, dc, context, wxRICHTEXT_UNFORMATTED, line->GetPosition()+ GetPosition()))
{
pt.x = line->GetPosition().x + GetPosition().x + rangeSize.x;
*height = line->GetSize().y;
/// Hit-testing: returns a flag indicating hit test details, plus
/// information about position
-int wxRichTextParagraph::HitTest(wxDC& dc, const wxPoint& pt, long& textPosition, wxRichTextObject** obj, wxRichTextObject** contextObj, int flags)
+int wxRichTextParagraph::HitTest(wxDC& dc, wxRichTextDrawingContext& context, const wxPoint& pt, long& textPosition, wxRichTextObject** obj, wxRichTextObject** contextObj, int flags)
{
if (!IsShown())
return wxRICHTEXT_HITTEST_NONE;
{
long tmpPos;
wxRichTextObject* tempObj, *tempContextObj;
- if (GetParent() && GetParent()->wxRichTextObject::HitTest(dc, pt, tmpPos, & tempObj, & tempContextObj, flags) == wxRICHTEXT_HITTEST_NONE)
+ if (GetParent() && GetParent()->wxRichTextObject::HitTest(dc, context, pt, tmpPos, & tempObj, & tempContextObj, flags) == wxRICHTEXT_HITTEST_NONE)
return wxRICHTEXT_HITTEST_NONE;
}
while (objNode)
{
wxRichTextObject* child = objNode->GetData();
- if (child->IsTopLevel() && ((flags & wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS) == 0))
+ // Don't recurse if we have wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS,
+ // and also, if this seems composite but actually is marked as atomic,
+ // don't recurse.
+ if (child->IsTopLevel() && ((flags & wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS) == 0) &&
+ (! (((flags & wxRICHTEXT_HITTEST_HONOUR_ATOMIC) != 0) && child->IsAtomic())))
{
{
- int hitTest = child->HitTest(dc, pt, textPosition, obj, contextObj);
+ int hitTest = child->HitTest(dc, context, pt, textPosition, obj, contextObj);
if (hitTest != wxRICHTEXT_HITTEST_NONE)
return hitTest;
}
int paraDescent;
// This calculates the partial text extents
- GetRangeSize(lineRange, paraSize, paraDescent, dc, wxRICHTEXT_UNFORMATTED, linePos, & partialExtents);
+ GetRangeSize(lineRange, paraSize, paraDescent, dc, context, wxRICHTEXT_UNFORMATTED, linePos, & partialExtents);
int lastX = linePos.x;
size_t i;
wxRichTextRange rangeToUse(lineRange.GetStart(), i);
- GetRangeSize(rangeToUse, childSize, descent, dc, wxRICHTEXT_UNFORMATTED, linePos);
+ GetRangeSize(rangeToUse, childSize, descent, dc, context, wxRICHTEXT_UNFORMATTED, linePos);
int nextX = childSize.x + linePos.x;
}
/// Find a suitable wrap position.
-bool wxRichTextParagraph::FindWrapPosition(const wxRichTextRange& range, wxDC& dc, int availableSpace, long& wrapPosition, wxArrayInt* partialExtents)
+bool wxRichTextParagraph::FindWrapPosition(const wxRichTextRange& range, wxDC& dc, wxRichTextDrawingContext& context, int availableSpace, long& wrapPosition, wxArrayInt* partialExtents)
{
if (range.GetLength() <= 0)
return false;
if (minPos == maxPos)
{
int descent = 0;
- GetRangeSize(wxRichTextRange(range.GetStart(), minPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
+ GetRangeSize(wxRichTextRange(range.GetStart(), minPos), sz, descent, dc, context, wxRICHTEXT_UNFORMATTED);
if (sz.x > availableSpace)
breakPosition = minPos - 1;
else if ((maxPos - minPos) == 1)
{
int descent = 0;
- GetRangeSize(wxRichTextRange(range.GetStart(), minPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
+ GetRangeSize(wxRichTextRange(range.GetStart(), minPos), sz, descent, dc, context, wxRICHTEXT_UNFORMATTED);
if (sz.x > availableSpace)
breakPosition = minPos - 1;
else
{
- GetRangeSize(wxRichTextRange(range.GetStart(), maxPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
+ GetRangeSize(wxRichTextRange(range.GetStart(), maxPos), sz, descent, dc, context, wxRICHTEXT_UNFORMATTED);
if (sz.x > availableSpace)
breakPosition = maxPos-1;
}
long nextPos = minPos + ((maxPos - minPos) / 2);
int descent = 0;
- GetRangeSize(wxRichTextRange(range.GetStart(), nextPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
+ GetRangeSize(wxRichTextRange(range.GetStart(), nextPos), sz, descent, dc, context, wxRICHTEXT_UNFORMATTED);
if (sz.x > availableSpace)
{
sm_defaultTabs.Clear();
}
-void wxRichTextParagraph::LayoutFloat(wxDC& dc, const wxRect& rect, int style, wxRichTextFloatCollector* floatCollector)
+void wxRichTextParagraph::LayoutFloat(wxDC& dc, wxRichTextDrawingContext& context, const wxRect& rect, int style, wxRichTextFloatCollector* floatCollector)
{
wxRichTextObjectList::compatibility_iterator node = GetChildren().GetFirst();
while (node)
{
wxSize size;
int descent, x = 0;
- anchored->GetRangeSize(anchored->GetRange(), size, descent, dc, style);
+ anchored->GetRangeSize(anchored->GetRange(), size, descent, dc, context, style);
int offsetY = 0;
if (anchored->GetAttributes().GetTextBoxAttr().GetTop().IsValid())
#define WIDTH_FOR_DEFAULT_TABS 50
/// Draw the item
-bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int WXUNUSED(style))
+bool wxRichTextPlainText::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int WXUNUSED(style))
{
wxRichTextParagraph* para = wxDynamicCast(GetParent(), wxRichTextParagraph);
wxASSERT (para != NULL);
wxRichTextAttr textAttr(para ? para->GetCombinedAttributes(GetAttributes(), false /* no box attributes */) : GetAttributes());
+ context.ApplyVirtualAttributes(textAttr, this);
// Let's make the assumption for now that for content in a paragraph, including
// text, we never have a discontinuous selection. So we only deal with a
wxString str = m_text;
wxString toRemove = wxRichTextLineBreakChar;
str.Replace(toRemove, wxT(" "));
- if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS))
+ if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & (wxTEXT_ATTR_EFFECT_CAPITALS|wxTEXT_ATTR_EFFECT_SMALL_CAPITALS)))
str.MakeUpper();
long len = range.GetLength();
int x, y;
if ( textFont.IsOk() )
{
+ if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SMALL_CAPITALS))
+ {
+ textFont.SetPointSize((int) (textFont.GetPointSize()*0.75));
+ wxCheckSetFont(dc, textFont);
+ charHeight = dc.GetCharHeight();
+ }
+
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;
+ if (textFont.IsUsingSizeInPixels())
+ {
+ double size = static_cast<double>(textFont.GetPixelSize().y) / wxSCRIPT_MUL_FACTOR;
+ textFont.SetPixelSize(wxSize(0, static_cast<int>(size)));
+ x = rect.x;
+ y = rect.y;
+ }
+ else
+ {
+ 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));
+ if (textFont.IsUsingSizeInPixels())
+ {
+ double size = static_cast<double>(textFont.GetPixelSize().y) / wxSCRIPT_MUL_FACTOR;
+ textFont.SetPixelSize(wxSize(0, 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));
+ }
+ else
+ {
+ 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 += w;
}
- return true;
+ return true;
}
/// Lay the item out
-bool wxRichTextPlainText::Layout(wxDC& dc, const wxRect& WXUNUSED(rect), const wxRect& WXUNUSED(parentRect), int WXUNUSED(style))
+bool wxRichTextPlainText::Layout(wxDC& dc, wxRichTextDrawingContext& context, const wxRect& WXUNUSED(rect), const wxRect& WXUNUSED(parentRect), int WXUNUSED(style))
{
// 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));
+ GetRangeSize(GetRange(), m_size, m_descent, dc, context, 0, wxPoint(0, 0));
m_maxSize = m_size;
// Eventually we want to have a reasonable estimate of minimum size.
m_minSize = wxSize(0, 0);
/// 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, wxArrayInt* partialExtents) const
+bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int WXUNUSED(flags), wxPoint position, wxArrayInt* partialExtents) const
{
if (!range.IsWithin(GetRange()))
return false;
int relativeX = position.x - GetParent()->GetPosition().x;
wxRichTextAttr textAttr(para ? para->GetCombinedAttributes(GetAttributes()) : GetAttributes());
+ context.ApplyVirtualAttributes(textAttr, (wxRichTextObject*) this);
// Always assume unformatted text, since at this level we have no knowledge
// of line breaks - and we don't need it, since we'll calculate size within
|| (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) );
+ if (textFont.IsUsingSizeInPixels())
+ {
+ double size = static_cast<double>(textFont.GetPixelSize().y) / wxSCRIPT_MUL_FACTOR;
+ textFont.SetPixelSize(wxSize(0, static_cast<int>(size)));
+ }
+ else
+ {
+ double size = static_cast<double>(textFont.GetPointSize()) / wxSCRIPT_MUL_FACTOR;
+ textFont.SetPointSize(static_cast<int>(size));
+ }
+ wxCheckSetFont(dc, textFont);
+ bScript = true;
+ }
+ else if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SMALL_CAPITALS))
+ {
+ wxFont textFont = font;
+ textFont.SetPointSize((int) (textFont.GetPointSize()*0.75));
wxCheckSetFont(dc, textFont);
bScript = true;
}
wxString stringChunk = str.Mid(startPos, (size_t) len);
- if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS))
+ if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & (wxTEXT_ATTR_EFFECT_CAPITALS|wxTEXT_ATTR_EFFECT_SMALL_CAPITALS)))
stringChunk.MakeUpper();
wxCoord w, h;
wxRichTextPlainText* newObject = new wxRichTextPlainText(secondPart);
newObject->SetAttributes(GetAttributes());
+ newObject->SetProperties(GetProperties());
newObject->SetRange(wxRichTextRange(pos, GetRange().GetEnd()));
GetRange().SetEnd(pos-1);
/// Returns true if this object can merge itself with the given one.
bool wxRichTextPlainText::CanMerge(wxRichTextObject* object) const
{
- return object->GetClassInfo() == CLASSINFO(wxRichTextPlainText) &&
- (m_text.empty() || wxTextAttrEq(GetAttributes(), object->GetAttributes()));
+ return object->GetClassInfo() == wxCLASSINFO(wxRichTextPlainText) &&
+ (m_text.empty() || (wxTextAttrEq(GetAttributes(), object->GetAttributes()) && m_properties == object->GetProperties()));
}
/// Returns true if this object merged itself with the given one.
IMPLEMENT_DYNAMIC_CLASS(wxRichTextBuffer, wxRichTextParagraphLayoutBox)
-wxList wxRichTextBuffer::sm_handlers;
-wxRichTextRenderer* wxRichTextBuffer::sm_renderer = NULL;
-int wxRichTextBuffer::sm_bulletRightMargin = 20;
-float wxRichTextBuffer::sm_bulletProportion = (float) 0.3;
+wxList wxRichTextBuffer::sm_handlers;
+wxList wxRichTextBuffer::sm_drawingHandlers;
+wxRichTextFieldTypeHashMap wxRichTextBuffer::sm_fieldTypes;
+wxRichTextRenderer* wxRichTextBuffer::sm_renderer = NULL;
+int wxRichTextBuffer::sm_bulletRightMargin = 20;
+float wxRichTextBuffer::sm_bulletProportion = (float) 0.3;
/// Initialisation
void wxRichTextBuffer::Init()
m_suppressUndo = 0;
m_handlerFlags = 0;
m_scale = 1.0;
+ m_dimensionScale = 1.0;
+ m_fontScale = 1.0;
+ SetMargins(4);
}
/// Initialisation
m_batchedCommand = NULL;
m_suppressUndo = obj.m_suppressUndo;
m_invalidRange = obj.m_invalidRange;
+ m_dimensionScale = obj.m_dimensionScale;
+ m_fontScale = obj.m_fontScale;
}
/// Push style sheet to top of stack
}
wxRichTextAttr attr(buffer->GetDefaultStyle());
+ // Don't include box attributes such as margins
+ attr.GetTextBoxAttr().Reset();
wxRichTextParagraph* newPara = new wxRichTextParagraph(wxEmptyString, this, & attr);
action->GetNewParagraphs().AppendChild(newPara);
action->SetPosition(pos);
- // Use the default character style
// Use the default character style
if (!buffer->GetDefaultStyle().IsDefault() && newPara->GetChildren().GetFirst())
{
// Check whether the default style merely reflects the paragraph/basic style,
// in which case don't apply it.
wxRichTextAttr defaultStyle(buffer->GetDefaultStyle());
+ defaultStyle.GetTextBoxAttr().Reset();
wxRichTextAttr toApply;
if (para)
{
wxRichTextAttr attr(buffer->GetDefaultStyle());
+ // Don't include box attributes such as margins
+ attr.GetTextBoxAttr().Reset();
+
wxRichTextParagraph* newPara = new wxRichTextParagraph(this, & attr);
if (p)
newPara->SetAttributes(*p);
wxRichTextAttr attr(buffer->GetDefaultStyle());
+ // Don't include box attributes such as margins
+ attr.GetTextBoxAttr().Reset();
+
wxRichTextParagraph* newPara = new wxRichTextParagraph(this, & attr);
if (p)
newPara->SetAttributes(*p);
return obj;
}
+wxRichTextField* wxRichTextParagraphLayoutBox::InsertFieldWithUndo(wxRichTextBuffer* buffer, long pos, const wxString& fieldType,
+ const wxRichTextProperties& properties,
+ wxRichTextCtrl* ctrl, int flags,
+ const wxRichTextAttr& textAttr)
+{
+ wxRichTextAction* action = new wxRichTextAction(NULL, _("Insert Field"), wxRICHTEXT_INSERT, buffer, this, ctrl, false);
+
+ wxRichTextAttr* p = NULL;
+ wxRichTextAttr paraAttr;
+ if (flags & wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE)
+ {
+ paraAttr = GetStyleForNewParagraph(buffer, pos);
+ if (!paraAttr.IsDefault())
+ p = & paraAttr;
+ }
+
+ wxRichTextAttr attr(buffer->GetDefaultStyle());
+
+ // Don't include box attributes such as margins
+ attr.GetTextBoxAttr().Reset();
+
+ wxRichTextParagraph* newPara = new wxRichTextParagraph(this, & attr);
+ if (p)
+ newPara->SetAttributes(*p);
+
+ wxRichTextField* fieldObject = new wxRichTextField();
+ fieldObject->wxRichTextObject::SetProperties(properties);
+ fieldObject->SetFieldType(fieldType);
+ fieldObject->SetAttributes(textAttr);
+ newPara->AppendChild(fieldObject);
+ action->GetNewParagraphs().AppendChild(newPara);
+ action->GetNewParagraphs().UpdateRanges();
+ action->GetNewParagraphs().SetPartialParagraph(true);
+ action->SetPosition(pos);
+
+ // Set the range we'll need to delete in Undo
+ action->SetRange(wxRichTextRange(pos, pos));
+
+ buffer->SubmitAction(action);
+
+ wxRichTextField* obj = wxDynamicCast(GetLeafObjectAtPosition(pos), wxRichTextField);
+ return obj;
+}
+
/// Get the style that is appropriate for a new paragraph at this position.
/// If the previous paragraph has a paragraph style name, look up the next-paragraph
/// style.
/// Submit immediately, or delay according to whether collapsing is on
bool wxRichTextBuffer::SubmitAction(wxRichTextAction* action)
{
+ if (action && !action->GetNewParagraphs().IsEmpty())
+ PrepareContent(action->GetNewParagraphs());
+
if (BatchingUndo() && m_batchedCommand && !SuppressingUndo())
{
wxRichTextCommand* cmd = new wxRichTextCommand(action->GetName());
bool wxRichTextBuffer::BeginStyle(const wxRichTextAttr& style)
{
wxRichTextAttr newStyle(GetDefaultStyle());
+ newStyle.GetTextBoxAttr().Reset();
// Save the old default style
- m_attributeStack.Append((wxObject*) new wxRichTextAttr(GetDefaultStyle()));
+ m_attributeStack.Append((wxObject*) new wxRichTextAttr(newStyle));
wxRichTextApplyStyle(newStyle, style);
newStyle.SetFlags(style.GetFlags()|newStyle.GetFlags());
/// Hit-testing: returns a flag indicating hit test details, plus
/// information about position
-int wxRichTextBuffer::HitTest(wxDC& dc, const wxPoint& pt, long& textPosition, wxRichTextObject** obj, wxRichTextObject** contextObj, int flags)
+int wxRichTextBuffer::HitTest(wxDC& dc, wxRichTextDrawingContext& context, const wxPoint& pt, long& textPosition, wxRichTextObject** obj, wxRichTextObject** contextObj, int flags)
{
- int ret = wxRichTextParagraphLayoutBox::HitTest(dc, pt, textPosition, obj, contextObj, flags);
+ int ret = wxRichTextParagraphLayoutBox::HitTest(dc, context, pt, textPosition, obj, contextObj, flags);
if (ret != wxRICHTEXT_HITTEST_NONE)
{
return ret;
}
}
+void wxRichTextBuffer::SetFontScale(double fontScale)
+{
+ m_fontScale = fontScale;
+ m_fontTable.SetFontScale(fontScale);
+}
+
+void wxRichTextBuffer::SetDimensionScale(double dimScale)
+{
+ m_dimensionScale = dimScale;
+}
+
bool wxRichTextStdRenderer::DrawStandardBullet(wxRichTextParagraph* paragraph, wxDC& dc, const wxRichTextAttr& bulletAttr, const wxRect& rect)
{
if (bulletAttr.GetTextColour().IsOk())
if ((attr.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_SYMBOL) && !attr.GetBulletFont().IsEmpty() && attr.HasFont())
{
wxRichTextAttr fontAttr;
- fontAttr.SetFontSize(attr.GetFontSize());
+ if (attr.HasFontPixelSize())
+ fontAttr.SetFontPixelSize(attr.GetFontSize());
+ else
+ fontAttr.SetFontPointSize(attr.GetFontSize());
fontAttr.SetFontStyle(attr.GetFontStyle());
fontAttr.SetFontWeight(attr.GetFontWeight());
fontAttr.SetFontUnderlined(attr.GetFontUnderlined());
}
/// Draw the item
-bool wxRichTextBox::Draw(wxDC& dc, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
+bool wxRichTextBox::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
{
if (!IsShown())
return true;
// so we can apply commands (properties, delete, ...) to objects such as text boxes and images.
// Ultimately we would like to be able to interactively resize an active object
// using drag handles.
- return wxRichTextParagraphLayoutBox::Draw(dc, range, selection, rect, descent, style);
+ return wxRichTextParagraphLayoutBox::Draw(dc, context, range, selection, rect, descent, style);
}
/// Copy
return false;
}
-IMPLEMENT_DYNAMIC_CLASS(wxRichTextCell, wxRichTextBox)
+/*!
+ * wxRichTextField
+ */
-wxRichTextCell::wxRichTextCell(wxRichTextObject* parent):
- wxRichTextBox(parent)
+IMPLEMENT_DYNAMIC_CLASS(wxRichTextField, wxRichTextParagraphLayoutBox)
+
+wxRichTextField::wxRichTextField(const wxString& fieldType, wxRichTextObject* parent):
+ wxRichTextParagraphLayoutBox(parent)
{
+ SetFieldType(fieldType);
}
/// Draw the item
-bool wxRichTextCell::Draw(wxDC& dc, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
+bool wxRichTextField::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
+{
+ if (!IsShown())
+ return true;
+
+ wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+ if (fieldType && fieldType->Draw(this, dc, context, range, selection, rect, descent, style))
+ return true;
+
+ // Fallback; but don't draw guidelines.
+ style &= ~wxRICHTEXT_DRAW_GUIDELINES;
+ return wxRichTextParagraphLayoutBox::Draw(dc, context, range, selection, rect, descent, style);
+}
+
+bool wxRichTextField::Layout(wxDC& dc, wxRichTextDrawingContext& context, const wxRect& rect, const wxRect& parentRect, int style)
+{
+ wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+ if (fieldType && fieldType->Layout(this, dc, context, rect, parentRect, style))
+ return true;
+
+ // Fallback
+ return wxRichTextParagraphLayoutBox::Layout(dc, context, rect, parentRect, style);
+}
+
+bool wxRichTextField::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, wxPoint position, wxArrayInt* partialExtents) const
+{
+ wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+ if (fieldType)
+ return fieldType->GetRangeSize((wxRichTextField*) this, range, size, descent, dc, context, flags, position, partialExtents);
+
+ return wxRichTextParagraphLayoutBox::GetRangeSize(range, size, descent, dc, context, flags, position, partialExtents);
+}
+
+/// Calculate range
+void wxRichTextField::CalculateRange(long start, long& end)
{
- return wxRichTextBox::Draw(dc, range, selection, rect, descent, style);
+ if (IsTopLevel())
+ wxRichTextParagraphLayoutBox::CalculateRange(start, end);
+ else
+ wxRichTextObject::CalculateRange(start, end);
}
/// Copy
-void wxRichTextCell::Copy(const wxRichTextCell& obj)
+void wxRichTextField::Copy(const wxRichTextField& obj)
{
- wxRichTextBox::Copy(obj);
+ wxRichTextParagraphLayoutBox::Copy(obj);
+
+ UpdateField(GetBuffer());
}
// Edit properties via a GUI
-bool wxRichTextCell::EditProperties(wxWindow* parent, wxRichTextBuffer* buffer)
+bool wxRichTextField::EditProperties(wxWindow* parent, wxRichTextBuffer* buffer)
{
- // We need to gather common attributes for all selected cells.
+ wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+ if (fieldType)
+ return fieldType->EditProperties(this, parent, buffer);
- wxRichTextTable* table = wxDynamicCast(GetParent(), wxRichTextTable);
- bool multipleCells = false;
- wxRichTextAttr attr;
+ return false;
+}
- if (table && buffer && buffer->GetRichTextCtrl() && buffer->GetRichTextCtrl()->GetSelection().IsValid() &&
- buffer->GetRichTextCtrl()->GetSelection().GetContainer() == GetParent())
- {
- wxRichTextAttr clashingAttr, absentAttr;
- const wxRichTextSelection& sel = buffer->GetRichTextCtrl()->GetSelection();
- size_t i;
- int selectedCellCount = 0;
- for (i = 0; i < sel.GetCount(); i++)
- {
- const wxRichTextRange& range = sel[i];
- wxRichTextCell* cell = table->GetCell(range.GetStart());
- if (cell)
- {
- wxRichTextAttr cellStyle = cell->GetAttributes();
+bool wxRichTextField::CanEditProperties() const
+{
+ wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+ if (fieldType)
+ return fieldType->CanEditProperties((wxRichTextField*) this);
- CollectStyle(attr, cellStyle, clashingAttr, absentAttr);
+ return false;
+}
- selectedCellCount ++;
- }
- }
- multipleCells = selectedCellCount > 1;
- }
- else
- {
- attr = GetAttributes();
- }
+wxString wxRichTextField::GetPropertiesMenuLabel() const
+{
+ wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+ if (fieldType)
+ return fieldType->GetPropertiesMenuLabel((wxRichTextField*) this);
- wxString caption;
+ return wxEmptyString;
+}
+
+bool wxRichTextField::UpdateField(wxRichTextBuffer* buffer)
+{
+ wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+ if (fieldType)
+ return fieldType->UpdateField(buffer, (wxRichTextField*) this);
+
+ return false;
+}
+
+bool wxRichTextField::IsTopLevel() const
+{
+ wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+ if (fieldType)
+ return fieldType->IsTopLevel((wxRichTextField*) this);
+
+ return true;
+}
+
+IMPLEMENT_CLASS(wxRichTextFieldType, wxObject)
+
+IMPLEMENT_CLASS(wxRichTextFieldTypeStandard, wxRichTextFieldType)
+
+wxRichTextFieldTypeStandard::wxRichTextFieldTypeStandard(const wxString& name, const wxString& label, int displayStyle)
+{
+ Init();
+
+ SetName(name);
+ SetLabel(label);
+ SetDisplayStyle(displayStyle);
+}
+
+wxRichTextFieldTypeStandard::wxRichTextFieldTypeStandard(const wxString& name, const wxBitmap& bitmap, int displayStyle)
+{
+ Init();
+
+ SetName(name);
+ SetBitmap(bitmap);
+ SetDisplayStyle(displayStyle);
+}
+
+void wxRichTextFieldTypeStandard::Init()
+{
+ m_displayStyle = wxRICHTEXT_FIELD_STYLE_RECTANGLE;
+ m_font = wxFont(6, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
+ m_textColour = *wxWHITE;
+ m_borderColour = *wxBLACK;
+ m_backgroundColour = *wxBLACK;
+ m_verticalPadding = 1;
+ m_horizontalPadding = 3;
+ m_horizontalMargin = 2;
+ m_verticalMargin = 0;
+}
+
+void wxRichTextFieldTypeStandard::Copy(const wxRichTextFieldTypeStandard& field)
+{
+ wxRichTextFieldType::Copy(field);
+
+ m_label = field.m_label;
+ m_displayStyle = field.m_displayStyle;
+ m_font = field.m_font;
+ m_textColour = field.m_textColour;
+ m_borderColour = field.m_borderColour;
+ m_backgroundColour = field.m_backgroundColour;
+ m_verticalPadding = field.m_verticalPadding;
+ m_horizontalPadding = field.m_horizontalPadding;
+ m_horizontalMargin = field.m_horizontalMargin;
+ m_bitmap = field.m_bitmap;
+}
+
+bool wxRichTextFieldTypeStandard::Draw(wxRichTextField* obj, wxDC& dc, wxRichTextDrawingContext& WXUNUSED(context), const wxRichTextRange& WXUNUSED(range), const wxRichTextSelection& selection, const wxRect& rect, int descent, int WXUNUSED(style))
+{
+ if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_COMPOSITE)
+ return false; // USe default composite drawing
+ else // if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_RECTANGLE || m_displayStyle == wxRICHTEXT_FIELD_STYLE_NOBORDER)
+ {
+ int borderSize = 1;
+
+ wxPen borderPen(m_borderColour, 1, wxSOLID);
+ wxBrush backgroundBrush(m_backgroundColour);
+ wxColour textColour(m_textColour);
+
+ if (selection.WithinSelection(obj->GetRange().GetStart(), obj))
+ {
+ wxColour highlightColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT));
+ wxColour highlightTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
+
+ borderPen = wxPen(highlightTextColour, 1, wxSOLID);
+ backgroundBrush = wxBrush(highlightColour);
+
+ wxCheckSetBrush(dc, backgroundBrush);
+ wxCheckSetPen(dc, wxPen(highlightColour, 1, wxSOLID));
+ dc.DrawRectangle(rect);
+ }
+
+ if (m_displayStyle != wxRICHTEXT_FIELD_STYLE_NO_BORDER)
+ borderSize = 0;
+
+ // objectRect is the area where the content is drawn, after margins around it have been taken into account
+ wxRect objectRect = wxRect(wxPoint(rect.x + m_horizontalMargin, rect.y + wxMax(0, rect.height - descent - obj->GetCachedSize().y)),
+ wxSize(obj->GetCachedSize().x - 2*m_horizontalMargin - borderSize, obj->GetCachedSize().y));
+
+ // clientArea is where the text is actually written
+ wxRect clientArea = objectRect;
+
+ if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_RECTANGLE)
+ {
+ dc.SetPen(borderPen);
+ dc.SetBrush(backgroundBrush);
+ dc.DrawRoundedRectangle(objectRect, 4.0);
+ }
+ else if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_START_TAG)
+ {
+ int arrowLength = objectRect.height/2;
+ clientArea.width -= (arrowLength - m_horizontalPadding);
+
+ wxPoint pts[5];
+ pts[0].x = objectRect.x; pts[0].y = objectRect.y;
+ pts[1].x = objectRect.x + objectRect.width - arrowLength; pts[1].y = objectRect.y;
+ pts[2].x = objectRect.x + objectRect.width; pts[2].y = objectRect.y + (objectRect.height/2);
+ pts[3].x = objectRect.x + objectRect.width - arrowLength; pts[3].y = objectRect.y + objectRect.height;
+ pts[4].x = objectRect.x; pts[4].y = objectRect.y + objectRect.height;
+ dc.SetPen(borderPen);
+ dc.SetBrush(backgroundBrush);
+ dc.DrawPolygon(5, pts);
+ }
+ else if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_END_TAG)
+ {
+ int arrowLength = objectRect.height/2;
+ clientArea.width -= (arrowLength - m_horizontalPadding);
+ clientArea.x += (arrowLength - m_horizontalPadding);
+
+ wxPoint pts[5];
+ pts[0].x = objectRect.x + objectRect.width; pts[0].y = objectRect.y;
+ pts[1].x = objectRect.x + arrowLength; pts[1].y = objectRect.y;
+ pts[2].x = objectRect.x; pts[2].y = objectRect.y + (objectRect.height/2);
+ pts[3].x = objectRect.x + arrowLength; pts[3].y = objectRect.y + objectRect.height;
+ pts[4].x = objectRect.x + objectRect.width; pts[4].y = objectRect.y + objectRect.height;
+ dc.SetPen(borderPen);
+ dc.SetBrush(backgroundBrush);
+ dc.DrawPolygon(5, pts);
+ }
+
+ if (m_bitmap.IsOk())
+ {
+ int x = clientArea.x + (clientArea.width - m_bitmap.GetWidth())/2;
+ int y = clientArea.y + m_verticalPadding;
+ dc.DrawBitmap(m_bitmap, x, y, true);
+
+ if (selection.WithinSelection(obj->GetRange().GetStart(), obj))
+ {
+ wxCheckSetBrush(dc, *wxBLACK_BRUSH);
+ wxCheckSetPen(dc, *wxBLACK_PEN);
+ dc.SetLogicalFunction(wxINVERT);
+ dc.DrawRectangle(wxRect(x, y, m_bitmap.GetWidth(), m_bitmap.GetHeight()));
+ dc.SetLogicalFunction(wxCOPY);
+ }
+ }
+ else
+ {
+ wxString label(m_label);
+ if (label.IsEmpty())
+ label = wxT("??");
+ int w, h, maxDescent;
+ dc.SetFont(m_font);
+ dc.GetTextExtent(m_label, & w, &h, & maxDescent);
+ dc.SetTextForeground(textColour);
+
+ int x = clientArea.x + (clientArea.width - w)/2;
+ int y = clientArea.y + (clientArea.height - (h - maxDescent))/2;
+ dc.DrawText(m_label, x, y);
+ }
+ }
+
+ return true;
+}
+
+bool wxRichTextFieldTypeStandard::Layout(wxRichTextField* obj, wxDC& dc, wxRichTextDrawingContext& context, const wxRect& WXUNUSED(rect), const wxRect& WXUNUSED(parentRect), int style)
+{
+ if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_COMPOSITE)
+ return false; // USe default composite layout
+
+ wxSize size = GetSize(obj, dc, context, style);
+ obj->SetCachedSize(size);
+ obj->SetMinSize(size);
+ obj->SetMaxSize(size);
+ return true;
+}
+
+bool wxRichTextFieldTypeStandard::GetRangeSize(wxRichTextField* obj, const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, wxPoint position, wxArrayInt* partialExtents) const
+{
+ if (IsTopLevel(obj))
+ return obj->wxRichTextParagraphLayoutBox::GetRangeSize(range, size, descent, dc, context, flags, position);
+ else
+ {
+ wxSize sz = GetSize(obj, dc, context, 0);
+ if (partialExtents)
+ {
+ int lastSize;
+ if (partialExtents->GetCount() > 0)
+ lastSize = (*partialExtents)[partialExtents->GetCount()-1];
+ else
+ lastSize = 0;
+ partialExtents->Add(lastSize + sz.x);
+ }
+ size = sz;
+ return true;
+ }
+}
+
+wxSize wxRichTextFieldTypeStandard::GetSize(wxRichTextField* WXUNUSED(obj), wxDC& dc, wxRichTextDrawingContext& WXUNUSED(context), int WXUNUSED(style)) const
+{
+ int borderSize = 1;
+ int w = 0, h = 0, maxDescent = 0;
+
+ wxSize sz;
+ if (m_bitmap.IsOk())
+ {
+ w = m_bitmap.GetWidth();
+ h = m_bitmap.GetHeight();
+
+ sz = wxSize(w + m_horizontalMargin*2, h + m_verticalMargin*2);
+ }
+ else
+ {
+ wxString label(m_label);
+ if (label.IsEmpty())
+ label = wxT("??");
+ dc.SetFont(m_font);
+ dc.GetTextExtent(label, & w, &h, & maxDescent);
+
+ sz = wxSize(w + m_horizontalPadding*2 + m_horizontalMargin*2, h + m_verticalPadding *2 + m_verticalMargin*2);
+ }
+
+ if (m_displayStyle != wxRICHTEXT_FIELD_STYLE_NO_BORDER)
+ {
+ sz.x += borderSize*2;
+ sz.y += borderSize*2;
+ }
+
+ if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_START_TAG || m_displayStyle == wxRICHTEXT_FIELD_STYLE_END_TAG)
+ {
+ // Add space for the arrow
+ sz.x += (sz.y/2 - m_horizontalPadding);
+ }
+
+ return sz;
+}
+
+IMPLEMENT_DYNAMIC_CLASS(wxRichTextCell, wxRichTextBox)
+
+wxRichTextCell::wxRichTextCell(wxRichTextObject* parent):
+ wxRichTextBox(parent)
+{
+}
+
+/// Draw the item
+bool wxRichTextCell::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
+{
+ return wxRichTextBox::Draw(dc, context, range, selection, rect, descent, style);
+}
+
+/// Copy
+void wxRichTextCell::Copy(const wxRichTextCell& obj)
+{
+ wxRichTextBox::Copy(obj);
+}
+
+// Edit properties via a GUI
+bool wxRichTextCell::EditProperties(wxWindow* parent, wxRichTextBuffer* buffer)
+{
+ // We need to gather common attributes for all selected cells.
+
+ wxRichTextTable* table = wxDynamicCast(GetParent(), wxRichTextTable);
+ bool multipleCells = false;
+ wxRichTextAttr attr;
+
+ if (table && buffer && buffer->GetRichTextCtrl() && buffer->GetRichTextCtrl()->GetSelection().IsValid() &&
+ buffer->GetRichTextCtrl()->GetSelection().GetContainer() == GetParent())
+ {
+ wxRichTextAttr clashingAttr, absentAttr;
+ const wxRichTextSelection& sel = buffer->GetRichTextCtrl()->GetSelection();
+ size_t i;
+ int selectedCellCount = 0;
+ for (i = 0; i < sel.GetCount(); i++)
+ {
+ const wxRichTextRange& range = sel[i];
+ wxRichTextCell* cell = table->GetCell(range.GetStart());
+ if (cell)
+ {
+ wxRichTextAttr cellStyle = cell->GetAttributes();
+
+ CollectStyle(attr, cellStyle, clashingAttr, absentAttr);
+
+ selectedCellCount ++;
+ }
+ }
+ multipleCells = selectedCellCount > 1;
+ }
+ else
+ {
+ attr = GetAttributes();
+ }
+
+ wxString caption;
if (multipleCells)
caption = _("Multiple Cell Properties");
else
wxRichTextObjectPropertiesDialog cellDlg(this, wxGetTopLevelParent(parent), wxID_ANY, caption);
cellDlg.SetAttributes(attr);
- wxRichTextSizePage* sizePage = wxDynamicCast(cellDlg.FindPage(CLASSINFO(wxRichTextSizePage)), wxRichTextSizePage);
+ wxRichTextSizePage* sizePage = wxDynamicCast(cellDlg.FindPage(wxCLASSINFO(wxRichTextSizePage)), wxRichTextSizePage);
if (sizePage)
{
// We don't want position and floating controls for a cell.
}
// Draws the object.
-bool wxRichTextTable::Draw(wxDC& dc, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
+bool wxRichTextTable::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
{
- return wxRichTextBox::Draw(dc, range, selection, rect, descent, style);
+ return wxRichTextBox::Draw(dc, context, range, selection, rect, descent, style);
}
WX_DECLARE_OBJARRAY(wxRect, wxRichTextRectArray);
// layout to a particular size, or it could be the total space available in the
// parent. rect is the overall size, so we must subtract margins and padding.
// to get the actual available space.
-bool wxRichTextTable::Layout(wxDC& dc, const wxRect& rect, const wxRect& WXUNUSED(parentRect), int style)
+bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const wxRect& rect, const wxRect& WXUNUSED(parentRect), int style)
{
SetPosition(rect.GetPosition());
wxRichTextBuffer* buffer = GetBuffer();
if (buffer) scale = buffer->GetScale();
- wxRect availableSpace = GetAvailableContentArea(dc, rect);
+ wxRect availableSpace = GetAvailableContentArea(dc, context, rect);
wxTextAttrDimensionConverter converter(dc, scale, availableSpace.GetSize());
+ wxRichTextAttr attr(GetAttributes());
+ context.ApplyVirtualAttributes(attr, this);
+
// If we have no fixed table size, and assuming we're not pushed for
// space, then we don't have to try to stretch the table to fit the contents.
bool stretchToFitTableWidth = false;
int tableWidth = rect.width;
- if (GetAttributes().GetTextBoxAttr().GetWidth().IsValid())
+ if (attr.GetTextBoxAttr().GetWidth().IsValid())
{
- tableWidth = converter.GetPixels(GetAttributes().GetTextBoxAttr().GetWidth());
+ tableWidth = converter.GetPixels(attr.GetTextBoxAttr().GetWidth());
// Fixed table width, so we do want to stretch columns out if necessary.
stretchToFitTableWidth = true;
// Get internal padding
int paddingLeft = 0, paddingTop = 0;
- if (GetAttributes().GetTextBoxAttr().GetPadding().GetLeft().IsValid())
- paddingLeft = converter.GetPixels(GetAttributes().GetTextBoxAttr().GetPadding().GetLeft());
- if (GetAttributes().GetTextBoxAttr().GetPadding().GetTop().IsValid())
- paddingTop = converter.GetPixels(GetAttributes().GetTextBoxAttr().GetPadding().GetTop());
+ if (attr.GetTextBoxAttr().GetPadding().GetLeft().IsValid())
+ paddingLeft = converter.GetPixels(attr.GetTextBoxAttr().GetPadding().GetLeft());
+ if (attr.GetTextBoxAttr().GetPadding().GetTop().IsValid())
+ paddingTop = converter.GetPixels(attr.GetTextBoxAttr().GetPadding().GetTop());
// Assume that left and top padding are also used for inter-cell padding.
int paddingX = paddingLeft;
int paddingY = paddingTop;
int totalLeftMargin = 0, totalRightMargin = 0, totalTopMargin = 0, totalBottomMargin = 0;
- GetTotalMargin(dc, buffer, GetAttributes(), totalLeftMargin, totalRightMargin, totalTopMargin, totalBottomMargin);
+ GetTotalMargin(dc, buffer, attr, totalLeftMargin, totalRightMargin, totalTopMargin, totalBottomMargin);
// Internal table width - the area for content
int internalTableWidth = tableWidth - totalLeftMargin - totalRightMargin;
wxArrayInt absoluteColWidths;
absoluteColWidths.Add(0, m_colCount);
- // wxArrayInt absoluteColWidthsSpanning(m_colCount);
+
wxArrayInt percentageColWidths;
percentageColWidths.Add(0, m_colCount);
// wxArrayInt percentageColWidthsSpanning(m_colCount);
// Lay out cell to find min/max widths
cell->Invalidate(wxRICHTEXT_ALL);
- cell->Layout(dc, availableSpace, availableSpace, style);
+ cell->Layout(dc, context, availableSpace, availableSpace, style);
if (colSpan == 1)
{
// Lay out cell
cell->Invalidate(wxRICHTEXT_ALL);
- cell->Layout(dc, availableCellSpace, availableSpace, style);
+ cell->Layout(dc, context, availableCellSpace, availableSpace, style);
// TODO: use GetCachedSize().x to compute 'natural' size
wxRect availableCellSpace = wxRect(cell->GetPosition(), wxSize(actualWidths[i], maxCellHeight));
// Lay out cell with new height
cell->Invalidate(wxRICHTEXT_ALL);
- cell->Layout(dc, availableCellSpace, availableSpace, style);
+ cell->Layout(dc, context, availableCellSpace, availableSpace, style);
// Make sure the cell size really is the appropriate size,
// not the calculated box size
{
wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect;
contentRect = wxRect(wxPoint(0, 0), wxSize(maxRight - availableSpace.x, y - availableSpace.y));
- GetBoxRects(dc, GetBuffer(), GetAttributes(), marginRect, borderRect, contentRect, paddingRect, outlineRect);
+ GetBoxRects(dc, GetBuffer(), attr, marginRect, borderRect, contentRect, paddingRect, outlineRect);
SetCachedSize(marginRect.GetSize());
}
}
// Finds the absolute position and row height for the given character position
-bool wxRichTextTable::FindPosition(wxDC& dc, long index, wxPoint& pt, int* height, bool forceLineStart)
+bool wxRichTextTable::FindPosition(wxDC& dc, wxRichTextDrawingContext& context, long index, wxPoint& pt, int* height, bool forceLineStart)
{
wxRichTextCell* child = GetCell(index+1);
if (child)
{
// Find the position at the start of the child cell, since the table doesn't
// have any caret position of its own.
- return child->FindPosition(dc, -1, pt, height, forceLineStart);
+ return child->FindPosition(dc, context, -1, pt, height, forceLineStart);
}
else
return false;
}
// Gets the range size.
-bool wxRichTextTable::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position, wxArrayInt* partialExtents) const
+bool wxRichTextTable::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, wxPoint position, wxArrayInt* partialExtents) const
{
- return wxRichTextBox::GetRangeSize(range, size, descent, dc, flags, position, partialExtents);
+ return wxRichTextBox::GetRangeSize(range, size, descent, dc, context, flags, position, partialExtents);
}
// Deletes content in the given range.
wxRichTextBuffer::SetRenderer(new wxRichTextStdRenderer);
wxRichTextBuffer::InitStandardHandlers();
wxRichTextParagraph::InitDefaultTabs();
+
+ wxRichTextXMLHandler::RegisterNodeName(wxT("text"), wxT("wxRichTextPlainText"));
+ wxRichTextXMLHandler::RegisterNodeName(wxT("symbol"), wxT("wxRichTextPlainText"));
+ wxRichTextXMLHandler::RegisterNodeName(wxT("image"), wxT("wxRichTextImage"));
+ wxRichTextXMLHandler::RegisterNodeName(wxT("paragraph"), wxT("wxRichTextParagraph"));
+ wxRichTextXMLHandler::RegisterNodeName(wxT("paragraphlayout"), wxT("wxRichTextParagraphLayoutBox"));
+ wxRichTextXMLHandler::RegisterNodeName(wxT("textbox"), wxT("wxRichTextBox"));
+ wxRichTextXMLHandler::RegisterNodeName(wxT("cell"), wxT("wxRichTextCell"));
+ wxRichTextXMLHandler::RegisterNodeName(wxT("table"), wxT("wxRichTextTable"));
+ wxRichTextXMLHandler::RegisterNodeName(wxT("field"), wxT("wxRichTextField"));
+
return true;
}
void OnExit()
{
wxRichTextBuffer::CleanUpHandlers();
+ wxRichTextBuffer::CleanUpDrawingHandlers();
+ wxRichTextBuffer::CleanUpFieldTypes();
+ wxRichTextXMLHandler::ClearNodeToClassMap();
wxRichTextDecimalToRoman(-1);
wxRichTextParagraph::ClearDefaultTabs();
wxRichTextCtrl::ClearAvailableFontNames();
// first, but of course this means we'll be doing it twice.
if (!m_buffer->IsDirty() && m_ctrl) // can only do optimisation if the buffer is already laid out correctly
{
- wxSize clientSize = m_ctrl->GetClientSize();
- wxPoint firstVisiblePt = m_ctrl->GetFirstVisiblePoint();
+ wxSize clientSize = m_ctrl->GetUnscaledSize(m_ctrl->GetClientSize());
+ wxPoint firstVisiblePt = m_ctrl->GetUnscaledPoint(m_ctrl->GetFirstVisiblePoint());
int lastY = firstVisiblePt.y + clientSize.y;
wxRichTextParagraph* para = container->GetParagraphAtPosition(GetRange().GetStart());
container->DeleteRange(GetRange());
container->UpdateRanges();
+
// InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object,
// Layout() would stop prematurely at the top level.
container->InvalidateHierarchy(wxRichTextRange(GetRange().GetStart(), GetRange().GetStart()));
container->InsertFragment(GetRange().GetStart(), m_oldParagraphs);
container->UpdateRanges();
+
// InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object,
// Layout() would stop prematurely at the top level.
container->InvalidateHierarchy(GetRange());
{
size_t i;
- wxSize clientSize = m_ctrl->GetClientSize();
- wxPoint firstVisiblePt = m_ctrl->GetFirstVisiblePoint();
+ wxSize clientSize = m_ctrl->GetUnscaledSize(m_ctrl->GetClientSize());
+ wxPoint firstVisiblePt = m_ctrl->GetUnscaledPoint(m_ctrl->GetFirstVisiblePoint());
// Start/end positions
int firstY = 0;
lastY = firstVisiblePt.y + clientSize.y;
// Convert to device coordinates
- wxRect rect(m_ctrl->GetPhysicalPoint(wxPoint(firstVisiblePt.x, firstY)), wxSize(clientSize.x, lastY - firstY));
+ wxRect rect(m_ctrl->GetPhysicalPoint(m_ctrl->GetScaledPoint(wxPoint(firstVisiblePt.x, firstY))), m_ctrl->GetScaledSize(wxSize(clientSize.x, lastY - firstY)));
m_ctrl->RefreshRect(rect);
}
else
wxRichTextImage::wxRichTextImage(const wxImage& image, wxRichTextObject* parent, wxRichTextAttr* charStyle):
wxRichTextObject(parent)
{
+ Init();
m_imageBlock.MakeImageBlockDefaultQuality(image, wxBITMAP_TYPE_PNG);
if (charStyle)
SetAttributes(*charStyle);
wxRichTextImage::wxRichTextImage(const wxRichTextImageBlock& imageBlock, wxRichTextObject* parent, wxRichTextAttr* charStyle):
wxRichTextObject(parent)
{
+ Init();
m_imageBlock = imageBlock;
if (charStyle)
SetAttributes(*charStyle);
}
+void wxRichTextImage::Init()
+{
+ m_originalImageSize = wxSize(-1, -1);
+}
+
/// Create a cached image at the required size
bool wxRichTextImage::LoadImageCache(wxDC& dc, bool resetCache)
{
- if (resetCache || !m_imageCache.IsOk() /* || m_imageCache.GetWidth() != size.x || m_imageCache.GetHeight() != size.y */)
+ if (!m_imageBlock.IsOk())
+ return false;
+
+ // If we have an original image size, use that to compute the cached bitmap size
+ // instead of loading the image each time. This way we can avoid loading
+ // the image so long as the new cached bitmap size hasn't changed.
+
+ wxImage image;
+ if (resetCache || m_originalImageSize == wxSize(-1, -1))
{
- if (!m_imageBlock.IsOk())
- return false;
+ m_imageCache = wxNullBitmap;
- wxImage image;
m_imageBlock.Load(image);
if (!image.IsOk())
return false;
- int width = image.GetWidth();
- int height = image.GetHeight();
+ m_originalImageSize = wxSize(image.GetWidth(), image.GetHeight());
+ }
+
+ int width = m_originalImageSize.GetWidth();
+ int height = m_originalImageSize.GetHeight();
- if (GetAttributes().GetTextBoxAttr().GetWidth().IsValid() && GetAttributes().GetTextBoxAttr().GetWidth().GetValue() > 0)
+ int parentWidth = 0;
+ int parentHeight = 0;
+
+ int maxWidth = -1;
+ int maxHeight = -1;
+
+ wxRichTextBuffer* buffer = GetBuffer();
+ if (buffer)
+ {
+ wxSize sz;
+ if (buffer->GetRichTextCtrl())
{
- if (GetAttributes().GetTextBoxAttr().GetWidth().GetUnits() == wxTEXT_ATTR_UNITS_TENTHS_MM)
- width = ConvertTenthsMMToPixels(dc, GetAttributes().GetTextBoxAttr().GetWidth().GetValue());
- else
- width = GetAttributes().GetTextBoxAttr().GetWidth().GetValue();
+ // Subtract borders
+ sz = buffer->GetRichTextCtrl()->GetClientSize();
+
+ wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect;
+ marginRect = wxRect(0, 0, sz.x, sz.y);
+ buffer->GetBoxRects(dc, buffer, buffer->GetAttributes(), marginRect, borderRect, contentRect, paddingRect, outlineRect);
+
+ sz = contentRect.GetSize();
+
+ // Start with a maximum width of the control size, even if not specified by the content,
+ // to minimize the amount of picture overlapping the right-hand side
+ maxWidth = sz.x;
}
- if (GetAttributes().GetTextBoxAttr().GetHeight().IsValid() && GetAttributes().GetTextBoxAttr().GetHeight().GetValue() > 0)
+ else
+ sz = buffer->GetCachedSize();
+ parentWidth = sz.GetWidth();
+ parentHeight = sz.GetHeight();
+ }
+
+ if (GetAttributes().GetTextBoxAttr().GetWidth().IsValid() && GetAttributes().GetTextBoxAttr().GetWidth().GetValue() > 0)
+ {
+ if (parentWidth > 0 && GetAttributes().GetTextBoxAttr().GetWidth().GetUnits() == wxTEXT_ATTR_UNITS_PERCENTAGE)
+ width = (int) ((GetAttributes().GetTextBoxAttr().GetWidth().GetValue() * parentWidth)/100.0);
+ else if (GetAttributes().GetTextBoxAttr().GetWidth().GetUnits() == wxTEXT_ATTR_UNITS_TENTHS_MM)
+ width = ConvertTenthsMMToPixels(dc, GetAttributes().GetTextBoxAttr().GetWidth().GetValue());
+ else if (GetAttributes().GetTextBoxAttr().GetWidth().GetUnits() == wxTEXT_ATTR_UNITS_PIXELS)
+ width = GetAttributes().GetTextBoxAttr().GetWidth().GetValue();
+ }
+
+ // Limit to max width
+
+ if (GetAttributes().GetTextBoxAttr().GetMaxSize().GetWidth().IsValid() && GetAttributes().GetTextBoxAttr().GetMaxSize().GetWidth().GetValue() > 0)
+ {
+ int mw = -1;
+
+ if (parentWidth > 0 && GetAttributes().GetTextBoxAttr().GetMaxSize().GetWidth().GetUnits() == wxTEXT_ATTR_UNITS_PERCENTAGE)
+ mw = (int) ((GetAttributes().GetTextBoxAttr().GetMaxSize().GetWidth().GetValue() * parentWidth)/100.0);
+ else if (GetAttributes().GetTextBoxAttr().GetMaxSize().GetWidth().GetUnits() == wxTEXT_ATTR_UNITS_TENTHS_MM)
+ mw = ConvertTenthsMMToPixels(dc, GetAttributes().GetTextBoxAttr().GetMaxSize().GetWidth().GetValue());
+ else if (GetAttributes().GetTextBoxAttr().GetMaxSize().GetWidth().GetUnits() == wxTEXT_ATTR_UNITS_PIXELS)
+ mw = GetAttributes().GetTextBoxAttr().GetMaxSize().GetWidth().GetValue();
+
+ // If we already have a smaller max width due to the constraints of the control size,
+ // don't use the larger max width.
+ if (mw != -1 && ((maxWidth == -1) || (mw < maxWidth)))
+ maxWidth = mw;
+ }
+
+ if (maxWidth > 0 && width > maxWidth)
+ width = maxWidth;
+
+ // Preserve the aspect ratio
+ if (width != m_originalImageSize.GetWidth())
+ height = (int) (float(m_originalImageSize.GetHeight()) * (float(width)/float(m_originalImageSize.GetWidth())));
+
+ if (GetAttributes().GetTextBoxAttr().GetHeight().IsValid() && GetAttributes().GetTextBoxAttr().GetHeight().GetValue() > 0)
+ {
+ if (parentHeight > 0 && GetAttributes().GetTextBoxAttr().GetHeight().GetUnits() == wxTEXT_ATTR_UNITS_PERCENTAGE)
+ height = (int) ((GetAttributes().GetTextBoxAttr().GetHeight().GetValue() * parentHeight)/100.0);
+ else if (GetAttributes().GetTextBoxAttr().GetHeight().GetUnits() == wxTEXT_ATTR_UNITS_TENTHS_MM)
+ height = ConvertTenthsMMToPixels(dc, GetAttributes().GetTextBoxAttr().GetHeight().GetValue());
+ else if (GetAttributes().GetTextBoxAttr().GetHeight().GetUnits() == wxTEXT_ATTR_UNITS_PIXELS)
+ height = GetAttributes().GetTextBoxAttr().GetHeight().GetValue();
+
+ // Preserve the aspect ratio
+ if (height != m_originalImageSize.GetHeight())
+ width = (int) (float(m_originalImageSize.GetWidth()) * (float(height)/float(m_originalImageSize.GetHeight())));
+ }
+
+ // Limit to max height
+
+ if (GetAttributes().GetTextBoxAttr().GetMaxSize().GetHeight().IsValid() && GetAttributes().GetTextBoxAttr().GetMaxSize().GetHeight().GetValue() > 0)
+ {
+ if (parentHeight > 0 && GetAttributes().GetTextBoxAttr().GetMaxSize().GetHeight().GetUnits() == wxTEXT_ATTR_UNITS_PERCENTAGE)
+ maxHeight = (int) ((GetAttributes().GetTextBoxAttr().GetMaxSize().GetHeight().GetValue() * parentHeight)/100.0);
+ else if (GetAttributes().GetTextBoxAttr().GetMaxSize().GetHeight().GetUnits() == wxTEXT_ATTR_UNITS_TENTHS_MM)
+ maxHeight = ConvertTenthsMMToPixels(dc, GetAttributes().GetTextBoxAttr().GetMaxSize().GetHeight().GetValue());
+ else if (GetAttributes().GetTextBoxAttr().GetMaxSize().GetHeight().GetUnits() == wxTEXT_ATTR_UNITS_PIXELS)
+ maxHeight = GetAttributes().GetTextBoxAttr().GetMaxSize().GetHeight().GetValue();
+ }
+
+ if (maxHeight > 0 && height > maxHeight)
+ {
+ height = maxHeight;
+
+ // Preserve the aspect ratio
+ if (height != m_originalImageSize.GetHeight())
+ width = (int) (float(m_originalImageSize.GetWidth()) * (float(height)/float(m_originalImageSize.GetHeight())));
+ }
+
+ if (m_imageCache.IsOk() && m_imageCache.GetWidth() == width && m_imageCache.GetHeight() == height)
+ {
+ // Do nothing, we didn't need to change the image cache
+ }
+ else
+ {
+ if (!image.IsOk())
{
- if (GetAttributes().GetTextBoxAttr().GetHeight().GetUnits() == wxTEXT_ATTR_UNITS_TENTHS_MM)
- height = ConvertTenthsMMToPixels(dc, GetAttributes().GetTextBoxAttr().GetHeight().GetValue());
- else
- height = GetAttributes().GetTextBoxAttr().GetHeight().GetValue();
+ m_imageBlock.Load(image);
+ if (!image.IsOk())
+ return false;
}
if (image.GetWidth() == width && image.GetHeight() == height)
}
/// Draw the item
-bool wxRichTextImage::Draw(wxDC& dc, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int WXUNUSED(descent), int WXUNUSED(style))
+bool wxRichTextImage::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& WXUNUSED(range), const wxRichTextSelection& selection, const wxRect& rect, int WXUNUSED(descent), int WXUNUSED(style))
{
if (!IsShown())
return true;
if (!LoadImageCache(dc))
return false;
- DrawBoxAttributes(dc, GetBuffer(), GetAttributes(), wxRect(rect.GetPosition(), GetCachedSize()));
+ wxRichTextAttr attr(GetAttributes());
+ context.ApplyVirtualAttributes(attr, this);
-#if 0
- int y = rect.y + (rect.height - m_imageCache.GetHeight());
-
- dc.DrawBitmap(m_imageCache, rect.x, y, true);
-#endif
+ DrawBoxAttributes(dc, GetBuffer(), attr, wxRect(rect.GetPosition(), GetCachedSize()));
wxSize imageSize(m_imageCache.GetWidth(), m_imageCache.GetHeight());
wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect;
marginRect = rect; // outer rectangle, will calculate contentRect
- GetBoxRects(dc, GetBuffer(), GetAttributes(), marginRect, borderRect, contentRect, paddingRect, outlineRect);
+ GetBoxRects(dc, GetBuffer(), attr, marginRect, borderRect, contentRect, paddingRect, outlineRect);
dc.DrawBitmap(m_imageCache, contentRect.x, contentRect.y, true);
- if (selection.WithinSelection(range.GetStart(), this))
+ if (selection.WithinSelection(GetRange().GetStart(), this))
{
wxCheckSetBrush(dc, *wxBLACK_BRUSH);
wxCheckSetPen(dc, *wxBLACK_PEN);
}
/// Lay the item out
-bool wxRichTextImage::Layout(wxDC& dc, const wxRect& rect, const wxRect& WXUNUSED(parentRect), int WXUNUSED(style))
+bool wxRichTextImage::Layout(wxDC& dc, wxRichTextDrawingContext& context, const wxRect& rect, const wxRect& WXUNUSED(parentRect), int WXUNUSED(style))
{
if (!LoadImageCache(dc))
return false;
wxSize imageSize(m_imageCache.GetWidth(), m_imageCache.GetHeight());
wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect;
contentRect = wxRect(wxPoint(0,0), imageSize);
- GetBoxRects(dc, GetBuffer(), GetAttributes(), marginRect, borderRect, contentRect, paddingRect, outlineRect);
+
+ wxRichTextAttr attr(GetAttributes());
+ context.ApplyVirtualAttributes(attr, this);
+
+ GetBoxRects(dc, GetBuffer(), attr, marginRect, borderRect, contentRect, paddingRect, outlineRect);
wxSize overallSize = marginRect.GetSize();
/// 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& dc, int WXUNUSED(flags), wxPoint WXUNUSED(position), wxArrayInt* partialExtents) const
+bool wxRichTextImage::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& WXUNUSED(descent), wxDC& dc, wxRichTextDrawingContext& context, int WXUNUSED(flags), wxPoint WXUNUSED(position), wxArrayInt* partialExtents) const
{
if (!range.IsWithin(GetRange()))
return false;
return false;
}
+ wxRichTextAttr attr(GetAttributes());
+ context.ApplyVirtualAttributes(attr, (wxRichTextObject*) this);
+
wxSize imageSize(m_imageCache.GetWidth(), m_imageCache.GetHeight());
wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect;
contentRect = wxRect(wxPoint(0,0), imageSize);
- GetBoxRects(dc, GetBuffer(), GetAttributes(), marginRect, borderRect, contentRect, paddingRect, outlineRect);
+ GetBoxRects(dc, GetBuffer(), attr, marginRect, borderRect, contentRect, paddingRect, outlineRect);
wxSize overallSize = marginRect.GetSize();
wxRichTextObject::Copy(obj);
m_imageBlock = obj.m_imageBlock;
+ m_originalImageSize = obj.m_originalImageSize;
}
/// Edit properties via a GUI
return (attr1 == attr2);
}
-// Partial equality test taking flags into account
-bool wxTextAttrEqPartial(const wxRichTextAttr& attr1, const wxRichTextAttr& attr2)
-{
- return attr1.EqPartial(attr2);
-}
-
/// Compare tabs
bool wxRichTextTabsEq(const wxArrayInt& tabs1, const wxArrayInt& tabs2)
{
public:
wxRichTextFontTableData() {}
- wxFont FindFont(const wxRichTextAttr& fontSpec);
+ wxFont FindFont(const wxRichTextAttr& fontSpec, double fontScale);
wxRichTextFontTableHashMap m_hashMap;
};
-wxFont wxRichTextFontTableData::FindFont(const wxRichTextAttr& fontSpec)
+wxFont wxRichTextFontTableData::FindFont(const wxRichTextAttr& fontSpec, double fontScale)
{
wxString facename(fontSpec.GetFontFaceName());
- wxString spec(wxString::Format(wxT("%d-%d-%d-%d-%s-%d"), fontSpec.GetFontSize(), fontSpec.GetFontStyle(), fontSpec.GetFontWeight(), (int) fontSpec.GetFontUnderlined(), facename.c_str(), (int) fontSpec.GetFontEncoding()));
- wxRichTextFontTableHashMap::iterator entry = m_hashMap.find(spec);
+ int fontSize = fontSpec.GetFontSize();
+ if (fontScale != 1.0)
+ fontSize = (int) ((double(fontSize) * fontScale) + 0.5);
+
+ wxString units;
+ if (fontSpec.HasFontPixelSize() && !fontSpec.HasFontPointSize())
+ units = wxT("px");
+ else
+ units = wxT("pt");
+ wxString spec = wxString::Format(wxT("%d-%s-%d-%d-%d-%d-%s-%d"),
+ fontSize, units.c_str(), fontSpec.GetFontStyle(), fontSpec.GetFontWeight(), (int) fontSpec.GetFontUnderlined(), (int) fontSpec.GetFontStrikethrough(),
+ facename.c_str(), (int) fontSpec.GetFontEncoding());
+
+ wxRichTextFontTableHashMap::iterator entry = m_hashMap.find(spec);
if ( entry == m_hashMap.end() )
{
- wxFont font(fontSpec.GetFontSize(), wxDEFAULT, fontSpec.GetFontStyle(), fontSpec.GetFontWeight(), fontSpec.GetFontUnderlined(), facename.c_str());
- m_hashMap[spec] = font;
- return font;
+ if (fontSpec.HasFontPixelSize() && !fontSpec.HasFontPointSize())
+ {
+ wxFont font(wxSize(0, fontSize), wxFONTFAMILY_DEFAULT, fontSpec.GetFontStyle(), fontSpec.GetFontWeight(), fontSpec.GetFontUnderlined(), facename);
+ if (fontSpec.HasFontStrikethrough() && fontSpec.GetFontStrikethrough())
+ font.SetStrikethrough(true);
+ m_hashMap[spec] = font;
+ return font;
+ }
+ else
+ {
+ wxFont font(fontSize, wxFONTFAMILY_DEFAULT, fontSpec.GetFontStyle(), fontSpec.GetFontWeight(), fontSpec.GetFontUnderlined(), facename.c_str());
+ if (fontSpec.HasFontStrikethrough() && fontSpec.GetFontStrikethrough())
+ font.SetStrikethrough(true);
+
+ m_hashMap[spec] = font;
+ return font;
+ }
}
else
{
wxRichTextFontTable::wxRichTextFontTable()
{
m_refData = new wxRichTextFontTableData;
+ m_fontScale = 1.0;
}
wxRichTextFontTable::wxRichTextFontTable(const wxRichTextFontTable& table)
void wxRichTextFontTable::operator= (const wxRichTextFontTable& table)
{
Ref(table);
+ m_fontScale = table.m_fontScale;
}
wxFont wxRichTextFontTable::FindFont(const wxRichTextAttr& fontSpec)
{
wxRichTextFontTableData* data = (wxRichTextFontTableData*) m_refData;
if (data)
- return data->FindFont(fontSpec);
+ return data->FindFont(fontSpec, m_fontScale);
else
return wxFont();
}
data->m_hashMap.clear();
}
-// wxTextBoxAttr
+void wxRichTextFontTable::SetFontScale(double fontScale)
+{
+ if (fontScale != m_fontScale)
+ Clear();
+ m_fontScale = fontScale;
+}
+// wxTextBoxAttr
void wxTextBoxAttr::Reset()
{
}
// Partial equality test
-bool wxTextBoxAttr::EqPartial(const wxTextBoxAttr& attr) const
+bool wxTextBoxAttr::EqPartial(const wxTextBoxAttr& attr, bool weakTest) const
{
+ if (!weakTest &&
+ ((!HasFloatMode() && attr.HasFloatMode()) ||
+ (!HasClearMode() && attr.HasClearMode()) ||
+ (!HasCollapseBorders() && attr.HasCollapseBorders()) ||
+ (!HasVerticalAlignment() && attr.HasVerticalAlignment()) ||
+ (!HasBoxStyleName() && attr.HasBoxStyleName())))
+ {
+ return false;
+ }
if (attr.HasFloatMode() && HasFloatMode() && (GetFloatMode() != attr.GetFloatMode()))
return false;
// Position
- if (!m_position.EqPartial(attr.m_position))
+ if (!m_position.EqPartial(attr.m_position, weakTest))
return false;
// Size
- if (!m_size.EqPartial(attr.m_size))
+ if (!m_size.EqPartial(attr.m_size, weakTest))
return false;
- if (!m_minSize.EqPartial(attr.m_minSize))
+ if (!m_minSize.EqPartial(attr.m_minSize, weakTest))
return false;
- if (!m_maxSize.EqPartial(attr.m_maxSize))
+ if (!m_maxSize.EqPartial(attr.m_maxSize, weakTest))
return false;
// Margins
- if (!m_margins.EqPartial(attr.m_margins))
+ if (!m_margins.EqPartial(attr.m_margins, weakTest))
return false;
// Padding
- if (!m_padding.EqPartial(attr.m_padding))
+ if (!m_padding.EqPartial(attr.m_padding, weakTest))
return false;
// Border
- if (!GetBorder().EqPartial(attr.GetBorder()))
+ if (!GetBorder().EqPartial(attr.GetBorder(), weakTest))
return false;
// Outline
- if (!GetOutline().EqPartial(attr.GetOutline()))
+ if (!GetOutline().EqPartial(attr.GetOutline(), weakTest))
return false;
return true;
return (m_textBoxAttr == attr.m_textBoxAttr);
}
-// Partial equality test taking comparison object into account
-bool wxRichTextAttr::EqPartial(const wxRichTextAttr& attr) const
+// Partial equality test
+bool wxRichTextAttr::EqPartial(const wxRichTextAttr& attr, bool weakTest) const
{
- if (!(wxTextAttr::EqPartial(attr)))
+ if (!(wxTextAttr::EqPartial(attr, weakTest)))
return false;
- return m_textBoxAttr.EqPartial(attr.m_textBoxAttr);
+ return m_textBoxAttr.EqPartial(attr.m_textBoxAttr, weakTest);
}
// Merges the given attributes. If compareWith
}
// Partial equality test
-bool wxTextAttrBorder::EqPartial(const wxTextAttrBorder& border) const
+bool wxTextAttrBorder::EqPartial(const wxTextAttrBorder& border, bool weakTest) const
{
- if (border.HasStyle() && !HasStyle() && (border.GetStyle() != GetStyle()))
+ if (!weakTest &&
+ ((!HasStyle() && border.HasStyle()) ||
+ (!HasColour() && border.HasColour()) ||
+ (!HasWidth() && border.HasWidth())))
+ {
return false;
+ }
- if (border.HasColour() && !HasColour() && (border.GetColourLong() != GetColourLong()))
+ if (border.HasStyle() && HasStyle() && (border.GetStyle() != GetStyle()))
return false;
- if (border.HasWidth() && !HasWidth() && !(border.GetWidth() == GetWidth()))
+ if (border.HasColour() && HasColour() && (border.GetColourLong() != GetColourLong()))
+ return false;
+
+ if (border.HasWidth() && HasWidth() && !(border.GetWidth() == GetWidth()))
return false;
return true;
}
// Partial equality test
-bool wxTextAttrBorders::EqPartial(const wxTextAttrBorders& borders) const
+bool wxTextAttrBorders::EqPartial(const wxTextAttrBorders& borders, bool weakTest) const
{
- return m_left.EqPartial(borders.m_left) && m_right.EqPartial(borders.m_right) &&
- m_top.EqPartial(borders.m_top) && m_bottom.EqPartial(borders.m_bottom);
+ return m_left.EqPartial(borders.m_left, weakTest) && m_right.EqPartial(borders.m_right, weakTest) &&
+ m_top.EqPartial(borders.m_top, weakTest) && m_bottom.EqPartial(borders.m_bottom, weakTest);
}
// Apply border to 'this', but not if the same as compareWith
}
// Partial equality test
-bool wxTextAttrDimension::EqPartial(const wxTextAttrDimension& dim) const
+bool wxTextAttrDimension::EqPartial(const wxTextAttrDimension& dim, bool weakTest) const
{
+ if (!weakTest && !IsValid() && dim.IsValid())
+ return false;
+
if (dim.IsValid() && IsValid() && !((*this) == dim))
return false;
else
}
// Partial equality test
-bool wxTextAttrDimensions::EqPartial(const wxTextAttrDimensions& dims) const
+bool wxTextAttrDimensions::EqPartial(const wxTextAttrDimensions& dims, bool weakTest) const
{
- if (!m_left.EqPartial(dims.m_left))
+ if (!m_left.EqPartial(dims.m_left, weakTest))
return false;
- if (!m_right.EqPartial(dims.m_right))
+ if (!m_right.EqPartial(dims.m_right, weakTest))
return false;
- if (!m_top.EqPartial(dims.m_top))
+ if (!m_top.EqPartial(dims.m_top, weakTest))
return false;
- if (!m_bottom.EqPartial(dims.m_bottom))
+ if (!m_bottom.EqPartial(dims.m_bottom, weakTest))
return false;
return true;
}
// Partial equality test
-bool wxTextAttrSize::EqPartial(const wxTextAttrSize& size) const
+bool wxTextAttrSize::EqPartial(const wxTextAttrSize& size, bool weakTest) const
{
- if (!m_width.EqPartial(size.m_width))
+ if (!m_width.EqPartial(size.m_width, weakTest))
return false;
- if (!m_height.EqPartial(size.m_height))
+ if (!m_height.EqPartial(size.m_height, weakTest))
return false;
return true;
if (attr.HasFont())
{
- if (attr.HasFontSize() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_SIZE))
+ // If different font size units are being used, this is a clash.
+ if (((attr.GetFlags() & wxTEXT_ATTR_FONT_SIZE) | (currentStyle.GetFlags() & wxTEXT_ATTR_FONT_SIZE)) == wxTEXT_ATTR_FONT_SIZE)
+ {
+ currentStyle.SetFontSize(0);
+ currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_SIZE);
+ clashingAttr.AddFlag(wxTEXT_ATTR_FONT_SIZE);
+ }
+ else
{
- if (currentStyle.HasFontSize())
+ if (attr.HasFontPointSize() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_POINT_SIZE))
{
- if (currentStyle.GetFontSize() != attr.GetFontSize())
+ if (currentStyle.HasFontPointSize())
{
- // Clash of attr - mark as such
- clashingAttr.AddFlag(wxTEXT_ATTR_FONT_SIZE);
- currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_SIZE);
+ if (currentStyle.GetFontSize() != attr.GetFontSize())
+ {
+ // Clash of attr - mark as such
+ clashingAttr.AddFlag(wxTEXT_ATTR_FONT_POINT_SIZE);
+ currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_POINT_SIZE);
+ }
}
+ else
+ currentStyle.SetFontSize(attr.GetFontSize());
+ }
+
+ if (attr.HasFontPixelSize() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_PIXEL_SIZE))
+ {
+ if (currentStyle.HasFontPixelSize())
+ {
+ if (currentStyle.GetFontSize() != attr.GetFontSize())
+ {
+ // Clash of attr - mark as such
+ clashingAttr.AddFlag(wxTEXT_ATTR_FONT_PIXEL_SIZE);
+ currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_PIXEL_SIZE);
+ }
+ }
+ else
+ currentStyle.SetFontPixelSize(attr.GetFontSize());
}
- else
- currentStyle.SetFontSize(attr.GetFontSize());
}
if (attr.HasFontItalic() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_ITALIC))
else
currentStyle.SetFontUnderlined(attr.GetFontUnderlined());
}
+
+ if (attr.HasFontStrikethrough() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_STRIKETHROUGH))
+ {
+ if (currentStyle.HasFontStrikethrough())
+ {
+ if (currentStyle.GetFontStrikethrough() != attr.GetFontStrikethrough())
+ {
+ // Clash of attr - mark as such
+ clashingAttr.AddFlag(wxTEXT_ATTR_FONT_STRIKETHROUGH);
+ currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_STRIKETHROUGH);
+ }
+ }
+ else
+ currentStyle.SetFontStrikethrough(attr.GetFontStrikethrough());
+ }
}
if (attr.HasTextColour() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_TEXT_COLOUR))
return false;
}
+IMPLEMENT_CLASS(wxRichTextDrawingHandler, wxObject)
+IMPLEMENT_CLASS(wxRichTextDrawingContext, wxObject)
+
+bool wxRichTextDrawingContext::HasVirtualAttributes(wxRichTextObject* obj) const
+{
+ wxList::compatibility_iterator node = m_buffer->GetDrawingHandlers().GetFirst();
+ while (node)
+ {
+ wxRichTextDrawingHandler *handler = (wxRichTextDrawingHandler*)node->GetData();
+ if (handler->HasVirtualAttributes(obj))
+ return true;
+
+ node = node->GetNext();
+ }
+ return false;
+}
+
+wxRichTextAttr wxRichTextDrawingContext::GetVirtualAttributes(wxRichTextObject* obj) const
+{
+ wxRichTextAttr attr;
+ // We apply all handlers, so we can may combine several different attributes
+ wxList::compatibility_iterator node = m_buffer->GetDrawingHandlers().GetFirst();
+ while (node)
+ {
+ wxRichTextDrawingHandler *handler = (wxRichTextDrawingHandler*)node->GetData();
+ if (handler->HasVirtualAttributes(obj))
+ {
+ bool success = handler->GetVirtualAttributes(attr, obj);
+ wxASSERT(success);
+ wxUnusedVar(success);
+ }
+
+ node = node->GetNext();
+ }
+ return attr;
+}
+
+bool wxRichTextDrawingContext::ApplyVirtualAttributes(wxRichTextAttr& attr, wxRichTextObject* obj) const
+{
+ if (HasVirtualAttributes(obj))
+ {
+ wxRichTextAttr a(GetVirtualAttributes(obj));
+ attr.Apply(a);
+ return true;
+ }
+ else
+ return false;
+}
+
+/// Adds a handler to the end
+void wxRichTextBuffer::AddDrawingHandler(wxRichTextDrawingHandler *handler)
+{
+ sm_drawingHandlers.Append(handler);
+}
+
+/// Inserts a handler at the front
+void wxRichTextBuffer::InsertDrawingHandler(wxRichTextDrawingHandler *handler)
+{
+ sm_drawingHandlers.Insert( handler );
+}
+
+/// Removes a handler
+bool wxRichTextBuffer::RemoveDrawingHandler(const wxString& name)
+{
+ wxRichTextDrawingHandler *handler = FindDrawingHandler(name);
+ if (handler)
+ {
+ sm_drawingHandlers.DeleteObject(handler);
+ delete handler;
+ return true;
+ }
+ else
+ return false;
+}
+
+wxRichTextDrawingHandler* wxRichTextBuffer::FindDrawingHandler(const wxString& name)
+{
+ wxList::compatibility_iterator node = sm_drawingHandlers.GetFirst();
+ while (node)
+ {
+ wxRichTextDrawingHandler *handler = (wxRichTextDrawingHandler*)node->GetData();
+ if (handler->GetName().Lower() == name.Lower()) return handler;
+
+ node = node->GetNext();
+ }
+ return NULL;
+}
+
+void wxRichTextBuffer::CleanUpDrawingHandlers()
+{
+ wxList::compatibility_iterator node = sm_drawingHandlers.GetFirst();
+ while (node)
+ {
+ wxRichTextDrawingHandler* handler = (wxRichTextDrawingHandler*)node->GetData();
+ wxList::compatibility_iterator next = node->GetNext();
+ delete handler;
+ node = next;
+ }
+
+ sm_drawingHandlers.Clear();
+}
+
+void wxRichTextBuffer::AddFieldType(wxRichTextFieldType *fieldType)
+{
+ sm_fieldTypes[fieldType->GetName()] = fieldType;
+}
+
+bool wxRichTextBuffer::RemoveFieldType(const wxString& name)
+{
+ wxRichTextFieldTypeHashMap::iterator it = sm_fieldTypes.find(name);
+ if (it == sm_fieldTypes.end())
+ return false;
+ else
+ {
+ wxRichTextFieldType* fieldType = it->second;
+ sm_fieldTypes.erase(it);
+ delete fieldType;
+ return true;
+ }
+}
+
+wxRichTextFieldType *wxRichTextBuffer::FindFieldType(const wxString& name)
+{
+ wxRichTextFieldTypeHashMap::iterator it = sm_fieldTypes.find(name);
+ if (it == sm_fieldTypes.end())
+ return NULL;
+ else
+ return it->second;
+}
+
+void wxRichTextBuffer::CleanUpFieldTypes()
+{
+ wxRichTextFieldTypeHashMap::iterator it;
+ for( it = sm_fieldTypes.begin(); it != sm_fieldTypes.end(); ++it )
+ {
+ wxRichTextFieldType* fieldType = it->second;
+ delete fieldType;
+ }
+
+ sm_fieldTypes.clear();
+}
#endif
// wxUSE_RICHTEXT