Fixed floating image layout when typing in subsequent paragraph

Now makes use of max size for images and keeps the image size reasonable
Added original image size so can usually avoid reloading image when recomputing
cached bitmap size
Takes into account bottom of the last floating image so scrollbars are
set correctly
Original image size is shown in disabled size controls


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@71277 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Julian Smart
2012-04-25 11:42:31 +00:00
parent c6182d489c
commit 23698b123b
4 changed files with 194 additions and 37 deletions

View File

@@ -4012,7 +4012,7 @@ public:
/** /**
Default constructor. Default constructor.
*/ */
wxRichTextImage(wxRichTextObject* parent = NULL): wxRichTextObject(parent) { } wxRichTextImage(wxRichTextObject* parent = NULL): wxRichTextObject(parent) { Init(); }
/** /**
Creates a wxRichTextImage from a wxImage. Creates a wxRichTextImage from a wxImage.
@@ -4029,6 +4029,11 @@ public:
*/ */
wxRichTextImage(const wxRichTextImage& obj): wxRichTextObject(obj) { Copy(obj); } wxRichTextImage(const wxRichTextImage& obj): wxRichTextObject(obj) { Copy(obj); }
/**
Initialisation.
*/
void Init();
// Overridables // Overridables
virtual bool Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style); virtual bool Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style);
@@ -4079,12 +4084,12 @@ public:
/** /**
Sets the image cache. Sets the image cache.
*/ */
void SetImageCache(const wxBitmap& bitmap) { m_imageCache = bitmap; } void SetImageCache(const wxBitmap& bitmap) { m_imageCache = bitmap; m_originalImageSize = wxSize(bitmap.GetWidth(), bitmap.GetHeight()); }
/** /**
Resets the image cache. Resets the image cache.
*/ */
void ResetImageCache() { m_imageCache = wxNullBitmap; } void ResetImageCache() { m_imageCache = wxNullBitmap; m_originalImageSize = wxSize(-1, -1); }
/** /**
Returns the image block containing the raw data. Returns the image block containing the raw data.
@@ -4108,9 +4113,20 @@ public:
*/ */
virtual bool LoadImageCache(wxDC& dc, bool resetCache = false); virtual bool LoadImageCache(wxDC& dc, bool resetCache = false);
/**
Gets the original image size.
*/
wxSize GetOriginalImageSize() const { return m_originalImageSize; }
/**
Sets the original image size.
*/
void SetOriginalImageSize(const wxSize& sz) { m_originalImageSize = sz; }
protected: protected:
wxRichTextImageBlock m_imageBlock; wxRichTextImageBlock m_imageBlock;
wxBitmap m_imageCache; wxBitmap m_imageCache;
wxSize m_originalImageSize;
}; };
class WXDLLIMPEXP_FWD_RICHTEXT wxRichTextCommand; class WXDLLIMPEXP_FWD_RICHTEXT wxRichTextCommand;

View File

@@ -3971,6 +3971,16 @@ public:
*/ */
wxRichTextImageBlock& GetImageBlock() { return m_imageBlock; } wxRichTextImageBlock& GetImageBlock() { return m_imageBlock; }
/**
Gets the original image size.
*/
wxSize GetOriginalImageSize() const;
/**
Sets the original image size.
*/
void SetOriginalImageSize(const wxSize& sz);
// Operations // Operations
/** /**

View File

@@ -613,7 +613,11 @@ void wxRichTextObject::Invalidate(const wxRichTextRange& invalidRange)
{ {
if (invalidRange != wxRICHTEXT_NONE) 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); SetMaxSize(wxDefaultSize);
SetMinSize(wxDefaultSize); SetMinSize(wxDefaultSize);
} }
@@ -2026,6 +2030,14 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, wxRichTextDrawingContext& co
else else
maxHeight = 0; // topMargin + bottomMargin; maxHeight = 0; // topMargin + bottomMargin;
// 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()) if (attr.GetTextBoxAttr().GetSize().GetWidth().IsValid())
{ {
wxRect r = AdjustAvailableSpace(dc, GetBuffer(), wxRichTextAttr() /* not used */, attr, parentRect, parentRect); wxRect r = AdjustAvailableSpace(dc, GetBuffer(), wxRichTextAttr() /* not used */, attr, parentRect, parentRect);
@@ -10057,6 +10069,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxRichTextImage, wxRichTextObject)
wxRichTextImage::wxRichTextImage(const wxImage& image, wxRichTextObject* parent, wxRichTextAttr* charStyle): wxRichTextImage::wxRichTextImage(const wxImage& image, wxRichTextObject* parent, wxRichTextAttr* charStyle):
wxRichTextObject(parent) wxRichTextObject(parent)
{ {
Init();
m_imageBlock.MakeImageBlockDefaultQuality(image, wxBITMAP_TYPE_PNG); m_imageBlock.MakeImageBlockDefaultQuality(image, wxBITMAP_TYPE_PNG);
if (charStyle) if (charStyle)
SetAttributes(*charStyle); SetAttributes(*charStyle);
@@ -10065,40 +10078,155 @@ wxRichTextImage::wxRichTextImage(const wxImage& image, wxRichTextObject* parent,
wxRichTextImage::wxRichTextImage(const wxRichTextImageBlock& imageBlock, wxRichTextObject* parent, wxRichTextAttr* charStyle): wxRichTextImage::wxRichTextImage(const wxRichTextImageBlock& imageBlock, wxRichTextObject* parent, wxRichTextAttr* charStyle):
wxRichTextObject(parent) wxRichTextObject(parent)
{ {
Init();
m_imageBlock = imageBlock; m_imageBlock = imageBlock;
if (charStyle) if (charStyle)
SetAttributes(*charStyle); SetAttributes(*charStyle);
} }
void wxRichTextImage::Init()
{
m_originalImageSize = wxSize(-1, -1);
}
/// Create a cached image at the required size /// Create a cached image at the required size
bool wxRichTextImage::LoadImageCache(wxDC& dc, bool resetCache) 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 (!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))
{
m_imageCache = wxNullBitmap;
wxImage image;
m_imageBlock.Load(image); m_imageBlock.Load(image);
if (!image.IsOk()) if (!image.IsOk())
return false; return false;
int width = image.GetWidth(); m_originalImageSize = wxSize(image.GetWidth(), image.GetHeight());
int height = image.GetHeight(); }
if (GetAttributes().GetTextBoxAttr().GetWidth().IsValid() && GetAttributes().GetTextBoxAttr().GetWidth().GetValue() > 0) int width = m_originalImageSize.GetWidth();
int height = m_originalImageSize.GetHeight();
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) // Subtract borders
width = ConvertTenthsMMToPixels(dc, GetAttributes().GetTextBoxAttr().GetWidth().GetValue()); sz = buffer->GetRichTextCtrl()->GetClientSize();
else
width = GetAttributes().GetTextBoxAttr().GetWidth().GetValue(); 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) m_imageBlock.Load(image);
height = ConvertTenthsMMToPixels(dc, GetAttributes().GetTextBoxAttr().GetHeight().GetValue()); if (!image.IsOk())
else return false;
height = GetAttributes().GetTextBoxAttr().GetHeight().GetValue();
} }
if (image.GetWidth() == width && image.GetHeight() == height) if (image.GetWidth() == width && image.GetHeight() == height)
@@ -10243,6 +10371,7 @@ void wxRichTextImage::Copy(const wxRichTextImage& obj)
wxRichTextObject::Copy(obj); wxRichTextObject::Copy(obj);
m_imageBlock = obj.m_imageBlock; m_imageBlock = obj.m_imageBlock;
m_originalImageSize = obj.m_originalImageSize;
} }
/// Edit properties via a GUI /// Edit properties via a GUI

View File

@@ -533,25 +533,27 @@ bool wxRichTextSizePage::TransferDataToWindow()
} }
} }
if (dialog && dialog->GetObject()) wxRichTextImage* imageObj = NULL;
{ if (dialog)
wxTextAttrSize size = dialog->GetObject()->GetNaturalSize(); imageObj = wxDynamicCast(dialog->GetObject(), wxRichTextImage);
if (size.GetWidth().IsValid() && size.GetHeight().IsValid())
{
if (!GetAttributes()->GetTextBoxAttr().GetWidth().IsValid() || GetAttributes()->GetTextBoxAttr().GetWidth().GetValue() <= 0)
{
GetAttributes()->GetTextBoxAttr().GetWidth() = size.GetWidth();
}
if (!GetAttributes()->GetTextBoxAttr().GetHeight().IsValid() || GetAttributes()->GetTextBoxAttr().GetHeight().GetValue() <= 0) // For an image, show the original width and height if the size is not explicitly specified.
{ if (imageObj && !GetAttributes()->GetTextBoxAttr().GetWidth().IsValid() && !GetAttributes()->GetTextBoxAttr().GetHeight().IsValid() &&
GetAttributes()->GetTextBoxAttr().GetHeight() = size.GetHeight(); imageObj->GetOriginalImageSize() != wxSize(-1, -1))
} {
} m_widthCheckbox->SetValue(false);
m_heightCheckbox->SetValue(false);
m_unitsW->SetSelection(0);
m_unitsH->SetSelection(0);
m_width->SetValue(wxString::Format(wxT("%d"), (int) imageObj->GetOriginalImageSize().GetWidth()));
m_height->SetValue(wxString::Format(wxT("%d"), (int) imageObj->GetOriginalImageSize().GetHeight()));
}
else
{
wxRichTextFormattingDialog::SetDimensionValue(GetAttributes()->GetTextBoxAttr().GetWidth(), m_width, m_unitsW, m_widthCheckbox);
wxRichTextFormattingDialog::SetDimensionValue(GetAttributes()->GetTextBoxAttr().GetHeight(), m_height, m_unitsH, m_heightCheckbox);
} }
wxRichTextFormattingDialog::SetDimensionValue(GetAttributes()->GetTextBoxAttr().GetWidth(), m_width, m_unitsW, m_widthCheckbox);
wxRichTextFormattingDialog::SetDimensionValue(GetAttributes()->GetTextBoxAttr().GetHeight(), m_height, m_unitsH, m_heightCheckbox);
wxRichTextFormattingDialog::SetDimensionValue(GetAttributes()->GetTextBoxAttr().GetMinSize().GetWidth(), m_minWidth, m_unitsMinW, m_minWidthCheckbox); wxRichTextFormattingDialog::SetDimensionValue(GetAttributes()->GetTextBoxAttr().GetMinSize().GetWidth(), m_minWidth, m_unitsMinW, m_minWidthCheckbox);
wxRichTextFormattingDialog::SetDimensionValue(GetAttributes()->GetTextBoxAttr().GetMinSize().GetHeight(), m_minHeight, m_unitsMinH, m_minHeightCheckbox); wxRichTextFormattingDialog::SetDimensionValue(GetAttributes()->GetTextBoxAttr().GetMinSize().GetHeight(), m_minHeight, m_unitsMinH, m_minHeightCheckbox);
wxRichTextFormattingDialog::SetDimensionValue(GetAttributes()->GetTextBoxAttr().GetMaxSize().GetWidth(), m_maxWidth, m_unitsMaxW, m_maxWidthCheckbox); wxRichTextFormattingDialog::SetDimensionValue(GetAttributes()->GetTextBoxAttr().GetMaxSize().GetWidth(), m_maxWidth, m_unitsMaxW, m_maxWidthCheckbox);