No #if wxUSE_DRAG_AND_DROP around the wxMetafileDataObject class, so compilation...
[wxWidgets.git] / src / msw / metafile.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/metafile.cpp
3 // Purpose: wxMetafileDC etc.
4 // Author: Julian Smart
5 // Modified by: VZ 07.01.00: implemented wxMetaFileDataObject
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "metafile.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 #ifndef WX_PRECOMP
32 #include "wx/setup.h"
33 #endif
34
35 #if wxUSE_METAFILE
36
37 #ifndef WX_PRECOMP
38 #include "wx/utils.h"
39 #include "wx/app.h"
40 #endif
41
42 #include "wx/metafile.h"
43 #include "wx/clipbrd.h"
44 #include "wx/msw/private.h"
45
46 #include <stdio.h>
47 #include <string.h>
48
49 // ----------------------------------------------------------------------------
50 // wxWin macros
51 // ----------------------------------------------------------------------------
52
53 IMPLEMENT_DYNAMIC_CLASS(wxMetafile, wxObject)
54 IMPLEMENT_ABSTRACT_CLASS(wxMetafileDC, wxDC)
55
56 // ============================================================================
57 // implementation
58 // ============================================================================
59
60 // ----------------------------------------------------------------------------
61 // wxMetafileRefData
62 // ----------------------------------------------------------------------------
63
64 /*
65 * Metafiles
66 * Currently, the only purpose for making a metafile is to put
67 * it on the clipboard.
68 */
69
70 wxMetafileRefData::wxMetafileRefData()
71 {
72 m_metafile = 0;
73 m_windowsMappingMode = wxMM_ANISOTROPIC;
74 m_width = m_height = 0;
75 }
76
77 wxMetafileRefData::~wxMetafileRefData()
78 {
79 if (m_metafile)
80 {
81 DeleteMetaFile((HMETAFILE) m_metafile);
82 m_metafile = 0;
83 }
84 }
85
86 // ----------------------------------------------------------------------------
87 // wxMetafile
88 // ----------------------------------------------------------------------------
89
90 wxMetafile::wxMetafile(const wxString& file)
91 {
92 m_refData = new wxMetafileRefData;
93
94 M_METAFILEDATA->m_windowsMappingMode = wxMM_ANISOTROPIC;
95 M_METAFILEDATA->m_metafile = 0;
96 if (!file.IsNull() && (file.Cmp(wxT("")) == 0))
97 M_METAFILEDATA->m_metafile = (WXHANDLE) GetMetaFile(file);
98 }
99
100 wxMetafile::~wxMetafile()
101 {
102 }
103
104 bool wxMetafile::SetClipboard(int width, int height)
105 {
106 if (!m_refData)
107 return FALSE;
108
109 bool alreadyOpen = wxClipboardOpen();
110 if (!alreadyOpen)
111 {
112 wxOpenClipboard();
113 if (!wxEmptyClipboard())
114 return FALSE;
115 }
116 bool success = wxSetClipboardData(wxDF_METAFILE, this, width,height);
117 if (!alreadyOpen)
118 wxCloseClipboard();
119
120 return success;
121 }
122
123 bool wxMetafile::Play(wxDC *dc)
124 {
125 if (!m_refData)
126 return FALSE;
127
128 dc->BeginDrawing();
129
130 if (dc->GetHDC() && M_METAFILEDATA->m_metafile)
131 PlayMetaFile(GetHdcOf(*dc), (HMETAFILE) M_METAFILEDATA->m_metafile);
132
133 dc->EndDrawing();
134
135 return TRUE;
136 }
137
138 void wxMetafile::SetHMETAFILE(WXHANDLE mf)
139 {
140 if (!m_refData)
141 m_refData = new wxMetafileRefData;
142
143 M_METAFILEDATA->m_metafile = mf;
144 }
145
146 void wxMetafile::SetWindowsMappingMode(int mm)
147 {
148 if (!m_refData)
149 m_refData = new wxMetafileRefData;
150
151 M_METAFILEDATA->m_windowsMappingMode = mm;
152 }
153
154 // ----------------------------------------------------------------------------
155 // Metafile device context
156 // ----------------------------------------------------------------------------
157
158 // Original constructor that does not takes origin and extent. If you use this,
159 // *DO* give origin/extent arguments to wxMakeMetafilePlaceable.
160 wxMetafileDC::wxMetafileDC(const wxString& file)
161 {
162 m_metaFile = NULL;
163 m_minX = 10000;
164 m_minY = 10000;
165 m_maxX = -10000;
166 m_maxY = -10000;
167 // m_title = NULL;
168
169 if (!file.IsNull() && wxFileExists(file))
170 wxRemoveFile(file);
171
172 if (!file.IsNull() && (file != wxT("")))
173 m_hDC = (WXHDC) CreateMetaFile(file);
174 else
175 m_hDC = (WXHDC) CreateMetaFile(NULL);
176
177 m_ok = (m_hDC != (WXHDC) 0) ;
178
179 // Actual Windows mapping mode, for future reference.
180 m_windowsMappingMode = wxMM_TEXT;
181
182 SetMapMode(wxMM_TEXT); // NOTE: does not set HDC mapmode (this is correct)
183 }
184
185 // New constructor that takes origin and extent. If you use this, don't
186 // give origin/extent arguments to wxMakeMetafilePlaceable.
187 wxMetafileDC::wxMetafileDC(const wxString& file, int xext, int yext, int xorg, int yorg)
188 {
189 m_minX = 10000;
190 m_minY = 10000;
191 m_maxX = -10000;
192 m_maxY = -10000;
193 if ( !!file && wxFileExists(file))
194 wxRemoveFile(file);
195 m_hDC = (WXHDC) CreateMetaFile(file);
196
197 m_ok = TRUE;
198
199 ::SetWindowOrgEx((HDC) m_hDC,xorg,yorg, NULL);
200 ::SetWindowExtEx((HDC) m_hDC,xext,yext, NULL);
201
202 // Actual Windows mapping mode, for future reference.
203 m_windowsMappingMode = wxMM_ANISOTROPIC;
204
205 SetMapMode(wxMM_TEXT); // NOTE: does not set HDC mapmode (this is correct)
206 }
207
208 wxMetafileDC::~wxMetafileDC()
209 {
210 m_hDC = 0;
211 }
212
213 void wxMetafileDC::GetTextExtent(const wxString& string, long *x, long *y,
214 long *descent, long *externalLeading, wxFont *theFont, bool use16bit) const
215 {
216 wxFont *fontToUse = theFont;
217 if (!fontToUse)
218 fontToUse = (wxFont*) &m_font;
219
220 HDC dc = GetDC(NULL);
221
222 SIZE sizeRect;
223 TEXTMETRIC tm;
224 GetTextExtentPoint(dc, WXSTRINGCAST string, wxStrlen(WXSTRINGCAST string), &sizeRect);
225 GetTextMetrics(dc, &tm);
226
227 ReleaseDC(NULL, dc);
228
229 if ( x )
230 *x = sizeRect.cx;
231 if ( y )
232 *y = sizeRect.cy;
233 if ( descent )
234 *descent = tm.tmDescent;
235 if ( externalLeading )
236 *externalLeading = tm.tmExternalLeading;
237 }
238
239 wxMetafile *wxMetafileDC::Close()
240 {
241 SelectOldObjects(m_hDC);
242 HANDLE mf = CloseMetaFile((HDC) m_hDC);
243 m_hDC = 0;
244 if (mf)
245 {
246 wxMetafile *wx_mf = new wxMetafile;
247 wx_mf->SetHMETAFILE((WXHANDLE) mf);
248 wx_mf->SetWindowsMappingMode(m_windowsMappingMode);
249 return wx_mf;
250 }
251 return NULL;
252 }
253
254 void wxMetafileDC::SetMapMode(int mode)
255 {
256 m_mappingMode = mode;
257
258 // int pixel_width = 0;
259 // int pixel_height = 0;
260 // int mm_width = 0;
261 // int mm_height = 0;
262
263 float mm2pixelsX = 10.0;
264 float mm2pixelsY = 10.0;
265
266 switch (mode)
267 {
268 case wxMM_TWIPS:
269 {
270 m_logicalScaleX = (float)(twips2mm * mm2pixelsX);
271 m_logicalScaleY = (float)(twips2mm * mm2pixelsY);
272 break;
273 }
274 case wxMM_POINTS:
275 {
276 m_logicalScaleX = (float)(pt2mm * mm2pixelsX);
277 m_logicalScaleY = (float)(pt2mm * mm2pixelsY);
278 break;
279 }
280 case wxMM_METRIC:
281 {
282 m_logicalScaleX = mm2pixelsX;
283 m_logicalScaleY = mm2pixelsY;
284 break;
285 }
286 case wxMM_LOMETRIC:
287 {
288 m_logicalScaleX = (float)(mm2pixelsX/10.0);
289 m_logicalScaleY = (float)(mm2pixelsY/10.0);
290 break;
291 }
292 default:
293 case wxMM_TEXT:
294 {
295 m_logicalScaleX = 1.0;
296 m_logicalScaleY = 1.0;
297 break;
298 }
299 }
300 m_windowExtX = 100;
301 m_windowExtY = 100;
302 }
303
304 // ----------------------------------------------------------------------------
305 // wxMakeMetafilePlaceable
306 // ----------------------------------------------------------------------------
307
308 #ifdef __WIN32__
309 struct RECT32
310 {
311 short left;
312 short top;
313 short right;
314 short bottom;
315 };
316
317 struct mfPLACEABLEHEADER {
318 DWORD key;
319 short hmf;
320 RECT32 bbox;
321 WORD inch;
322 DWORD reserved;
323 WORD checksum;
324 };
325 #else
326 struct mfPLACEABLEHEADER {
327 DWORD key;
328 HANDLE hmf;
329 RECT bbox;
330 WORD inch;
331 DWORD reserved;
332 WORD checksum;
333 };
334 #endif
335
336 /*
337 * Pass filename of existing non-placeable metafile, and bounding box.
338 * Adds a placeable metafile header, sets the mapping mode to anisotropic,
339 * and sets the window origin and extent to mimic the wxMM_TEXT mapping mode.
340 *
341 */
342
343 bool wxMakeMetafilePlaceable(const wxString& filename, float scale)
344 {
345 return wxMakeMetafilePlaceable(filename, 0, 0, 0, 0, scale, FALSE);
346 }
347
348 bool wxMakeMetafilePlaceable(const wxString& filename, int x1, int y1, int x2, int y2, float scale, bool useOriginAndExtent)
349 {
350 // I'm not sure if this is the correct way of suggesting a scale
351 // to the client application, but it's the only way I can find.
352 int unitsPerInch = (int)(576/scale);
353
354 mfPLACEABLEHEADER header;
355 header.key = 0x9AC6CDD7L;
356 header.hmf = 0;
357 header.bbox.left = (int)(x1);
358 header.bbox.top = (int)(y1);
359 header.bbox.right = (int)(x2);
360 header.bbox.bottom = (int)(y2);
361 header.inch = unitsPerInch;
362 header.reserved = 0;
363
364 // Calculate checksum
365 WORD *p;
366 mfPLACEABLEHEADER *pMFHead = &header;
367 for (p =(WORD *)pMFHead,pMFHead -> checksum = 0;
368 p < (WORD *)&pMFHead ->checksum; ++p)
369 pMFHead ->checksum ^= *p;
370
371 FILE *fd = fopen(filename.fn_str(), "rb");
372 if (!fd) return FALSE;
373
374 wxChar tempFileBuf[256];
375 wxGetTempFileName(wxT("mf"), tempFileBuf);
376 FILE *fHandle = fopen(wxConvFile.cWX2MB(tempFileBuf), "wb");
377 if (!fHandle)
378 return FALSE;
379 fwrite((void *)&header, sizeof(unsigned char), sizeof(mfPLACEABLEHEADER), fHandle);
380
381 // Calculate origin and extent
382 int originX = x1;
383 int originY = y1;
384 int extentX = x2 - x1;
385 int extentY = (y2 - y1);
386
387 // Read metafile header and write
388 METAHEADER metaHeader;
389 fread((void *)&metaHeader, sizeof(unsigned char), sizeof(metaHeader), fd);
390
391 if (useOriginAndExtent)
392 metaHeader.mtSize += 15;
393 else
394 metaHeader.mtSize += 5;
395
396 fwrite((void *)&metaHeader, sizeof(unsigned char), sizeof(metaHeader), fHandle);
397
398 // Write SetMapMode, SetWindowOrigin and SetWindowExt records
399 char modeBuffer[8];
400 char originBuffer[10];
401 char extentBuffer[10];
402 METARECORD *modeRecord = (METARECORD *)&modeBuffer;
403
404 METARECORD *originRecord = (METARECORD *)&originBuffer;
405 METARECORD *extentRecord = (METARECORD *)&extentBuffer;
406
407 modeRecord->rdSize = 4;
408 modeRecord->rdFunction = META_SETMAPMODE;
409 modeRecord->rdParm[0] = MM_ANISOTROPIC;
410
411 originRecord->rdSize = 5;
412 originRecord->rdFunction = META_SETWINDOWORG;
413 originRecord->rdParm[0] = originY;
414 originRecord->rdParm[1] = originX;
415
416 extentRecord->rdSize = 5;
417 extentRecord->rdFunction = META_SETWINDOWEXT;
418 extentRecord->rdParm[0] = extentY;
419 extentRecord->rdParm[1] = extentX;
420
421 fwrite((void *)modeBuffer, sizeof(char), 8, fHandle);
422
423 if (useOriginAndExtent)
424 {
425 fwrite((void *)originBuffer, sizeof(char), 10, fHandle);
426 fwrite((void *)extentBuffer, sizeof(char), 10, fHandle);
427 }
428
429 int ch = -2;
430 while (ch != EOF)
431 {
432 ch = getc(fd);
433 if (ch != EOF)
434 {
435 putc(ch, fHandle);
436 }
437 }
438 fclose(fHandle);
439 fclose(fd);
440 wxRemoveFile(filename);
441 wxCopyFile(tempFileBuf, filename);
442 wxRemoveFile(tempFileBuf);
443 return TRUE;
444 }
445
446
447 #if wxUSE_DRAG_AND_DROP
448
449 // ----------------------------------------------------------------------------
450 // wxMetafileDataObject
451 // ----------------------------------------------------------------------------
452
453 size_t wxMetafileDataObject::GetDataSize() const
454 {
455 return sizeof(METAFILEPICT);
456 }
457
458 bool wxMetafileDataObject::GetDataHere(void *buf) const
459 {
460 METAFILEPICT *mfpict = (METAFILEPICT *)buf;
461 const wxMetafile mf = GetMetafile();
462 mfpict->mm = mf.GetWindowsMappingMode();
463 mfpict->xExt = mf.GetWidth();
464 mfpict->yExt = mf.GetHeight();
465 mfpict->hMF = (HMETAFILE)mf.GetHMETAFILE();
466
467 wxCHECK_MSG( mfpict->hMF, FALSE, _T("copying invalid metafile") );
468
469 return TRUE;
470 }
471
472 bool wxMetafileDataObject::SetData(size_t WXUNUSED(len), const void *buf)
473 {
474 const METAFILEPICT *mfpict = (const METAFILEPICT *)buf;
475
476 wxMetafile mf;
477 mf.SetWindowsMappingMode(mfpict->mm);
478 mf.SetWidth(mfpict->xExt);
479 mf.SetHeight(mfpict->yExt);
480 mf.SetHMETAFILE((WXHANDLE)mfpict->hMF);
481
482 wxCHECK_MSG( mfpict->hMF, FALSE, _T("pasting invalid metafile") );
483
484 SetMetafile(mf);
485
486 return TRUE;
487 }
488
489 #endif // wxUSE_DRAG_AND_DROP
490
491 #endif // wxUSE_METAFILE
492