]> git.saurik.com Git - wxWidgets.git/blame - src/msw/enhmeta.cpp
Correct erasing of background behind controls in a toolbar in wxMSW.
[wxWidgets.git] / src / msw / enhmeta.cpp
CommitLineData
d9317fd4 1///////////////////////////////////////////////////////////////////////////////
658ff7f1 2// Name: src/msw/enhmeta.cpp
d9317fd4
VZ
3// Purpose: implementation of wxEnhMetaFileXXX classes
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 13.01.00
d9317fd4 7// Copyright: (c) 2000 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
65571936 8// Licence: wxWindows licence
d9317fd4
VZ
9///////////////////////////////////////////////////////////////////////////////
10
11// ============================================================================
12// declarations
13// ============================================================================
14
15// ----------------------------------------------------------------------------
16// headers
17// ----------------------------------------------------------------------------
18
d9317fd4
VZ
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#if wxUSE_ENH_METAFILE
27
28#ifndef WX_PRECOMP
29 #include "wx/string.h"
30 #include "wx/log.h"
7dca9b44 31 #include "wx/intl.h"
d9317fd4
VZ
32#endif //WX_PRECOMP
33
888dde65
RR
34#include "wx/dc.h"
35#include "wx/msw/dc.h"
36
d9317fd4 37#include "wx/metafile.h"
bfbd6dc1 38#include "wx/clipbrd.h"
d9317fd4
VZ
39
40#include "wx/msw/private.h"
41
42// ----------------------------------------------------------------------------
43// wxWin macros
44// ----------------------------------------------------------------------------
45
46IMPLEMENT_DYNAMIC_CLASS(wxEnhMetaFile, wxObject)
d9317fd4
VZ
47
48// ----------------------------------------------------------------------------
49// macros
50// ----------------------------------------------------------------------------
51
52#define GetEMF() ((HENHMETAFILE)m_hMF)
53#define GetEMFOf(mf) ((HENHMETAFILE)((mf).m_hMF))
54
55// ----------------------------------------------------------------------------
56// private functions
57// ----------------------------------------------------------------------------
58
59// we must pass NULL if the string is empty to metafile functions
60static inline const wxChar *GetMetaFileName(const wxString& fn)
017dc06b 61 { return !fn ? NULL : wxMSW_CONV_LPCTSTR(fn); }
d9317fd4
VZ
62
63// ============================================================================
64// implementation
65// ============================================================================
66
67// ----------------------------------------------------------------------------
68// wxEnhMetaFile
69// ----------------------------------------------------------------------------
70
8f884a0d
VZ
71wxGDIRefData *wxEnhMetaFile::CreateGDIRefData() const
72{
9a83f860 73 wxFAIL_MSG( wxT("must be implemented if used") );
8f884a0d
VZ
74
75 return NULL;
76}
77
78wxGDIRefData *
79wxEnhMetaFile::CloneGDIRefData(const wxGDIRefData *WXUNUSED(data)) const
80{
9a83f860 81 wxFAIL_MSG( wxT("must be implemented if used") );
8f884a0d
VZ
82
83 return NULL;
84}
85
7a295dfa
VZ
86void wxEnhMetaFile::Init()
87{
88 if ( m_filename.empty() )
89 {
90 m_hMF = 0;
91 }
92 else // have valid file name, load metafile from it
93 {
715e4f7e 94 m_hMF = (WXHANDLE)::GetEnhMetaFile(m_filename.t_str());
7a295dfa 95 if ( !m_hMF )
43b2d5e7 96 {
7a295dfa
VZ
97 wxLogSysError(_("Failed to load metafile from file \"%s\"."),
98 m_filename.c_str());
43b2d5e7 99 }
7a295dfa
VZ
100 }
101}
102
d9317fd4
VZ
103void wxEnhMetaFile::Assign(const wxEnhMetaFile& mf)
104{
105 if ( &mf == this )
106 return;
107
108 if ( mf.m_hMF )
109 {
110 m_hMF = (WXHANDLE)::CopyEnhMetaFile(GetEMFOf(mf),
111 GetMetaFileName(m_filename));
112 if ( !m_hMF )
113 {
9a83f860 114 wxLogLastError(wxT("CopyEnhMetaFile"));
d9317fd4
VZ
115 }
116 }
117 else
118 {
119 m_hMF = 0;
120 }
121}
122
123void wxEnhMetaFile::Free()
124{
125 if ( m_hMF )
126 {
127 if ( !::DeleteEnhMetaFile(GetEMF()) )
128 {
9a83f860 129 wxLogLastError(wxT("DeleteEnhMetaFile"));
d9317fd4
VZ
130 }
131 }
132}
133
134bool wxEnhMetaFile::Play(wxDC *dc, wxRect *rectBound)
135{
a1b806b9 136 wxCHECK_MSG( IsOk(), false, wxT("can't play invalid enhanced metafile") );
9a83f860 137 wxCHECK_MSG( dc, false, wxT("invalid wxDC in wxEnhMetaFile::Play") );
d9317fd4
VZ
138
139 RECT rect;
140 if ( rectBound )
141 {
142 rect.top = rectBound->y;
143 rect.left = rectBound->x;
144 rect.right = rectBound->x + rectBound->width;
145 rect.bottom = rectBound->y + rectBound->height;
146 }
147 else
148 {
149 wxSize size = GetSize();
150
151 rect.top =
152 rect.left = 0;
153 rect.right = size.x;
154 rect.bottom = size.y;
155 }
156
888dde65
RR
157 wxDCImpl *impl = dc->GetImpl();
158 wxMSWDCImpl *msw_impl = wxDynamicCast( impl, wxMSWDCImpl );
159 if (!msw_impl)
160 return false;
f0875501 161
888dde65 162 if ( !::PlayEnhMetaFile(GetHdcOf(*msw_impl), GetEMF(), &rect) )
d9317fd4 163 {
9a83f860 164 wxLogLastError(wxT("PlayEnhMetaFile"));
d9317fd4 165
cbe874bd 166 return false;
d9317fd4
VZ
167 }
168
cbe874bd 169 return true;
d9317fd4
VZ
170}
171
172wxSize wxEnhMetaFile::GetSize() const
173{
174 wxSize size = wxDefaultSize;
175
a1b806b9 176 if ( IsOk() )
d9317fd4
VZ
177 {
178 ENHMETAHEADER hdr;
179 if ( !::GetEnhMetaFileHeader(GetEMF(), sizeof(hdr), &hdr) )
180 {
9a83f860 181 wxLogLastError(wxT("GetEnhMetaFileHeader"));
d9317fd4
VZ
182 }
183 else
184 {
185 // the width and height are in HIMETRIC (0.01mm) units, transform
186 // them to pixels
187 LONG w = hdr.rclFrame.right,
188 h = hdr.rclFrame.bottom;
189
190 HIMETRICToPixel(&w, &h);
191
192 size.x = w;
193 size.y = h;
194 }
195 }
196
197 return size;
198}
199
bfbd6dc1
VZ
200bool wxEnhMetaFile::SetClipboard(int WXUNUSED(width), int WXUNUSED(height))
201{
caf448e3 202#if wxUSE_DRAG_AND_DROP && wxUSE_CLIPBOARD
9a83f860 203 wxCHECK_MSG( m_hMF, false, wxT("can't copy invalid metafile to clipboard") );
bfbd6dc1
VZ
204
205 return wxTheClipboard->AddData(new wxEnhMetaFileDataObject(*this));
a95e38c0 206#else // !wxUSE_DRAG_AND_DROP
9a83f860 207 wxFAIL_MSG(wxT("not implemented"));
cbe874bd 208 return false;
a95e38c0 209#endif // wxUSE_DRAG_AND_DROP/!wxUSE_DRAG_AND_DROP
bfbd6dc1
VZ
210}
211
d9317fd4 212// ----------------------------------------------------------------------------
0273787a 213// wxEnhMetaFileDCImpl
d9317fd4
VZ
214// ----------------------------------------------------------------------------
215
888dde65
RR
216class wxEnhMetaFileDCImpl : public wxMSWDCImpl
217{
218public:
f0875501 219 wxEnhMetaFileDCImpl( wxEnhMetaFileDC *owner,
888dde65
RR
220 const wxString& filename, int width, int height,
221 const wxString& description );
cc344571
VS
222 wxEnhMetaFileDCImpl( wxEnhMetaFileDC *owner,
223 const wxDC& referenceDC,
224 const wxString& filename, int width, int height,
225 const wxString& description );
888dde65
RR
226 virtual ~wxEnhMetaFileDCImpl();
227
228 // obtain a pointer to the new metafile (caller should delete it)
229 wxEnhMetaFile *Close();
230
231protected:
232 virtual void DoGetSize(int *width, int *height) const;
233
234private:
cc344571
VS
235 void Create(HDC hdcRef,
236 const wxString& filename, int width, int height,
237 const wxString& description);
238
888dde65
RR
239 // size passed to ctor and returned by DoGetSize()
240 int m_width,
241 m_height;
242};
243
244
888dde65
RR
245wxEnhMetaFileDCImpl::wxEnhMetaFileDCImpl( wxEnhMetaFileDC* owner,
246 const wxString& filename,
247 int width, int height,
248 const wxString& description )
0273787a 249 : wxMSWDCImpl( owner )
cc344571
VS
250{
251 Create(ScreenHDC(), filename, width, height, description);
252}
253
254wxEnhMetaFileDCImpl::wxEnhMetaFileDCImpl( wxEnhMetaFileDC* owner,
255 const wxDC& referenceDC,
256 const wxString& filename,
257 int width, int height,
258 const wxString& description )
259 : wxMSWDCImpl( owner )
260{
261 Create(GetHdcOf(referenceDC), filename, width, height, description);
262}
263
264void wxEnhMetaFileDCImpl::Create(HDC hdcRef,
265 const wxString& filename,
266 int width, int height,
267 const wxString& description)
d9317fd4 268{
024026be
VZ
269 m_width = width;
270 m_height = height;
271
33ac7e6f 272 RECT rect;
cbe874bd 273 RECT *pRect;
d9317fd4
VZ
274 if ( width && height )
275 {
276 rect.top =
277 rect.left = 0;
278 rect.right = width;
279 rect.bottom = height;
280
281 // CreateEnhMetaFile() wants them in HIMETRIC
cc344571 282 PixelToHIMETRIC(&rect.right, &rect.bottom, hdcRef);
cbe874bd 283
d9317fd4
VZ
284 pRect = &rect;
285 }
286 else
287 {
288 // GDI will try to find out the size for us (not recommended)
289 pRect = (LPRECT)NULL;
290 }
291
292 m_hDC = (WXHDC)::CreateEnhMetaFile(hdcRef, GetMetaFileName(filename),
017dc06b 293 pRect, description.t_str());
d9317fd4
VZ
294 if ( !m_hDC )
295 {
9a83f860 296 wxLogLastError(wxT("CreateEnhMetaFile"));
d9317fd4
VZ
297 }
298}
299
888dde65 300void wxEnhMetaFileDCImpl::DoGetSize(int *width, int *height) const
024026be
VZ
301{
302 if ( width )
303 *width = m_width;
304 if ( height )
305 *height = m_height;
306}
307
888dde65 308wxEnhMetaFile *wxEnhMetaFileDCImpl::Close()
d9317fd4 309{
9a83f860 310 wxCHECK_MSG( IsOk(), NULL, wxT("invalid wxEnhMetaFileDC") );
d9317fd4
VZ
311
312 HENHMETAFILE hMF = ::CloseEnhMetaFile(GetHdc());
313 if ( !hMF )
314 {
9a83f860 315 wxLogLastError(wxT("CloseEnhMetaFile"));
d9317fd4
VZ
316
317 return NULL;
318 }
319
320 wxEnhMetaFile *mf = new wxEnhMetaFile;
321 mf->SetHENHMETAFILE((WXHANDLE)hMF);
322 return mf;
323}
324
888dde65 325wxEnhMetaFileDCImpl::~wxEnhMetaFileDCImpl()
d9317fd4
VZ
326{
327 // avoid freeing it in the base class dtor
328 m_hDC = 0;
329}
330
0273787a
VZ
331// ----------------------------------------------------------------------------
332// wxEnhMetaFileDC
333// ----------------------------------------------------------------------------
334
335IMPLEMENT_ABSTRACT_CLASS(wxEnhMetaFileDC, wxDC)
336
337wxEnhMetaFileDC::wxEnhMetaFileDC(const wxString& filename,
338 int width, int height,
339 const wxString& description)
340 : wxDC(new wxEnhMetaFileDCImpl(this,
341 filename,
342 width, height,
343 description))
344{
345}
346
cc344571
VS
347wxEnhMetaFileDC::wxEnhMetaFileDC(const wxDC& referenceDC,
348 const wxString& filename,
349 int width, int height,
350 const wxString& description)
351 : wxDC(new wxEnhMetaFileDCImpl(this,
352 referenceDC,
353 filename,
354 width, height,
355 description))
356{
357}
358
0273787a
VZ
359wxEnhMetaFile *wxEnhMetaFileDC::Close()
360{
361 wxEnhMetaFileDCImpl * const
5c33522f 362 impl = static_cast<wxEnhMetaFileDCImpl *>(GetImpl());
9a83f860 363 wxCHECK_MSG( impl, NULL, wxT("no wxEnhMetaFileDC implementation") );
0273787a
VZ
364
365 return impl->Close();
366}
367
7ba4fbeb
VZ
368#if wxUSE_DRAG_AND_DROP
369
d9317fd4
VZ
370// ----------------------------------------------------------------------------
371// wxEnhMetaFileDataObject
372// ----------------------------------------------------------------------------
373
374wxDataFormat
375wxEnhMetaFileDataObject::GetPreferredFormat(Direction WXUNUSED(dir)) const
376{
377 return wxDF_ENHMETAFILE;
378}
379
380size_t wxEnhMetaFileDataObject::GetFormatCount(Direction WXUNUSED(dir)) const
381{
382 // wxDF_ENHMETAFILE and wxDF_METAFILE
383 return 2;
384}
385
386void wxEnhMetaFileDataObject::GetAllFormats(wxDataFormat *formats,
387 Direction WXUNUSED(dir)) const
388{
389 formats[0] = wxDF_ENHMETAFILE;
390 formats[1] = wxDF_METAFILE;
391}
392
393size_t wxEnhMetaFileDataObject::GetDataSize(const wxDataFormat& format) const
394{
395 if ( format == wxDF_ENHMETAFILE )
396 {
397 // we pass data by handle and not HGLOBAL
398 return 0u;
399 }
400 else
401 {
9a83f860 402 wxASSERT_MSG( format == wxDF_METAFILE, wxT("unsupported format") );
d9317fd4
VZ
403
404 return sizeof(METAFILEPICT);
405 }
406}
407
408bool wxEnhMetaFileDataObject::GetDataHere(const wxDataFormat& format, void *buf) const
409{
a1b806b9 410 wxCHECK_MSG( m_metafile.IsOk(), false, wxT("copying invalid enh metafile") );
d9317fd4
VZ
411
412 HENHMETAFILE hEMF = (HENHMETAFILE)m_metafile.GetHENHMETAFILE();
413
414 if ( format == wxDF_ENHMETAFILE )
415 {
416 HENHMETAFILE hEMFCopy = ::CopyEnhMetaFile(hEMF, NULL);
417 if ( !hEMFCopy )
418 {
9a83f860 419 wxLogLastError(wxT("CopyEnhMetaFile"));
d9317fd4 420
cbe874bd 421 return false;
d9317fd4
VZ
422 }
423
424 *(HENHMETAFILE *)buf = hEMFCopy;
425 }
426 else
427 {
9a83f860 428 wxASSERT_MSG( format == wxDF_METAFILE, wxT("unsupported format") );
d9317fd4
VZ
429
430 // convert to WMF
431
432 ScreenHDC hdc;
433
434 // first get the buffer size and alloc memory
435 size_t size = ::GetWinMetaFileBits(hEMF, 0, NULL, MM_ANISOTROPIC, hdc);
9a83f860 436 wxCHECK_MSG( size, false, wxT("GetWinMetaFileBits() failed") );
d9317fd4
VZ
437
438 BYTE *bits = (BYTE *)malloc(size);
439
440 // then get the enh metafile bits
441 if ( !::GetWinMetaFileBits(hEMF, size, bits, MM_ANISOTROPIC, hdc) )
442 {
9a83f860 443 wxLogLastError(wxT("GetWinMetaFileBits"));
d9317fd4
VZ
444
445 free(bits);
446
cbe874bd 447 return false;
d9317fd4
VZ
448 }
449
450 // and finally convert them to the WMF
451 HMETAFILE hMF = ::SetMetaFileBitsEx(size, bits);
452 free(bits);
453 if ( !hMF )
454 {
9a83f860 455 wxLogLastError(wxT("SetMetaFileBitsEx"));
d9317fd4 456
cbe874bd 457 return false;
d9317fd4
VZ
458 }
459
460 METAFILEPICT *mfpict = (METAFILEPICT *)buf;
461
462 wxSize sizeMF = m_metafile.GetSize();
463 mfpict->hMF = hMF;
464 mfpict->mm = MM_ANISOTROPIC;
465 mfpict->xExt = sizeMF.x;
466 mfpict->yExt = sizeMF.y;
467
468 PixelToHIMETRIC(&mfpict->xExt, &mfpict->yExt);
469 }
470
cbe874bd 471 return true;
d9317fd4
VZ
472}
473
474bool wxEnhMetaFileDataObject::SetData(const wxDataFormat& format,
475 size_t WXUNUSED(len),
476 const void *buf)
477{
478 HENHMETAFILE hEMF;
479
480 if ( format == wxDF_ENHMETAFILE )
481 {
482 hEMF = *(HENHMETAFILE *)buf;
483
9a83f860 484 wxCHECK_MSG( hEMF, false, wxT("pasting invalid enh metafile") );
d9317fd4
VZ
485 }
486 else
487 {
9a83f860 488 wxASSERT_MSG( format == wxDF_METAFILE, wxT("unsupported format") );
d9317fd4
VZ
489
490 // convert from WMF
491 const METAFILEPICT *mfpict = (const METAFILEPICT *)buf;
492
493 // first get the buffer size
494 size_t size = ::GetMetaFileBitsEx(mfpict->hMF, 0, NULL);
9a83f860 495 wxCHECK_MSG( size, false, wxT("GetMetaFileBitsEx() failed") );
d9317fd4
VZ
496
497 // then get metafile bits
498 BYTE *bits = (BYTE *)malloc(size);
499 if ( !::GetMetaFileBitsEx(mfpict->hMF, size, bits) )
500 {
9a83f860 501 wxLogLastError(wxT("GetMetaFileBitsEx"));
d9317fd4
VZ
502
503 free(bits);
504
cbe874bd 505 return false;
d9317fd4
VZ
506 }
507
508 ScreenHDC hdcRef;
509
510 // and finally create an enhanced metafile from them
511 hEMF = ::SetWinMetaFileBits(size, bits, hdcRef, mfpict);
512 free(bits);
513 if ( !hEMF )
514 {
9a83f860 515 wxLogLastError(wxT("SetWinMetaFileBits"));
d9317fd4 516
cbe874bd 517 return false;
d9317fd4
VZ
518 }
519 }
520
521 m_metafile.SetHENHMETAFILE((WXHANDLE)hEMF);
522
cbe874bd 523 return true;
d9317fd4 524}
7ba4fbeb
VZ
525
526// ----------------------------------------------------------------------------
527// wxEnhMetaFileSimpleDataObject
528// ----------------------------------------------------------------------------
529
530size_t wxEnhMetaFileSimpleDataObject::GetDataSize() const
531{
532 // we pass data by handle and not HGLOBAL
533 return 0u;
534}
535
536bool wxEnhMetaFileSimpleDataObject::GetDataHere(void *buf) const
537{
a1b806b9 538 wxCHECK_MSG( m_metafile.IsOk(), false, wxT("copying invalid enh metafile") );
7ba4fbeb
VZ
539
540 HENHMETAFILE hEMF = (HENHMETAFILE)m_metafile.GetHENHMETAFILE();
541
542 HENHMETAFILE hEMFCopy = ::CopyEnhMetaFile(hEMF, NULL);
543 if ( !hEMFCopy )
544 {
9a83f860 545 wxLogLastError(wxT("CopyEnhMetaFile"));
7ba4fbeb 546
cbe874bd 547 return false;
7ba4fbeb
VZ
548 }
549
550 *(HENHMETAFILE *)buf = hEMFCopy;
cbe874bd 551 return true;
7ba4fbeb
VZ
552}
553
554bool wxEnhMetaFileSimpleDataObject::SetData(size_t WXUNUSED(len),
555 const void *buf)
556{
557 HENHMETAFILE hEMF = *(HENHMETAFILE *)buf;
558
9a83f860 559 wxCHECK_MSG( hEMF, false, wxT("pasting invalid enh metafile") );
7ba4fbeb
VZ
560 m_metafile.SetHENHMETAFILE((WXHANDLE)hEMF);
561
cbe874bd 562 return true;
7ba4fbeb
VZ
563}
564
4ce1efe1 565
a2327a9f 566#endif // wxUSE_DRAG_AND_DROP
d9317fd4
VZ
567
568#endif // wxUSE_ENH_METAFILE