1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/msw/dcmemory.cpp
3 // Purpose:     wxMemoryDC class
4 // Author:      Julian Smart
5 // Modified by:
6 // Created:     01/02/97
7 // RCS-ID:      $Id: dcmemory.cpp 42755 2006-10-30 19:41:46Z VZ $
8 // Copyright:   (c) Julian Smart
9 // Licence:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11 
12 // ============================================================================
13 // declarations
14 // ============================================================================
15 
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19 
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22 
23 #ifdef __BORLANDC__
24     #pragma hdrstop
25 #endif
26 
27 #include "wx/dcmemory.h"
28 
29 #ifndef WX_PRECOMP
30     #include "wx/utils.h"
31     #include "wx/log.h"
32 #endif
33 
34 #include "wx/msw/private.h"
35 
36 // ----------------------------------------------------------------------------
37 // wxWin macros
38 // ----------------------------------------------------------------------------
39 
IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC,wxDC)40 IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC, wxDC)
41 
42 // ============================================================================
43 // implementation
44 // ============================================================================
45 
46 // ----------------------------------------------------------------------------
47 // wxMemoryDC
48 // ----------------------------------------------------------------------------
49 
50 wxMemoryDC::wxMemoryDC(wxDC *dc)
51 {
52     wxCHECK_RET( dc, _T("NULL dc in wxMemoryDC ctor") );
53 
54     CreateCompatible(dc);
55 
56     Init();
57 }
58 
Init()59 void wxMemoryDC::Init()
60 {
61     if ( m_ok )
62     {
63         SetBrush(*wxWHITE_BRUSH);
64         SetPen(*wxBLACK_PEN);
65 
66         // the background mode is only used for text background and is set in
67         // DrawText() to OPAQUE as required, otherwise always TRANSPARENT
68         ::SetBkMode( GetHdc(), TRANSPARENT );
69     }
70 }
71 
CreateCompatible(wxDC * dc)72 bool wxMemoryDC::CreateCompatible(wxDC *dc)
73 {
74     m_hDC = (WXHDC)::CreateCompatibleDC(dc ? GetHdcOf(*dc) : NULL);
75 
76     // as we created the DC, we must delete it in the dtor
77     m_bOwnsDC = true;
78 
79     m_ok = m_hDC != 0;
80 
81     return m_ok;
82 }
83 
DoSelect(const wxBitmap & bitmap)84 void wxMemoryDC::DoSelect( const wxBitmap& bitmap)
85 {
86     // select old bitmap out of the device context
87     if ( m_oldBitmap )
88     {
89         ::SelectObject(GetHdc(), (HBITMAP) m_oldBitmap);
90         if ( m_selectedBitmap.Ok() )
91         {
92 #ifdef __WXDEBUG__
93             m_selectedBitmap.SetSelectedInto(NULL);
94 #endif
95             m_selectedBitmap = wxNullBitmap;
96         }
97     }
98 
99     // check for whether the bitmap is already selected into a device context
100     wxASSERT_MSG( !bitmap.GetSelectedInto() ||
101                   (bitmap.GetSelectedInto() == this),
102                   wxT("Bitmap is selected in another wxMemoryDC, delete the first wxMemoryDC or use SelectObject(NULL)") );
103 
104     m_selectedBitmap = bitmap;
105     WXHBITMAP hBmp = m_selectedBitmap.GetHBITMAP();
106     if ( !hBmp )
107         return;
108 
109 #ifdef __WXDEBUG__
110     m_selectedBitmap.SetSelectedInto(this);
111 #endif
112     hBmp = (WXHBITMAP)::SelectObject(GetHdc(), (HBITMAP)hBmp);
113 
114     if ( !hBmp )
115     {
116         wxLogLastError(wxT("SelectObject(memDC, bitmap)"));
117 
118         wxFAIL_MSG(wxT("Couldn't select a bitmap into wxMemoryDC"));
119     }
120     else if ( !m_oldBitmap )
121     {
122         m_oldBitmap = hBmp;
123     }
124 }
125 
DoGetSize(int * width,int * height) const126 void wxMemoryDC::DoGetSize(int *width, int *height) const
127 {
128     if ( m_selectedBitmap.Ok() )
129     {
130         *width = m_selectedBitmap.GetWidth();
131         *height = m_selectedBitmap.GetHeight();
132     }
133     else
134     {
135         *width = 0;
136         *height = 0;
137     }
138 }
139 
140 // the rest of this file deals with drawing rectangles workaround, disabled by
141 // default
142 
143 #define wxUSE_MEMORY_DC_DRAW_RECTANGLE 0
144 
145 #if wxUSE_MEMORY_DC_DRAW_RECTANGLE
146 
147 // For some reason, drawing a rectangle on a memory DC has problems.
148 // Use this substitute if we can.
wxDrawRectangle(wxDC & dc,wxCoord x,wxCoord y,wxCoord width,wxCoord height)149 static void wxDrawRectangle(wxDC& dc, wxCoord x, wxCoord y, wxCoord width, wxCoord height)
150 {
151     wxBrush brush(dc.GetBrush());
152     wxPen pen(dc.GetPen());
153     if (brush.Ok() && brush.GetStyle() != wxTRANSPARENT)
154     {
155         HBRUSH hBrush = (HBRUSH) brush.GetResourceHandle() ;
156         if (hBrush)
157         {
158             RECT rect;
159             rect.left = x; rect.top = y;
160             rect.right = x + width - 1;
161             rect.bottom = y + height - 1;
162             ::FillRect((HDC) dc.GetHDC(), &rect, hBrush);
163         }
164     }
165     width --; height --;
166     if (pen.Ok() && pen.GetStyle() != wxTRANSPARENT)
167     {
168         dc.DrawLine(x, y, x + width, y);
169         dc.DrawLine(x, y, x, y + height);
170         dc.DrawLine(x, y+height, x+width, y + height);
171         dc.DrawLine(x+width, y+height, x+width, y);
172     }
173 }
174 
175 #endif // wxUSE_MEMORY_DC_DRAW_RECTANGLE
176 
DoDrawRectangle(wxCoord x,wxCoord y,wxCoord width,wxCoord height)177 void wxMemoryDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
178 {
179     // Set this to 1 to work around an apparent video driver bug
180     // (visible with e.g. 70x70 rectangle on a memory DC; see Drawing sample)
181 #if wxUSE_MEMORY_DC_DRAW_RECTANGLE
182     if (m_brush.Ok() && m_pen.Ok() &&
183         (m_brush.GetStyle() == wxSOLID || m_brush.GetStyle() == wxTRANSPARENT) &&
184         (m_pen.GetStyle() == wxSOLID || m_pen.GetStyle() == wxTRANSPARENT) &&
185         (GetLogicalFunction() == wxCOPY))
186     {
187         wxDrawRectangle(* this, x, y, width, height);
188     }
189     else
190 #endif // wxUSE_MEMORY_DC_DRAW_RECTANGLE
191     {
192         wxDC::DoDrawRectangle(x, y, width, height);
193     }
194 }
195