Added on-demand image loading option to wxRTC.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@76110 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Julian Smart
2014-03-10 11:08:42 +00:00
parent 3772880ce6
commit cd3fc53163
7 changed files with 420 additions and 21 deletions

View File

@@ -34,6 +34,7 @@ All (GUI):
- Send events when toggling wxPropertyGrid nodes from keyboard (Armel Asselin). - Send events when toggling wxPropertyGrid nodes from keyboard (Armel Asselin).
- Fix wxRearrangeList::Check() which asserted and misbehaved before. - Fix wxRearrangeList::Check() which asserted and misbehaved before.
- Optimized wxRTC insertion and deletion when floating objects are present. - Optimized wxRTC insertion and deletion when floating objects are present.
- Added on-demand image loading option to wxRTC.
wxGTK: wxGTK:

View File

@@ -2211,7 +2211,8 @@ public:
*/ */
wxRichTextDrawingContext(wxRichTextBuffer* buffer); wxRichTextDrawingContext(wxRichTextBuffer* buffer);
void Init() { m_buffer = NULL; m_enableVirtualAttributes = true; m_enableImages = true; m_layingOut = false; } void Init()
{ m_buffer = NULL; m_enableVirtualAttributes = true; m_enableImages = true; m_layingOut = false; m_enableDelayedImageLoading = false; }
/** /**
Does this object have virtual attributes? Does this object have virtual attributes?
@@ -2293,9 +2294,22 @@ public:
bool GetLayingOut() const { return m_layingOut; } bool GetLayingOut() const { return m_layingOut; }
/**
Enable or disable delayed image loading
*/
void EnableDelayedImageLoading(bool b) { m_enableDelayedImageLoading = b; }
/**
Returns @true if delayed image loading is enabled.
*/
bool GetDelayedImageLoading() const { return m_enableDelayedImageLoading; }
wxRichTextBuffer* m_buffer; wxRichTextBuffer* m_buffer;
bool m_enableVirtualAttributes; bool m_enableVirtualAttributes;
bool m_enableImages; bool m_enableImages;
bool m_enableDelayedImageLoading;
bool m_layingOut; bool m_layingOut;
}; };
@@ -2428,7 +2442,6 @@ public:
virtual bool Merge(wxRichTextObject* WXUNUSED(object), wxRichTextDrawingContext& WXUNUSED(context)) { return false; } virtual bool Merge(wxRichTextObject* WXUNUSED(object), wxRichTextDrawingContext& WXUNUSED(context)) { return false; }
/** /**
JACS
Returns @true if this object can potentially be split, by virtue of having Returns @true if this object can potentially be split, by virtue of having
different virtual attributes for individual sub-objects. different virtual attributes for individual sub-objects.
*/ */
@@ -4742,6 +4755,8 @@ class WXDLLIMPEXP_RICHTEXT wxRichTextImage: public wxRichTextObject
{ {
DECLARE_DYNAMIC_CLASS(wxRichTextImage) DECLARE_DYNAMIC_CLASS(wxRichTextImage)
public: public:
enum { ImageState_Unloaded, ImageState_Loaded, ImageState_Bad };
// Constructors // Constructors
/** /**
@@ -4824,12 +4839,12 @@ public:
/** /**
Sets the image cache. Sets the image cache.
*/ */
void SetImageCache(const wxBitmap& bitmap) { m_imageCache = bitmap; m_originalImageSize = wxSize(bitmap.GetWidth(), bitmap.GetHeight()); } void SetImageCache(const wxBitmap& bitmap) { m_imageCache = bitmap; m_originalImageSize = wxSize(bitmap.GetWidth(), bitmap.GetHeight()); m_imageState = ImageState_Loaded; }
/** /**
Resets the image cache. Resets the image cache.
*/ */
void ResetImageCache() { m_imageCache = wxNullBitmap; m_originalImageSize = wxSize(-1, -1); } void ResetImageCache() { m_imageCache = wxNullBitmap; m_originalImageSize = wxSize(-1, -1); m_imageState = ImageState_Unloaded; }
/** /**
Returns the image block containing the raw data. Returns the image block containing the raw data.
@@ -4851,7 +4866,12 @@ public:
/** /**
Creates a cached image at the required size. Creates a cached image at the required size.
*/ */
virtual bool LoadImageCache(wxDC& dc, wxRichTextDrawingContext& context, bool resetCache = false, const wxSize& parentSize = wxDefaultSize); virtual bool LoadImageCache(wxDC& dc, wxRichTextDrawingContext& context, wxSize& retImageSize, bool resetCache = false, const wxSize& parentSize = wxDefaultSize);
/**
Do the loading and scaling
*/
virtual bool LoadAndScaleImageCache(wxImage& image, const wxSize& sz, bool delayLoading, bool& changed);
/** /**
Gets the original image size. Gets the original image size.
@@ -4863,10 +4883,21 @@ public:
*/ */
void SetOriginalImageSize(const wxSize& sz) { m_originalImageSize = sz; } void SetOriginalImageSize(const wxSize& sz) { m_originalImageSize = sz; }
/**
Gets the image state.
*/
int GetImageState() const { return m_imageState; }
/**
Sets the image state.
*/
void SetImageState(int state) { m_imageState = state; }
protected: protected:
wxRichTextImageBlock m_imageBlock; wxRichTextImageBlock m_imageBlock;
wxBitmap m_imageCache; wxBitmap m_imageCache;
wxSize m_originalImageSize; wxSize m_originalImageSize;
int m_imageState;
}; };
class WXDLLIMPEXP_FWD_RICHTEXT wxRichTextCommand; class WXDLLIMPEXP_FWD_RICHTEXT wxRichTextCommand;

View File

@@ -17,7 +17,7 @@
#include "wx/scrolwin.h" #include "wx/scrolwin.h"
#include "wx/caret.h" #include "wx/caret.h"
#include "wx/timer.h"
#include "wx/textctrl.h" #include "wx/textctrl.h"
#if wxUSE_DRAG_AND_DROP #if wxUSE_DRAG_AND_DROP
@@ -79,6 +79,8 @@ class WXDLLIMPEXP_FWD_RICHTEXT wxRichTextStyleDefinition;
#define wxRICHTEXT_DEFAULT_DELAYED_LAYOUT_THRESHOLD 20000 #define wxRICHTEXT_DEFAULT_DELAYED_LAYOUT_THRESHOLD 20000
// Milliseconds before layout occurs after resize // Milliseconds before layout occurs after resize
#define wxRICHTEXT_DEFAULT_LAYOUT_INTERVAL 50 #define wxRICHTEXT_DEFAULT_LAYOUT_INTERVAL 50
// Milliseconds before delayed image processing occurs
#define wxRICHTEXT_DEFAULT_DELAYED_IMAGE_PROCESSING_INTERVAL 200
/* Identifiers /* Identifiers
*/ */
@@ -1980,6 +1982,12 @@ public:
*/ */
bool RefreshForSelectionChange(const wxRichTextSelection& oldSelection, const wxRichTextSelection& newSelection); bool RefreshForSelectionChange(const wxRichTextSelection& oldSelection, const wxRichTextSelection& newSelection);
/**
Overrides standard refresh in order to provoke delayed image loading.
*/
virtual void Refresh( bool eraseBackground = true,
const wxRect *rect = (const wxRect *) NULL );
/** /**
Sets the caret position. Sets the caret position.
@@ -2134,6 +2142,38 @@ public:
bool GetImagesEnabled() const { return m_enableImages; } bool GetImagesEnabled() const { return m_enableImages; }
/**
Enable or disable delayed image loading
*/
void EnableDelayedImageLoading(bool b) { m_enableDelayedImageLoading = b; }
/**
Returns @true if delayed image loading is enabled.
*/
bool GetDelayedImageLoading() const { return m_enableDelayedImageLoading; }
/**
Gets the flag indicating that delayed image processing is required.
*/
bool GetDelayedImageProcessingRequired() const { return m_delayedImageProcessingRequired; }
/**
Sets the flag indicating that delayed image processing is required.
*/
void SetDelayedImageProcessingRequired(bool b) { m_delayedImageProcessingRequired = b; }
/**
Returns the last time delayed image processing was performed.
*/
wxLongLong GetDelayedImageProcessingTime() const { return m_delayedImageProcessingTime; }
/**
Sets the last time delayed image processing was performed.
*/
void SetDelayedImageProcessingTime(wxLongLong t) { m_delayedImageProcessingTime = t; }
#ifdef DOXYGEN #ifdef DOXYGEN
/** /**
Returns the content of the entire control as a string. Returns the content of the entire control as a string.
@@ -2209,6 +2249,22 @@ public:
// implement wxTextEntry methods // implement wxTextEntry methods
virtual wxString DoGetValue() const; virtual wxString DoGetValue() const;
/**
Do delayed image loading and garbage-collect other images
*/
bool ProcessDelayedImageLoading(bool refresh);
bool ProcessDelayedImageLoading(const wxRect& screenRect, wxRichTextParagraphLayoutBox* box, int& loadCount);
/**
Request delayed image processing.
*/
void RequestDelayedImageProcessing();
/**
Respond to timer events.
*/
void OnTimer(wxTimerEvent& event);
protected: protected:
// implement the wxTextEntry pure virtual method // implement the wxTextEntry pure virtual method
virtual wxWindow *GetEditableWindow() { return this; } virtual wxWindow *GetEditableWindow() { return this; }
@@ -2336,6 +2392,12 @@ protected:
/// Whether images are enabled for this control /// Whether images are enabled for this control
bool m_enableImages; bool m_enableImages;
/// Whether delayed image loading is enabled for this control
bool m_enableDelayedImageLoading;
bool m_delayedImageProcessingRequired;
wxLongLong m_delayedImageProcessingTime;
wxTimer m_delayedImageProcessingTimer;
}; };
#if wxUSE_DRAG_AND_DROP #if wxUSE_DRAG_AND_DROP

View File

@@ -2123,9 +2123,35 @@ public:
bool GetImagesEnabled() const { return m_enableImages; } bool GetImagesEnabled() const { return m_enableImages; }
/**
Set laying out flag
*/
void SetLayingOut(bool b) { m_layingOut = b; }
/**
Returns @true if laying out.
*/
bool GetLayingOut() const { return m_layingOut; }
/**
Enable or disable delayed image loading
*/
void EnableDelayedImageLoading(bool b) { m_enableDelayedImageLoading = b; }
/**
Returns @true if delayed image loading is enabled.
*/
bool GetDelayedImageLoading() const { return m_enableDelayedImageLoading; }
wxRichTextBuffer* m_buffer; wxRichTextBuffer* m_buffer;
bool m_enableVirtualAttributes; bool m_enableVirtualAttributes;
bool m_enableImages; bool m_enableImages;
bool m_enableDelayedImageLoading;
bool m_layingOut;
}; };
/** /**
@@ -4671,11 +4697,38 @@ public:
/** /**
Creates a cached image at the required size. Creates a cached image at the required size.
*/ */
virtual bool LoadImageCache(wxDC& dc, wxRichTextDrawingContext& context, bool resetCache = false, const wxSize& parentSize = wxDefaultSize); virtual bool LoadImageCache(wxDC& dc, wxRichTextDrawingContext& context, wxSize& retImageSize, bool resetCache = false, const wxSize& parentSize = wxDefaultSize);
/**
Do the loading and scaling
*/
virtual bool LoadAndScaleImageCache(wxImage& image, const wxSize& sz, bool delayLoading, bool& changed);
/**
Gets the original image size.
*/
wxSize GetOriginalImageSize() const { return m_originalImageSize; }
/**
Sets the original image size.
*/
void SetOriginalImageSize(const wxSize& sz) { m_originalImageSize = sz; }
/**
Gets the image state.
*/
int GetImageState() const { return m_imageState; }
/**
Sets the image state.
*/
void SetImageState(int state) { m_imageState = state; }
protected: protected:
wxRichTextImageBlock m_imageBlock; wxRichTextImageBlock m_imageBlock;
wxBitmap m_imageCache; wxBitmap m_imageCache;
wxSize m_originalImageSize;
int m_imageState;
}; };
class wxRichTextCommand; class wxRichTextCommand;

View File

@@ -55,6 +55,8 @@
#define wxRICHTEXT_DEFAULT_DELAYED_LAYOUT_THRESHOLD 20000 #define wxRICHTEXT_DEFAULT_DELAYED_LAYOUT_THRESHOLD 20000
// Milliseconds before layout occurs after resize // Milliseconds before layout occurs after resize
#define wxRICHTEXT_DEFAULT_LAYOUT_INTERVAL 50 #define wxRICHTEXT_DEFAULT_LAYOUT_INTERVAL 50
// Milliseconds before delayed image processing occurs
#define wxRICHTEXT_DEFAULT_DELAYED_IMAGE_PROCESSING_INTERVAL 200
/* Identifiers /* Identifiers
*/ */
@@ -2044,6 +2046,38 @@ public:
bool GetImagesEnabled() const; bool GetImagesEnabled() const;
/**
Enable or disable delayed image loading
*/
void EnableDelayedImageLoading(bool b) { m_enableDelayedImageLoading = b; }
/**
Returns @true if delayed image loading is enabled.
*/
bool GetDelayedImageLoading() const { return m_enableDelayedImageLoading; }
/**
Gets the flag indicating that delayed image processing is required.
*/
bool GetDelayedImageProcessingRequired() const { return m_delayedImageProcessingRequired; }
/**
Sets the flag indicating that delayed image processing is required.
*/
void SetDelayedImageProcessingRequired(bool b) { m_delayedImageProcessingRequired = b; }
/**
Returns the last time delayed image processing was performed.
*/
wxLongLong GetDelayedImageProcessingTime() const { return m_delayedImageProcessingTime; }
/**
Sets the last time delayed image processing was performed.
*/
void SetDelayedImageProcessingTime(wxLongLong t) { m_delayedImageProcessingTime = t; }
/** /**
Returns the caret position since the default formatting was changed. As Returns the caret position since the default formatting was changed. As
soon as this position changes, we no longer reflect the default style soon as this position changes, we no longer reflect the default style
@@ -2137,6 +2171,22 @@ public:
// implement wxTextEntry methods // implement wxTextEntry methods
virtual wxString DoGetValue() const; virtual wxString DoGetValue() const;
/**
Do delayed image loading and garbage-collect other images
*/
bool ProcessDelayedImageLoading(bool refresh);
bool ProcessDelayedImageLoading(const wxRect& screenRect, wxRichTextParagraphLayoutBox* box, int& loadCount);
/**
Request delayed image processing.
*/
void RequestDelayedImageProcessing();
/**
Respond to timer events.
*/
void OnTimer(wxTimerEvent& event);
protected: protected:
// implement the wxTextEntry pure virtual method // implement the wxTextEntry pure virtual method
virtual wxWindow *GetEditableWindow(); virtual wxWindow *GetEditableWindow();
@@ -2220,6 +2270,23 @@ protected:
/// The object that currently has the editing focus /// The object that currently has the editing focus
wxRichTextParagraphLayoutBox* m_focusObject; wxRichTextParagraphLayoutBox* m_focusObject;
/// An overall scale factor
double m_scale;
/// Variables for scrollbar hysteresis detection
wxSize m_lastWindowSize;
int m_setupScrollbarsCount;
int m_setupScrollbarsCountInOnSize;
/// Whether images are enabled for this control
bool m_enableImages;
/// Whether delayed image loading is enabled for this control
bool m_enableDelayedImageLoading;
bool m_delayedImageProcessingRequired;
wxLongLong m_delayedImageProcessingTime;
wxTimer m_delayedImageProcessingTimer;
}; };
/** /**

View File

@@ -5150,7 +5150,8 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
} }
while (doLoop); while (doLoop);
if (child->IsTopLevel()) // 2014-03-08: also need to set object positions
//if (child->IsTopLevel())
{ {
// We can move it to the correct position at this point // We can move it to the correct position at this point
// TODO: probably need to add margin // TODO: probably need to add margin
@@ -12213,17 +12214,24 @@ wxRichTextImage::~wxRichTextImage()
void wxRichTextImage::Init() void wxRichTextImage::Init()
{ {
m_originalImageSize = wxSize(-1, -1); m_originalImageSize = wxSize(-1, -1);
m_imageState = ImageState_Unloaded;
} }
/// Create a cached image at the required size /// Create a cached image at the required size
bool wxRichTextImage::LoadImageCache(wxDC& dc, wxRichTextDrawingContext& context, bool resetCache, const wxSize& parentSize) bool wxRichTextImage::LoadImageCache(wxDC& dc, wxRichTextDrawingContext& context, wxSize& retImageSize, bool resetCache, const wxSize& parentSize)
{ {
if (!m_imageBlock.IsOk()) if (!m_imageBlock.IsOk())
{
m_imageState = ImageState_Bad;
return false; return false;
}
// Don't repeat unless absolutely necessary // Don't repeat unless absolutely necessary
if (m_imageCache.IsOk() && !resetCache && !context.GetLayingOut()) if (m_imageCache.IsOk() && !resetCache && !context.GetLayingOut())
{
retImageSize = wxSize(m_imageCache.GetWidth(), m_imageCache.GetHeight());
return true; return true;
}
if (!context.GetImagesEnabled()) if (!context.GetImagesEnabled())
{ {
@@ -12231,7 +12239,9 @@ bool wxRichTextImage::LoadImageCache(wxDC& dc, wxRichTextDrawingContext& context
{ {
wxBitmap bitmap(image_placeholder24x24_xpm); wxBitmap bitmap(image_placeholder24x24_xpm);
m_imageCache = bitmap; m_imageCache = bitmap;
m_imageState = ImageState_Loaded;
} }
retImageSize = wxSize(m_imageCache.GetWidth(), m_imageCache.GetHeight());
return true; return true;
} }
@@ -12243,13 +12253,15 @@ bool wxRichTextImage::LoadImageCache(wxDC& dc, wxRichTextDrawingContext& context
if (resetCache || m_originalImageSize.GetWidth() <= 0 || m_originalImageSize.GetHeight() <= 0) if (resetCache || m_originalImageSize.GetWidth() <= 0 || m_originalImageSize.GetHeight() <= 0)
{ {
m_imageCache = wxNullBitmap; m_imageCache = wxNullBitmap;
m_imageState = ImageState_Unloaded;
m_imageBlock.Load(image); if (!m_imageBlock.Load(image) || !image.IsOk())
if (!image.IsOk())
{ {
wxBitmap bitmap(image_placeholder24x24_xpm); wxBitmap bitmap(image_placeholder24x24_xpm);
m_imageCache = bitmap; m_imageCache = bitmap;
m_originalImageSize = wxSize(bitmap.GetWidth(), bitmap.GetHeight()); m_originalImageSize = wxSize(bitmap.GetWidth(), bitmap.GetHeight());
m_imageState = ImageState_Bad;
retImageSize = wxSize(m_imageCache.GetWidth(), m_imageCache.GetHeight());
return false; return false;
} }
@@ -12359,24 +12371,49 @@ bool wxRichTextImage::LoadImageCache(wxDC& dc, wxRichTextDrawingContext& context
width = wxMax(1, width); width = wxMax(1, width);
height = wxMax(1, height); height = wxMax(1, height);
retImageSize = wxSize(width, height);
bool changed = false;
return LoadAndScaleImageCache(image, retImageSize, context.GetDelayedImageLoading(), changed);
}
// Do the loading and scaling
bool wxRichTextImage::LoadAndScaleImageCache(wxImage& image, const wxSize& sz, bool delayLoading, bool& changed)
{
int width = sz.x;
int height = sz.y;
if (m_imageCache.IsOk() && m_imageCache.GetWidth() == width && m_imageCache.GetHeight() == height) if (m_imageCache.IsOk() && m_imageCache.GetWidth() == width && m_imageCache.GetHeight() == height)
{ {
// Do nothing, we didn't need to change the image cache // Do nothing, we didn't need to change the image cache
changed = false;
} }
else else
{ {
changed = true;
if (delayLoading)
{
if (m_imageCache.IsOk())
m_imageCache = wxNullBitmap;
m_imageState = ImageState_Unloaded;
return true;
}
if (!image.IsOk()) if (!image.IsOk())
{ {
m_imageBlock.Load(image); if (!m_imageBlock.Load(image) || !image.IsOk())
if (!image.IsOk())
{ {
wxBitmap bitmap(image_placeholder24x24_xpm); wxBitmap bitmap(image_placeholder24x24_xpm);
m_imageCache = bitmap; m_imageCache = bitmap;
m_originalImageSize = wxSize(bitmap.GetWidth(), bitmap.GetHeight()); m_originalImageSize = wxSize(bitmap.GetWidth(), bitmap.GetHeight());
m_imageState = ImageState_Bad;
return false; return false;
} }
} }
m_originalImageSize = wxSize(image.GetWidth(), image.GetHeight());
if (image.GetWidth() == width && image.GetHeight() == height) if (image.GetWidth() == width && image.GetHeight() == height)
m_imageCache = wxBitmap(image); m_imageCache = wxBitmap(image);
else else
@@ -12397,6 +12434,11 @@ bool wxRichTextImage::LoadImageCache(wxDC& dc, wxRichTextDrawingContext& context
} }
} }
if (m_imageCache.IsOk())
m_imageState = ImageState_Loaded;
else
m_imageState = ImageState_Bad;
return m_imageCache.IsOk(); return m_imageCache.IsOk();
} }
@@ -12406,9 +12448,6 @@ bool wxRichTextImage::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wx
if (!IsShown()) if (!IsShown())
return true; return true;
if (!m_imageCache.IsOk())
return false;
wxRichTextAttr attr(GetAttributes()); wxRichTextAttr attr(GetAttributes());
AdjustAttributes(attr, context); AdjustAttributes(attr, context);
@@ -12419,7 +12458,14 @@ bool wxRichTextImage::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wx
marginRect = rect; // outer rectangle, will calculate contentRect marginRect = rect; // outer rectangle, will calculate contentRect
GetBoxRects(dc, GetBuffer(), attr, marginRect, borderRect, contentRect, paddingRect, outlineRect); GetBoxRects(dc, GetBuffer(), attr, marginRect, borderRect, contentRect, paddingRect, outlineRect);
if (m_imageCache.IsOk())
dc.DrawBitmap(m_imageCache, contentRect.x, contentRect.y, true); dc.DrawBitmap(m_imageCache, contentRect.x, contentRect.y, true);
else
{
dc.SetPen(*wxLIGHT_GREY_PEN);
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRectangle(contentRect);
}
if (selection.WithinSelection(GetRange().GetStart(), this)) if (selection.WithinSelection(GetRange().GetStart(), this))
{ {
@@ -12436,10 +12482,10 @@ bool wxRichTextImage::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wx
/// Lay the item out /// Lay the item out
bool wxRichTextImage::Layout(wxDC& dc, wxRichTextDrawingContext& context, const wxRect& rect, const wxRect& parentRect, int WXUNUSED(style)) bool wxRichTextImage::Layout(wxDC& dc, wxRichTextDrawingContext& context, const wxRect& rect, const wxRect& parentRect, int WXUNUSED(style))
{ {
if (!LoadImageCache(dc, context, false, parentRect.GetSize())) wxSize imageSize;
if (!LoadImageCache(dc, context, imageSize, false, parentRect.GetSize()))
return false; return false;
wxSize imageSize(m_imageCache.GetWidth(), m_imageCache.GetHeight());
wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect; wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect;
contentRect = wxRect(wxPoint(0,0), imageSize); contentRect = wxRect(wxPoint(0,0), imageSize);
@@ -12465,7 +12511,8 @@ bool wxRichTextImage::GetRangeSize(const wxRichTextRange& range, wxSize& size, i
if (!range.IsWithin(GetRange())) if (!range.IsWithin(GetRange()))
return false; return false;
if (!((wxRichTextImage*)this)->LoadImageCache(dc, context, false, parentSize)) wxSize imageSize;
if (!((wxRichTextImage*)this)->LoadImageCache(dc, context, imageSize, false, parentSize))
{ {
size.x = 0; size.y = 0; size.x = 0; size.y = 0;
if (partialExtents) if (partialExtents)
@@ -12476,7 +12523,6 @@ bool wxRichTextImage::GetRangeSize(const wxRichTextRange& range, wxSize& size, i
wxRichTextAttr attr(GetAttributes()); wxRichTextAttr attr(GetAttributes());
((wxRichTextObject*)this)->AdjustAttributes(attr, context); ((wxRichTextObject*)this)->AdjustAttributes(attr, context);
wxSize imageSize(m_imageCache.GetWidth(), m_imageCache.GetHeight());
wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect; wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect;
contentRect = wxRect(wxPoint(0,0), imageSize); contentRect = wxRect(wxPoint(0,0), imageSize);
GetBoxRects(dc, GetBuffer(), attr, marginRect, borderRect, contentRect, paddingRect, outlineRect); GetBoxRects(dc, GetBuffer(), attr, marginRect, borderRect, contentRect, paddingRect, outlineRect);
@@ -15040,6 +15086,7 @@ wxRichTextDrawingContext::wxRichTextDrawingContext(wxRichTextBuffer* buffer)
{ {
EnableVirtualAttributes(m_buffer->GetRichTextCtrl()->GetVirtualAttributesEnabled()); EnableVirtualAttributes(m_buffer->GetRichTextCtrl()->GetVirtualAttributesEnabled());
m_enableImages = m_buffer->GetRichTextCtrl()->GetImagesEnabled(); m_enableImages = m_buffer->GetRichTextCtrl()->GetImagesEnabled();
m_enableDelayedImageLoading = m_buffer->GetRichTextCtrl()->GetDelayedImageLoading();
} }
} }

View File

@@ -177,6 +177,7 @@ BEGIN_EVENT_TABLE( wxRichTextCtrl, wxControl )
EVT_MOUSE_CAPTURE_LOST(wxRichTextCtrl::OnCaptureLost) EVT_MOUSE_CAPTURE_LOST(wxRichTextCtrl::OnCaptureLost)
EVT_CONTEXT_MENU(wxRichTextCtrl::OnContextMenu) EVT_CONTEXT_MENU(wxRichTextCtrl::OnContextMenu)
EVT_SYS_COLOUR_CHANGED(wxRichTextCtrl::OnSysColourChanged) EVT_SYS_COLOUR_CHANGED(wxRichTextCtrl::OnSysColourChanged)
EVT_TIMER(wxID_ANY, wxRichTextCtrl::OnTimer)
EVT_MENU(wxID_UNDO, wxRichTextCtrl::OnUndo) EVT_MENU(wxID_UNDO, wxRichTextCtrl::OnUndo)
EVT_UPDATE_UI(wxID_UNDO, wxRichTextCtrl::OnUpdateUndo) EVT_UPDATE_UI(wxID_UNDO, wxRichTextCtrl::OnUpdateUndo)
@@ -350,6 +351,8 @@ wxRichTextCtrl::~wxRichTextCtrl()
GetBuffer().RemoveEventHandler(this); GetBuffer().RemoveEventHandler(this);
delete m_contextMenu; delete m_contextMenu;
m_delayedImageProcessingTimer.Stop();
} }
/// Member initialisation /// Member initialisation
@@ -382,6 +385,10 @@ void wxRichTextCtrl::Init()
m_setupScrollbarsCountInOnSize = 0; m_setupScrollbarsCountInOnSize = 0;
m_enableImages = true; m_enableImages = true;
m_enableDelayedImageLoading = false;
m_delayedImageProcessingRequired = false;
m_delayedImageProcessingTime = 0;
} }
void wxRichTextCtrl::DoThaw() void wxRichTextCtrl::DoThaw()
@@ -2602,6 +2609,9 @@ void wxRichTextCtrl::OnSize(wxSizeEvent& event)
// OnSize was the source of a scrollbar change. // OnSize was the source of a scrollbar change.
m_setupScrollbarsCountInOnSize = m_setupScrollbarsCount; m_setupScrollbarsCountInOnSize = m_setupScrollbarsCount;
if (GetDelayedImageLoading())
RequestDelayedImageProcessing();
event.Skip(); event.Skip();
} }
@@ -2642,6 +2652,16 @@ void wxRichTextCtrl::OnIdle(wxIdleEvent& event)
Refresh(false); Refresh(false);
} }
const int imageProcessingInterval = wxRICHTEXT_DEFAULT_DELAYED_IMAGE_PROCESSING_INTERVAL;
if (m_enableDelayedImageLoading && m_delayedImageProcessingRequired && (wxGetLocalTimeMillis() > (m_delayedImageProcessingTime + imageProcessingInterval)))
{
m_delayedImageProcessingTimer.Stop();
m_delayedImageProcessingRequired = false;
m_delayedImageProcessingTime = 0;
ProcessDelayedImageLoading(true);
}
if (m_caretPositionForDefaultStyle != -2) if (m_caretPositionForDefaultStyle != -2)
{ {
// If the caret position has changed, no longer reflect the default style // If the caret position has changed, no longer reflect the default style
@@ -4045,6 +4065,9 @@ bool wxRichTextCtrl::LayoutContent(bool onlyVisibleRect)
if (!IsFrozen() && !onlyVisibleRect) if (!IsFrozen() && !onlyVisibleRect)
SetupScrollbars(); SetupScrollbars();
if (GetDelayedImageLoading())
RequestDelayedImageProcessing();
} }
return true; return true;
@@ -4668,6 +4691,15 @@ bool wxRichTextCtrl::RefreshForSelectionChange(const wxRichTextSelection& oldSel
return true; return true;
} }
// Overrides standard refresh in order to provoke delayed image loading.
void wxRichTextCtrl::Refresh( bool eraseBackground, const wxRect *rect)
{
if (GetDelayedImageLoading())
RequestDelayedImageProcessing();
wxWindow::Refresh(eraseBackground, rect);
}
// margins functions // margins functions
bool wxRichTextCtrl::DoSetMargins(const wxPoint& pt) bool wxRichTextCtrl::DoSetMargins(const wxPoint& pt)
{ {
@@ -4906,6 +4938,112 @@ wxRect wxRichTextCtrl::GetScaledRect(const wxRect& rect) const
(int) (0.5 + double(rect.width) * GetScale()), (int) (0.5 + double(rect.height) * GetScale())); (int) (0.5 + double(rect.width) * GetScale()), (int) (0.5 + double(rect.height) * GetScale()));
} }
// Do delayed image loading and garbage-collect other images
bool wxRichTextCtrl::ProcessDelayedImageLoading(bool refresh)
{
int loadCount = 0;
wxSize clientSize = GetUnscaledSize(GetClientSize());
wxPoint firstVisiblePt = GetUnscaledPoint(GetFirstVisiblePoint());
wxRect screenRect(firstVisiblePt, clientSize);
// Expand screen rect so that we actually process images in the vicinity,
// for smoother paging and scrolling.
screenRect.y -= (clientSize.y*3);
screenRect.height += (clientSize.y*6);
ProcessDelayedImageLoading(screenRect, & GetBuffer(), loadCount);
if (loadCount > 0 && refresh)
{
wxWindow::Refresh(false);
}
return loadCount > 0;
}
bool wxRichTextCtrl::ProcessDelayedImageLoading(const wxRect& screenRect, wxRichTextParagraphLayoutBox* box, int& loadCount)
{
if (!box || !box->IsShown())
return true;
wxRichTextObjectList::compatibility_iterator node = box->GetChildren().GetFirst();
while (node)
{
// Could be a cell or a paragraph
wxRichTextCompositeObject* composite = wxDynamicCast(node->GetData(), wxRichTextCompositeObject);
if (composite->IsTopLevel())
ProcessDelayedImageLoading(screenRect, wxDynamicCast(composite, wxRichTextParagraphLayoutBox), loadCount);
else // assume a paragraph
{
wxRichTextObjectList::compatibility_iterator node2 = composite->GetChildren().GetFirst();
while (node2)
{
wxRichTextObject* obj = node2->GetData();
if (obj->IsTopLevel())
ProcessDelayedImageLoading(screenRect, wxDynamicCast(obj, wxRichTextParagraphLayoutBox), loadCount);
else
{
wxRichTextImage* imageObj = wxDynamicCast(obj, wxRichTextImage);
if (imageObj && imageObj->IsShown())
{
const wxRect& rect(imageObj->GetRect());
if ((rect.GetBottom() < screenRect.GetTop()) || (rect.GetTop() > screenRect.GetBottom()))
{
// Off-screen
imageObj->ResetImageCache();
}
else
{
// On-screen
wxRichTextDrawingContext context(& GetBuffer());
context.SetLayingOut(true);
context.EnableDelayedImageLoading(false);
wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect;
marginRect = imageObj->GetRect(); // outer rectangle, will calculate contentRect
if (marginRect.GetSize() != wxDefaultSize)
{
wxClientDC dc(this);
wxRichTextAttr attr(imageObj->GetAttributes());
imageObj->AdjustAttributes(attr, context);
imageObj->GetBoxRects(dc, & GetBuffer(), attr, marginRect, borderRect, contentRect, paddingRect, outlineRect);
wxImage image;
bool changed = false;
if (imageObj->LoadAndScaleImageCache(image, contentRect.GetSize(), false, changed) && changed)
{
loadCount ++;
}
}
}
}
}
node2 = node2->GetNext();
}
}
node = node->GetNext();
}
return true;
}
void wxRichTextCtrl::RequestDelayedImageProcessing()
{
SetDelayedImageProcessingRequired(true);
SetDelayedImageProcessingTime(wxGetLocalTimeMillis());
m_delayedImageProcessingTimer.SetOwner(this, GetId());
m_delayedImageProcessingTimer.Start(wxRICHTEXT_DEFAULT_DELAYED_IMAGE_PROCESSING_INTERVAL);
}
void wxRichTextCtrl::OnTimer(wxTimerEvent& event)
{
if (event.GetId() == GetId())
wxWakeUpIdle();
else
event.Skip();
}
#if wxRICHTEXT_USE_OWN_CARET #if wxRICHTEXT_USE_OWN_CARET
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------