]> git.saurik.com Git - wxWidgets.git/commitdiff
Fixed floating image layout when typing in subsequent paragraph
authorJulian Smart <julian@anthemion.co.uk>
Wed, 25 Apr 2012 11:42:31 +0000 (11:42 +0000)
committerJulian Smart <julian@anthemion.co.uk>
Wed, 25 Apr 2012 11:42:31 +0000 (11:42 +0000)
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

include/wx/richtext/richtextbuffer.h
interface/wx/richtext/richtextbuffer.h
src/richtext/richtextbuffer.cpp
src/richtext/richtextsizepage.cpp

index cdcd75b83785435267312f446ff342ab8cdda1a8..e6465bbb77876e16ff41e05532e9bfbdfcc707c7 100644 (file)
@@ -4012,7 +4012,7 @@ public:
     /**
         Default constructor.
     */
-    wxRichTextImage(wxRichTextObject* parent = NULL): wxRichTextObject(parent) { }
+    wxRichTextImage(wxRichTextObject* parent = NULL): wxRichTextObject(parent) { Init(); }
 
     /**
         Creates a wxRichTextImage from a wxImage.
@@ -4029,6 +4029,11 @@ public:
     */
     wxRichTextImage(const wxRichTextImage& obj): wxRichTextObject(obj) { Copy(obj); }
 
+    /**
+        Initialisation.
+    */
+    void Init();
+
 // Overridables
 
     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.
     */
-    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.
     */
-    void ResetImageCache() { m_imageCache = wxNullBitmap; }
+    void ResetImageCache() { m_imageCache = wxNullBitmap; m_originalImageSize = wxSize(-1, -1); }
 
     /**
         Returns the image block containing the raw data.
@@ -4108,9 +4113,20 @@ public:
     */
     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:
     wxRichTextImageBlock    m_imageBlock;
     wxBitmap                m_imageCache;
+    wxSize                  m_originalImageSize;
 };
 
 class WXDLLIMPEXP_FWD_RICHTEXT wxRichTextCommand;
index 3525641fd2644012cbd515c5f4f39e4a2e392542..8227a7b63c74c67ec1379ab9fbeb7f7aa807b53d 100644 (file)
@@ -3971,6 +3971,16 @@ public:
     */
     wxRichTextImageBlock& GetImageBlock() { return m_imageBlock; }
 
+    /**
+        Gets the original image size.
+    */
+    wxSize GetOriginalImageSize() const;
+
+    /**
+        Sets the original image size.
+    */
+    void SetOriginalImageSize(const wxSize& sz);
+
 // Operations
 
     /**
index 5881f6f45c45847492fe823ad90607a484ded4ed..7e0ba4bdcf36b449768b927589d3a87c9dd344ad 100644 (file)
@@ -613,7 +613,11 @@ void wxRichTextObject::Invalidate(const wxRichTextRange& invalidRange)
 {
     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);
     }
@@ -2026,6 +2030,14 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, wxRichTextDrawingContext& co
     else
         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())
     {
         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):
     wxRichTextObject(parent)
 {
+    Init();
     m_imageBlock.MakeImageBlockDefaultQuality(image, wxBITMAP_TYPE_PNG);
     if (charStyle)
         SetAttributes(*charStyle);
@@ -10065,40 +10078,155 @@ wxRichTextImage::wxRichTextImage(const wxImage& image, wxRichTextObject* parent,
 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();
+
+    int parentWidth = 0;
+    int parentHeight = 0;
 
-        if (GetAttributes().GetTextBoxAttr().GetWidth().IsValid() && GetAttributes().GetTextBoxAttr().GetWidth().GetValue() > 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)
@@ -10243,6 +10371,7 @@ void wxRichTextImage::Copy(const wxRichTextImage& obj)
     wxRichTextObject::Copy(obj);
 
     m_imageBlock = obj.m_imageBlock;
+    m_originalImageSize = obj.m_originalImageSize;
 }
 
 /// Edit properties via a GUI
index 65281d9cf917c4d5f3ead1e7172d4b04b590464d..d9c9fff03edb18a6f870d5f80e277be579d2440a 100644 (file)
@@ -533,25 +533,27 @@ bool wxRichTextSizePage::TransferDataToWindow()
         }
     }
 
-    if (dialog && dialog->GetObject())
+    wxRichTextImage* imageObj = NULL;
+    if (dialog)
+        imageObj = wxDynamicCast(dialog->GetObject(), wxRichTextImage);
+
+    // 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() &&
+        imageObj->GetOriginalImageSize() != wxSize(-1, -1))
     {
-        wxTextAttrSize size = dialog->GetObject()->GetNaturalSize();
-        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)
-            {
-                GetAttributes()->GetTextBoxAttr().GetHeight() = size.GetHeight();
-            }
-        }
+        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().GetHeight(), m_minHeight, m_unitsMinH, m_minHeightCheckbox);
     wxRichTextFormattingDialog::SetDimensionValue(GetAttributes()->GetTextBoxAttr().GetMaxSize().GetWidth(), m_maxWidth, m_unitsMaxW, m_maxWidthCheckbox);