fixed enhanced metafiles loading from files
[wxWidgets.git] / src / msw / enhmeta.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: 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 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "enhmeta.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #if wxUSE_ENH_METAFILE
32
33 #ifndef WX_PRECOMP
34 #include "wx/string.h"
35 #include "wx/log.h"
36 #endif //WX_PRECOMP
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 IMPLEMENT_ABSTRACT_CLASS(wxEnhMetaFileDC, wxDC)
49
50 // ----------------------------------------------------------------------------
51 // macros
52 // ----------------------------------------------------------------------------
53
54 #define GetEMF() ((HENHMETAFILE)m_hMF)
55 #define GetEMFOf(mf) ((HENHMETAFILE)((mf).m_hMF))
56
57 // ----------------------------------------------------------------------------
58 // private functions
59 // ----------------------------------------------------------------------------
60
61 // we must pass NULL if the string is empty to metafile functions
62 static inline const wxChar *GetMetaFileName(const wxString& fn)
63 { return !fn ? (wxChar *)NULL : fn.c_str(); }
64
65 // ============================================================================
66 // implementation
67 // ============================================================================
68
69 // ----------------------------------------------------------------------------
70 // wxEnhMetaFile
71 // ----------------------------------------------------------------------------
72
73 void wxEnhMetaFile::Init()
74 {
75 if ( m_filename.empty() )
76 {
77 m_hMF = 0;
78 }
79 else // have valid file name, load metafile from it
80 {
81 m_hMF = GetEnhMetaFile(m_filename);
82 if ( !m_hMF )
83 wxLogSysError(_("Failed to load metafile from file \"%s\"."),
84 m_filename.c_str());
85 }
86 }
87
88 void wxEnhMetaFile::Assign(const wxEnhMetaFile& mf)
89 {
90 if ( &mf == this )
91 return;
92
93 if ( mf.m_hMF )
94 {
95 m_hMF = (WXHANDLE)::CopyEnhMetaFile(GetEMFOf(mf),
96 GetMetaFileName(m_filename));
97 if ( !m_hMF )
98 {
99 wxLogLastError(_T("CopyEnhMetaFile"));
100 }
101 }
102 else
103 {
104 m_hMF = 0;
105 }
106 }
107
108 void wxEnhMetaFile::Free()
109 {
110 if ( m_hMF )
111 {
112 if ( !::DeleteEnhMetaFile(GetEMF()) )
113 {
114 wxLogLastError(_T("DeleteEnhMetaFile"));
115 }
116 }
117 }
118
119 bool wxEnhMetaFile::Play(wxDC *dc, wxRect *rectBound)
120 {
121 wxCHECK_MSG( Ok(), false, _T("can't play invalid enhanced metafile") );
122 wxCHECK_MSG( dc, FALSE, _T("invalid wxDC in wxEnhMetaFile::Play") );
123
124 RECT rect;
125 if ( rectBound )
126 {
127 rect.top = rectBound->y;
128 rect.left = rectBound->x;
129 rect.right = rectBound->x + rectBound->width;
130 rect.bottom = rectBound->y + rectBound->height;
131 }
132 else
133 {
134 wxSize size = GetSize();
135
136 rect.top =
137 rect.left = 0;
138 rect.right = size.x;
139 rect.bottom = size.y;
140 }
141
142 if ( !::PlayEnhMetaFile(GetHdcOf(*dc), GetEMF(), &rect) )
143 {
144 wxLogLastError(_T("PlayEnhMetaFile"));
145
146 return false;
147 }
148
149 return true;
150 }
151
152 wxSize wxEnhMetaFile::GetSize() const
153 {
154 wxSize size = wxDefaultSize;
155
156 if ( Ok() )
157 {
158 ENHMETAHEADER hdr;
159 if ( !::GetEnhMetaFileHeader(GetEMF(), sizeof(hdr), &hdr) )
160 {
161 wxLogLastError(_T("GetEnhMetaFileHeader"));
162 }
163 else
164 {
165 // the width and height are in HIMETRIC (0.01mm) units, transform
166 // them to pixels
167 LONG w = hdr.rclFrame.right,
168 h = hdr.rclFrame.bottom;
169
170 HIMETRICToPixel(&w, &h);
171
172 size.x = w;
173 size.y = h;
174 }
175 }
176
177 return size;
178 }
179
180 bool wxEnhMetaFile::SetClipboard(int WXUNUSED(width), int WXUNUSED(height))
181 {
182 #if wxUSE_DRAG_AND_DROP
183 wxCHECK_MSG( m_hMF, FALSE, _T("can't copy invalid metafile to clipboard") );
184
185 return wxTheClipboard->AddData(new wxEnhMetaFileDataObject(*this));
186 #else // !wxUSE_DRAG_AND_DROP
187 wxFAIL_MSG(_T("not implemented"));
188 return false;
189 #endif // wxUSE_DRAG_AND_DROP/!wxUSE_DRAG_AND_DROP
190 }
191
192 // ----------------------------------------------------------------------------
193 // wxEnhMetaFileDC
194 // ----------------------------------------------------------------------------
195
196 wxEnhMetaFileDC::wxEnhMetaFileDC(const wxString& filename,
197 int width, int height,
198 const wxString& description)
199 {
200 ScreenHDC hdcRef;
201 RECT rect;
202 RECT *pRect;
203 if ( width && height )
204 {
205 rect.top =
206 rect.left = 0;
207 rect.right = width;
208 rect.bottom = height;
209
210 // CreateEnhMetaFile() wants them in HIMETRIC
211 PixelToHIMETRIC(&rect.right, &rect.bottom);
212
213 pRect = &rect;
214 }
215 else
216 {
217 // GDI will try to find out the size for us (not recommended)
218 pRect = (LPRECT)NULL;
219 }
220
221 m_hDC = (WXHDC)::CreateEnhMetaFile(hdcRef, GetMetaFileName(filename),
222 pRect, description);
223 if ( !m_hDC )
224 {
225 wxLogLastError(_T("CreateEnhMetaFile"));
226 }
227 }
228
229 wxEnhMetaFile *wxEnhMetaFileDC::Close()
230 {
231 wxCHECK_MSG( Ok(), NULL, _T("invalid wxEnhMetaFileDC") );
232
233 HENHMETAFILE hMF = ::CloseEnhMetaFile(GetHdc());
234 if ( !hMF )
235 {
236 wxLogLastError(_T("CloseEnhMetaFile"));
237
238 return NULL;
239 }
240
241 wxEnhMetaFile *mf = new wxEnhMetaFile;
242 mf->SetHENHMETAFILE((WXHANDLE)hMF);
243 return mf;
244 }
245
246 wxEnhMetaFileDC::~wxEnhMetaFileDC()
247 {
248 // avoid freeing it in the base class dtor
249 m_hDC = 0;
250 }
251
252 #if wxUSE_DRAG_AND_DROP
253
254 // ----------------------------------------------------------------------------
255 // wxEnhMetaFileDataObject
256 // ----------------------------------------------------------------------------
257
258 wxDataFormat
259 wxEnhMetaFileDataObject::GetPreferredFormat(Direction WXUNUSED(dir)) const
260 {
261 return wxDF_ENHMETAFILE;
262 }
263
264 size_t wxEnhMetaFileDataObject::GetFormatCount(Direction WXUNUSED(dir)) const
265 {
266 // wxDF_ENHMETAFILE and wxDF_METAFILE
267 return 2;
268 }
269
270 void wxEnhMetaFileDataObject::GetAllFormats(wxDataFormat *formats,
271 Direction WXUNUSED(dir)) const
272 {
273 formats[0] = wxDF_ENHMETAFILE;
274 formats[1] = wxDF_METAFILE;
275 }
276
277 size_t wxEnhMetaFileDataObject::GetDataSize(const wxDataFormat& format) const
278 {
279 if ( format == wxDF_ENHMETAFILE )
280 {
281 // we pass data by handle and not HGLOBAL
282 return 0u;
283 }
284 else
285 {
286 wxASSERT_MSG( format == wxDF_METAFILE, _T("unsupported format") );
287
288 return sizeof(METAFILEPICT);
289 }
290 }
291
292 bool wxEnhMetaFileDataObject::GetDataHere(const wxDataFormat& format, void *buf) const
293 {
294 wxCHECK_MSG( m_metafile.Ok(), false, _T("copying invalid enh metafile") );
295
296 HENHMETAFILE hEMF = (HENHMETAFILE)m_metafile.GetHENHMETAFILE();
297
298 if ( format == wxDF_ENHMETAFILE )
299 {
300 HENHMETAFILE hEMFCopy = ::CopyEnhMetaFile(hEMF, NULL);
301 if ( !hEMFCopy )
302 {
303 wxLogLastError(_T("CopyEnhMetaFile"));
304
305 return false;
306 }
307
308 *(HENHMETAFILE *)buf = hEMFCopy;
309 }
310 else
311 {
312 wxASSERT_MSG( format == wxDF_METAFILE, _T("unsupported format") );
313
314 // convert to WMF
315
316 ScreenHDC hdc;
317
318 // first get the buffer size and alloc memory
319 size_t size = ::GetWinMetaFileBits(hEMF, 0, NULL, MM_ANISOTROPIC, hdc);
320 wxCHECK_MSG( size, FALSE, _T("GetWinMetaFileBits() failed") );
321
322 BYTE *bits = (BYTE *)malloc(size);
323
324 // then get the enh metafile bits
325 if ( !::GetWinMetaFileBits(hEMF, size, bits, MM_ANISOTROPIC, hdc) )
326 {
327 wxLogLastError(_T("GetWinMetaFileBits"));
328
329 free(bits);
330
331 return false;
332 }
333
334 // and finally convert them to the WMF
335 HMETAFILE hMF = ::SetMetaFileBitsEx(size, bits);
336 free(bits);
337 if ( !hMF )
338 {
339 wxLogLastError(_T("SetMetaFileBitsEx"));
340
341 return false;
342 }
343
344 METAFILEPICT *mfpict = (METAFILEPICT *)buf;
345
346 wxSize sizeMF = m_metafile.GetSize();
347 mfpict->hMF = hMF;
348 mfpict->mm = MM_ANISOTROPIC;
349 mfpict->xExt = sizeMF.x;
350 mfpict->yExt = sizeMF.y;
351
352 PixelToHIMETRIC(&mfpict->xExt, &mfpict->yExt);
353 }
354
355 return true;
356 }
357
358 bool wxEnhMetaFileDataObject::SetData(const wxDataFormat& format,
359 size_t WXUNUSED(len),
360 const void *buf)
361 {
362 HENHMETAFILE hEMF;
363
364 if ( format == wxDF_ENHMETAFILE )
365 {
366 hEMF = *(HENHMETAFILE *)buf;
367
368 wxCHECK_MSG( hEMF, FALSE, _T("pasting invalid enh metafile") );
369 }
370 else
371 {
372 wxASSERT_MSG( format == wxDF_METAFILE, _T("unsupported format") );
373
374 // convert from WMF
375 const METAFILEPICT *mfpict = (const METAFILEPICT *)buf;
376
377 // first get the buffer size
378 size_t size = ::GetMetaFileBitsEx(mfpict->hMF, 0, NULL);
379 wxCHECK_MSG( size, FALSE, _T("GetMetaFileBitsEx() failed") );
380
381 // then get metafile bits
382 BYTE *bits = (BYTE *)malloc(size);
383 if ( !::GetMetaFileBitsEx(mfpict->hMF, size, bits) )
384 {
385 wxLogLastError(_T("GetMetaFileBitsEx"));
386
387 free(bits);
388
389 return false;
390 }
391
392 ScreenHDC hdcRef;
393
394 // and finally create an enhanced metafile from them
395 hEMF = ::SetWinMetaFileBits(size, bits, hdcRef, mfpict);
396 free(bits);
397 if ( !hEMF )
398 {
399 wxLogLastError(_T("SetWinMetaFileBits"));
400
401 return false;
402 }
403 }
404
405 m_metafile.SetHENHMETAFILE((WXHANDLE)hEMF);
406
407 return true;
408 }
409
410 // ----------------------------------------------------------------------------
411 // wxEnhMetaFileSimpleDataObject
412 // ----------------------------------------------------------------------------
413
414 size_t wxEnhMetaFileSimpleDataObject::GetDataSize() const
415 {
416 // we pass data by handle and not HGLOBAL
417 return 0u;
418 }
419
420 bool wxEnhMetaFileSimpleDataObject::GetDataHere(void *buf) const
421 {
422 wxCHECK_MSG( m_metafile.Ok(), false, _T("copying invalid enh metafile") );
423
424 HENHMETAFILE hEMF = (HENHMETAFILE)m_metafile.GetHENHMETAFILE();
425
426 HENHMETAFILE hEMFCopy = ::CopyEnhMetaFile(hEMF, NULL);
427 if ( !hEMFCopy )
428 {
429 wxLogLastError(_T("CopyEnhMetaFile"));
430
431 return false;
432 }
433
434 *(HENHMETAFILE *)buf = hEMFCopy;
435 return true;
436 }
437
438 bool wxEnhMetaFileSimpleDataObject::SetData(size_t WXUNUSED(len),
439 const void *buf)
440 {
441 HENHMETAFILE hEMF = *(HENHMETAFILE *)buf;
442
443 wxCHECK_MSG( hEMF, FALSE, _T("pasting invalid enh metafile") );
444 m_metafile.SetHENHMETAFILE((WXHANDLE)hEMF);
445
446 return true;
447 }
448
449
450 #endif // wxUSE_DRAG_AND_DROP
451
452 #endif // wxUSE_ENH_METAFILE