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