]> git.saurik.com Git - wxWidgets.git/blob - src/msw/enhmeta.cpp
Correct erasing of background behind controls in a toolbar in wxMSW.
[wxWidgets.git] / src / msw / enhmeta.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/enhmeta.cpp
3 // Purpose: implementation of wxEnhMetaFileXXX classes
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 13.01.00
7 // Copyright: (c) 2000 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
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 #if wxUSE_ENH_METAFILE
27
28 #ifndef WX_PRECOMP
29 #include "wx/string.h"
30 #include "wx/log.h"
31 #include "wx/intl.h"
32 #endif //WX_PRECOMP
33
34 #include "wx/dc.h"
35 #include "wx/msw/dc.h"
36
37 #include "wx/metafile.h"
38 #include "wx/clipbrd.h"
39
40 #include "wx/msw/private.h"
41
42 // ----------------------------------------------------------------------------
43 // wxWin macros
44 // ----------------------------------------------------------------------------
45
46 IMPLEMENT_DYNAMIC_CLASS(wxEnhMetaFile, wxObject)
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
60 static inline const wxChar *GetMetaFileName(const wxString& fn)
61 { return !fn ? NULL : wxMSW_CONV_LPCTSTR(fn); }
62
63 // ============================================================================
64 // implementation
65 // ============================================================================
66
67 // ----------------------------------------------------------------------------
68 // wxEnhMetaFile
69 // ----------------------------------------------------------------------------
70
71 wxGDIRefData *wxEnhMetaFile::CreateGDIRefData() const
72 {
73 wxFAIL_MSG( wxT("must be implemented if used") );
74
75 return NULL;
76 }
77
78 wxGDIRefData *
79 wxEnhMetaFile::CloneGDIRefData(const wxGDIRefData *WXUNUSED(data)) const
80 {
81 wxFAIL_MSG( wxT("must be implemented if used") );
82
83 return NULL;
84 }
85
86 void 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 {
94 m_hMF = (WXHANDLE)::GetEnhMetaFile(m_filename.t_str());
95 if ( !m_hMF )
96 {
97 wxLogSysError(_("Failed to load metafile from file \"%s\"."),
98 m_filename.c_str());
99 }
100 }
101 }
102
103 void 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 {
114 wxLogLastError(wxT("CopyEnhMetaFile"));
115 }
116 }
117 else
118 {
119 m_hMF = 0;
120 }
121 }
122
123 void wxEnhMetaFile::Free()
124 {
125 if ( m_hMF )
126 {
127 if ( !::DeleteEnhMetaFile(GetEMF()) )
128 {
129 wxLogLastError(wxT("DeleteEnhMetaFile"));
130 }
131 }
132 }
133
134 bool wxEnhMetaFile::Play(wxDC *dc, wxRect *rectBound)
135 {
136 wxCHECK_MSG( IsOk(), false, wxT("can't play invalid enhanced metafile") );
137 wxCHECK_MSG( dc, false, wxT("invalid wxDC in wxEnhMetaFile::Play") );
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
157 wxDCImpl *impl = dc->GetImpl();
158 wxMSWDCImpl *msw_impl = wxDynamicCast( impl, wxMSWDCImpl );
159 if (!msw_impl)
160 return false;
161
162 if ( !::PlayEnhMetaFile(GetHdcOf(*msw_impl), GetEMF(), &rect) )
163 {
164 wxLogLastError(wxT("PlayEnhMetaFile"));
165
166 return false;
167 }
168
169 return true;
170 }
171
172 wxSize wxEnhMetaFile::GetSize() const
173 {
174 wxSize size = wxDefaultSize;
175
176 if ( IsOk() )
177 {
178 ENHMETAHEADER hdr;
179 if ( !::GetEnhMetaFileHeader(GetEMF(), sizeof(hdr), &hdr) )
180 {
181 wxLogLastError(wxT("GetEnhMetaFileHeader"));
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
200 bool wxEnhMetaFile::SetClipboard(int WXUNUSED(width), int WXUNUSED(height))
201 {
202 #if wxUSE_DRAG_AND_DROP && wxUSE_CLIPBOARD
203 wxCHECK_MSG( m_hMF, false, wxT("can't copy invalid metafile to clipboard") );
204
205 return wxTheClipboard->AddData(new wxEnhMetaFileDataObject(*this));
206 #else // !wxUSE_DRAG_AND_DROP
207 wxFAIL_MSG(wxT("not implemented"));
208 return false;
209 #endif // wxUSE_DRAG_AND_DROP/!wxUSE_DRAG_AND_DROP
210 }
211
212 // ----------------------------------------------------------------------------
213 // wxEnhMetaFileDCImpl
214 // ----------------------------------------------------------------------------
215
216 class wxEnhMetaFileDCImpl : public wxMSWDCImpl
217 {
218 public:
219 wxEnhMetaFileDCImpl( wxEnhMetaFileDC *owner,
220 const wxString& filename, int width, int height,
221 const wxString& description );
222 wxEnhMetaFileDCImpl( wxEnhMetaFileDC *owner,
223 const wxDC& referenceDC,
224 const wxString& filename, int width, int height,
225 const wxString& description );
226 virtual ~wxEnhMetaFileDCImpl();
227
228 // obtain a pointer to the new metafile (caller should delete it)
229 wxEnhMetaFile *Close();
230
231 protected:
232 virtual void DoGetSize(int *width, int *height) const;
233
234 private:
235 void Create(HDC hdcRef,
236 const wxString& filename, int width, int height,
237 const wxString& description);
238
239 // size passed to ctor and returned by DoGetSize()
240 int m_width,
241 m_height;
242 };
243
244
245 wxEnhMetaFileDCImpl::wxEnhMetaFileDCImpl( wxEnhMetaFileDC* owner,
246 const wxString& filename,
247 int width, int height,
248 const wxString& description )
249 : wxMSWDCImpl( owner )
250 {
251 Create(ScreenHDC(), filename, width, height, description);
252 }
253
254 wxEnhMetaFileDCImpl::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
264 void wxEnhMetaFileDCImpl::Create(HDC hdcRef,
265 const wxString& filename,
266 int width, int height,
267 const wxString& description)
268 {
269 m_width = width;
270 m_height = height;
271
272 RECT rect;
273 RECT *pRect;
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
282 PixelToHIMETRIC(&rect.right, &rect.bottom, hdcRef);
283
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),
293 pRect, description.t_str());
294 if ( !m_hDC )
295 {
296 wxLogLastError(wxT("CreateEnhMetaFile"));
297 }
298 }
299
300 void wxEnhMetaFileDCImpl::DoGetSize(int *width, int *height) const
301 {
302 if ( width )
303 *width = m_width;
304 if ( height )
305 *height = m_height;
306 }
307
308 wxEnhMetaFile *wxEnhMetaFileDCImpl::Close()
309 {
310 wxCHECK_MSG( IsOk(), NULL, wxT("invalid wxEnhMetaFileDC") );
311
312 HENHMETAFILE hMF = ::CloseEnhMetaFile(GetHdc());
313 if ( !hMF )
314 {
315 wxLogLastError(wxT("CloseEnhMetaFile"));
316
317 return NULL;
318 }
319
320 wxEnhMetaFile *mf = new wxEnhMetaFile;
321 mf->SetHENHMETAFILE((WXHANDLE)hMF);
322 return mf;
323 }
324
325 wxEnhMetaFileDCImpl::~wxEnhMetaFileDCImpl()
326 {
327 // avoid freeing it in the base class dtor
328 m_hDC = 0;
329 }
330
331 // ----------------------------------------------------------------------------
332 // wxEnhMetaFileDC
333 // ----------------------------------------------------------------------------
334
335 IMPLEMENT_ABSTRACT_CLASS(wxEnhMetaFileDC, wxDC)
336
337 wxEnhMetaFileDC::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
347 wxEnhMetaFileDC::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
359 wxEnhMetaFile *wxEnhMetaFileDC::Close()
360 {
361 wxEnhMetaFileDCImpl * const
362 impl = static_cast<wxEnhMetaFileDCImpl *>(GetImpl());
363 wxCHECK_MSG( impl, NULL, wxT("no wxEnhMetaFileDC implementation") );
364
365 return impl->Close();
366 }
367
368 #if wxUSE_DRAG_AND_DROP
369
370 // ----------------------------------------------------------------------------
371 // wxEnhMetaFileDataObject
372 // ----------------------------------------------------------------------------
373
374 wxDataFormat
375 wxEnhMetaFileDataObject::GetPreferredFormat(Direction WXUNUSED(dir)) const
376 {
377 return wxDF_ENHMETAFILE;
378 }
379
380 size_t wxEnhMetaFileDataObject::GetFormatCount(Direction WXUNUSED(dir)) const
381 {
382 // wxDF_ENHMETAFILE and wxDF_METAFILE
383 return 2;
384 }
385
386 void wxEnhMetaFileDataObject::GetAllFormats(wxDataFormat *formats,
387 Direction WXUNUSED(dir)) const
388 {
389 formats[0] = wxDF_ENHMETAFILE;
390 formats[1] = wxDF_METAFILE;
391 }
392
393 size_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 {
402 wxASSERT_MSG( format == wxDF_METAFILE, wxT("unsupported format") );
403
404 return sizeof(METAFILEPICT);
405 }
406 }
407
408 bool wxEnhMetaFileDataObject::GetDataHere(const wxDataFormat& format, void *buf) const
409 {
410 wxCHECK_MSG( m_metafile.IsOk(), false, wxT("copying invalid enh metafile") );
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 {
419 wxLogLastError(wxT("CopyEnhMetaFile"));
420
421 return false;
422 }
423
424 *(HENHMETAFILE *)buf = hEMFCopy;
425 }
426 else
427 {
428 wxASSERT_MSG( format == wxDF_METAFILE, wxT("unsupported format") );
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);
436 wxCHECK_MSG( size, false, wxT("GetWinMetaFileBits() failed") );
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 {
443 wxLogLastError(wxT("GetWinMetaFileBits"));
444
445 free(bits);
446
447 return false;
448 }
449
450 // and finally convert them to the WMF
451 HMETAFILE hMF = ::SetMetaFileBitsEx(size, bits);
452 free(bits);
453 if ( !hMF )
454 {
455 wxLogLastError(wxT("SetMetaFileBitsEx"));
456
457 return false;
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
471 return true;
472 }
473
474 bool 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
484 wxCHECK_MSG( hEMF, false, wxT("pasting invalid enh metafile") );
485 }
486 else
487 {
488 wxASSERT_MSG( format == wxDF_METAFILE, wxT("unsupported format") );
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);
495 wxCHECK_MSG( size, false, wxT("GetMetaFileBitsEx() failed") );
496
497 // then get metafile bits
498 BYTE *bits = (BYTE *)malloc(size);
499 if ( !::GetMetaFileBitsEx(mfpict->hMF, size, bits) )
500 {
501 wxLogLastError(wxT("GetMetaFileBitsEx"));
502
503 free(bits);
504
505 return false;
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 {
515 wxLogLastError(wxT("SetWinMetaFileBits"));
516
517 return false;
518 }
519 }
520
521 m_metafile.SetHENHMETAFILE((WXHANDLE)hEMF);
522
523 return true;
524 }
525
526 // ----------------------------------------------------------------------------
527 // wxEnhMetaFileSimpleDataObject
528 // ----------------------------------------------------------------------------
529
530 size_t wxEnhMetaFileSimpleDataObject::GetDataSize() const
531 {
532 // we pass data by handle and not HGLOBAL
533 return 0u;
534 }
535
536 bool wxEnhMetaFileSimpleDataObject::GetDataHere(void *buf) const
537 {
538 wxCHECK_MSG( m_metafile.IsOk(), false, wxT("copying invalid enh metafile") );
539
540 HENHMETAFILE hEMF = (HENHMETAFILE)m_metafile.GetHENHMETAFILE();
541
542 HENHMETAFILE hEMFCopy = ::CopyEnhMetaFile(hEMF, NULL);
543 if ( !hEMFCopy )
544 {
545 wxLogLastError(wxT("CopyEnhMetaFile"));
546
547 return false;
548 }
549
550 *(HENHMETAFILE *)buf = hEMFCopy;
551 return true;
552 }
553
554 bool wxEnhMetaFileSimpleDataObject::SetData(size_t WXUNUSED(len),
555 const void *buf)
556 {
557 HENHMETAFILE hEMF = *(HENHMETAFILE *)buf;
558
559 wxCHECK_MSG( hEMF, false, wxT("pasting invalid enh metafile") );
560 m_metafile.SetHENHMETAFILE((WXHANDLE)hEMF);
561
562 return true;
563 }
564
565
566 #endif // wxUSE_DRAG_AND_DROP
567
568 #endif // wxUSE_ENH_METAFILE