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