1///////////////////////////////////////////////////////////////////////////// 2// Name: wx/dcbuffer.h 3// Purpose: wxBufferedDC class 4// Author: Ron Lee <ron@debian.org> 5// Modified by: Vadim Zeitlin (refactored, added bg preservation) 6// Created: 16/03/02 7// RCS-ID: $Id: dcbuffer.h 61872 2009-09-09 22:37:05Z VZ $ 8// Copyright: (c) Ron Lee 9// Licence: wxWindows licence 10///////////////////////////////////////////////////////////////////////////// 11 12#ifndef _WX_DCBUFFER_H_ 13#define _WX_DCBUFFER_H_ 14 15#include "wx/dcmemory.h" 16#include "wx/dcclient.h" 17#include "wx/window.h" 18 19// Split platforms into two groups - those which have well-working 20// double-buffering by default, and those which do not. 21#if defined(__WXMAC__) || defined(__WXGTK20__) || defined(__WXDFB__) 22 #define wxALWAYS_NATIVE_DOUBLE_BUFFER 1 23#else 24 #define wxALWAYS_NATIVE_DOUBLE_BUFFER 0 25#endif 26 27 28// ---------------------------------------------------------------------------- 29// Double buffering helper. 30// ---------------------------------------------------------------------------- 31 32// Assumes the buffer bitmap covers the entire scrolled window, 33// and prepares the window DC accordingly 34#define wxBUFFER_VIRTUAL_AREA 0x01 35 36// Assumes the buffer bitmap only covers the client area; 37// does not prepare the window DC 38#define wxBUFFER_CLIENT_AREA 0x02 39 40class WXDLLEXPORT wxBufferedDC : public wxMemoryDC 41{ 42public: 43 // Default ctor, must subsequently call Init for two stage construction. 44 wxBufferedDC() 45 : m_dc(NULL), 46 m_buffer(NULL), 47 m_style(0) 48 { 49 } 50 51 // Construct a wxBufferedDC using a user supplied buffer. 52 wxBufferedDC(wxDC *dc, 53 wxBitmap& buffer = wxNullBitmap, 54 int style = wxBUFFER_CLIENT_AREA) 55 : m_dc(NULL), m_buffer(NULL) 56 { 57 Init(dc, buffer, style); 58 } 59 60 // Construct a wxBufferedDC with an internal buffer of 'area' 61 // (where area is usually something like the size of the window 62 // being buffered) 63 wxBufferedDC(wxDC *dc, const wxSize& area, int style = wxBUFFER_CLIENT_AREA) 64 : m_dc(NULL), m_buffer(NULL) 65 { 66 Init(dc, area, style); 67 } 68 69 // The usually desired action in the dtor is to blit the buffer. 70 virtual ~wxBufferedDC() 71 { 72 if ( m_dc ) 73 UnMask(); 74 } 75 76 // These reimplement the actions of the ctors for two stage creation 77 void Init(wxDC *dc, 78 wxBitmap& buffer = wxNullBitmap, 79 int style = wxBUFFER_CLIENT_AREA) 80 { 81 InitCommon(dc, style); 82 83 m_buffer = &buffer; 84 85 UseBuffer(); 86 } 87 88 void Init(wxDC *dc, const wxSize &area, int style = wxBUFFER_CLIENT_AREA) 89 { 90 InitCommon(dc, style); 91 92 UseBuffer(area.x, area.y); 93 } 94 95 // Blits the buffer to the dc, and detaches the dc from the buffer (so it 96 // can be effectively used once only). 97 // 98 // Usually called in the dtor or by the dtor of derived classes if the 99 // BufferedDC must blit before the derived class (which may own the dc it's 100 // blitting to) is destroyed. 101 void UnMask() 102 { 103 wxCHECK_RET( m_dc, wxT("no underlying wxDC?") ); 104 wxASSERT_MSG( m_buffer && m_buffer->IsOk(), wxT("invalid backing store") ); 105 106 wxCoord x = 0, 107 y = 0; 108 109 if ( m_style & wxBUFFER_CLIENT_AREA ) 110 GetDeviceOrigin(&x, &y); 111 112 m_dc->Blit(0, 0, m_buffer->GetWidth(), m_buffer->GetHeight(), 113 this, -x, -y ); 114 m_dc = NULL; 115 } 116 117 // Set and get the style 118 void SetStyle(int style) { m_style = style; } 119 int GetStyle() const { return m_style; } 120 121private: 122 // common part of Init()s 123 void InitCommon(wxDC *dc, int style) 124 { 125 wxASSERT_MSG( !m_dc, wxT("wxBufferedDC already initialised") ); 126 127 m_dc = dc; 128 m_style = style; 129 130 // inherit the same layout direction as the original DC 131 if (dc && dc->IsOk()) 132 SetLayoutDirection(dc->GetLayoutDirection()); 133 } 134 135 // check that the bitmap is valid and use it 136 void UseBuffer(wxCoord w = -1, wxCoord h = -1); 137 138 // the underlying DC to which we copy everything drawn on this one in 139 // UnMask() 140 // 141 // NB: Without the existence of a wxNullDC, this must be a pointer, else it 142 // could probably be a reference. 143 wxDC *m_dc; 144 145 // the buffer (selected in this DC), initially invalid 146 wxBitmap *m_buffer; 147 148 // the buffering style 149 int m_style; 150 151 DECLARE_DYNAMIC_CLASS(wxBufferedDC) 152 DECLARE_NO_COPY_CLASS(wxBufferedDC) 153}; 154 155 156// ---------------------------------------------------------------------------- 157// Double buffered PaintDC. 158// ---------------------------------------------------------------------------- 159 160// Creates a double buffered wxPaintDC, optionally allowing the 161// user to specify their own buffer to use. 162class WXDLLEXPORT wxBufferedPaintDC : public wxBufferedDC 163{ 164public: 165 // If no bitmap is supplied by the user, a temporary one will be created. 166 wxBufferedPaintDC(wxWindow *window, wxBitmap& buffer, int style = wxBUFFER_CLIENT_AREA) 167 : m_paintdc(window) 168 { 169 // If we're buffering the virtual window, scale the paint DC as well 170 if (style & wxBUFFER_VIRTUAL_AREA) 171 window->PrepareDC( m_paintdc ); 172 173 if( buffer.IsOk() ) 174 Init(&m_paintdc, buffer, style); 175 else 176 Init(&m_paintdc, GetBufferedSize(window, style), style); 177 } 178 179 // If no bitmap is supplied by the user, a temporary one will be created. 180 wxBufferedPaintDC(wxWindow *window, int style = wxBUFFER_CLIENT_AREA) 181 : m_paintdc(window) 182 { 183 // If we're using the virtual window, scale the paint DC as well 184 if (style & wxBUFFER_VIRTUAL_AREA) 185 window->PrepareDC( m_paintdc ); 186 187 Init(&m_paintdc, GetBufferedSize(window, style), style); 188 } 189 190 // default copy ctor ok. 191 192 virtual ~wxBufferedPaintDC() 193 { 194 // We must UnMask here, else by the time the base class 195 // does it, the PaintDC will have already been destroyed. 196 UnMask(); 197 } 198 199protected: 200 // return the size needed by the buffer: this depends on whether we're 201 // buffering just the currently shown part or the total (scrolled) window 202 static wxSize GetBufferedSize(wxWindow *window, int style) 203 { 204 return style & wxBUFFER_VIRTUAL_AREA ? window->GetVirtualSize() 205 : window->GetClientSize(); 206 } 207 208private: 209 wxPaintDC m_paintdc; 210 211 DECLARE_ABSTRACT_CLASS(wxBufferedPaintDC) 212 DECLARE_NO_COPY_CLASS(wxBufferedPaintDC) 213}; 214 215 216 217// 218// wxAutoBufferedPaintDC is a wxPaintDC in toolkits which have double- 219// buffering by default. Otherwise it is a wxBufferedPaintDC. Thus, 220// you can only expect it work with a simple constructor that 221// accepts single wxWindow* argument. 222// 223#if wxALWAYS_NATIVE_DOUBLE_BUFFER 224 #define wxAutoBufferedPaintDCBase wxPaintDC 225#else 226 #define wxAutoBufferedPaintDCBase wxBufferedPaintDC 227#endif 228 229 230#ifdef __WXDEBUG__ 231 232class wxAutoBufferedPaintDC : public wxAutoBufferedPaintDCBase 233{ 234public: 235 236 wxAutoBufferedPaintDC(wxWindow* win) 237 : wxAutoBufferedPaintDCBase(win) 238 { 239 TestWinStyle(win); 240 } 241 242 virtual ~wxAutoBufferedPaintDC() { } 243 244private: 245 246 void TestWinStyle(wxWindow* win) 247 { 248 // Help the user to get the double-buffering working properly. 249 wxASSERT_MSG( win->GetBackgroundStyle() == wxBG_STYLE_CUSTOM, 250 wxT("In constructor, you need to call SetBackgroundStyle(wxBG_STYLE_CUSTOM), ") 251 wxT("and also, if needed, paint the background manually in the paint event handler.")); 252 } 253 254 DECLARE_NO_COPY_CLASS(wxAutoBufferedPaintDC) 255}; 256 257#else // !__WXDEBUG__ 258 259// In release builds, just use typedef 260typedef wxAutoBufferedPaintDCBase wxAutoBufferedPaintDC; 261 262#endif 263 264 265// Check if the window is natively double buffered and will return a wxPaintDC 266// if it is, a wxBufferedPaintDC otherwise. It is the caller's responsibility 267// to delete the wxDC pointer when finished with it. 268inline wxDC* wxAutoBufferedPaintDCFactory(wxWindow* window) 269{ 270 if ( window->IsDoubleBuffered() ) 271 return new wxPaintDC(window); 272 else 273 return new wxBufferedPaintDC(window); 274} 275 276#endif // _WX_DCBUFFER_H_ 277