Made wxStubs compile on Unix.
[wxWidgets.git] / src / msw / metafile.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: metafile.cpp
3 // Purpose: wxMetaFileDC etc.
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "metafile.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/setup.h"
25 #endif
26
27 #if USE_METAFILE
28
29 #ifndef WX_PRECOMP
30 #include "wx/utils.h"
31 #include "wx/app.h"
32 #endif
33
34 #include "wx/metafile.h"
35 #include "wx/clipbrd.h"
36 #include "wx/msw/private.h"
37
38 #include <stdio.h>
39 #include <string.h>
40
41 extern bool wxClipboardIsOpen;
42
43 #if !USE_SHARED_LIBRARY
44 IMPLEMENT_DYNAMIC_CLASS(wxMetaFile, wxObject)
45 IMPLEMENT_ABSTRACT_CLASS(wxMetaFileDC, wxDC)
46 #endif
47
48 /*
49 * Metafiles - Windows 3.1 only
50 * Currently, the only purpose for making a metafile is to put
51 * it on the clipboard.
52 */
53
54 wxMetaFile::wxMetaFile(const wxString& file)
55 {
56 m_windowsMappingMode = MM_ANISOTROPIC;
57 m_metaFile = 0;
58 if (!file.IsNull() && file == "")
59 m_metaFile = (WXHANDLE) GetMetaFile(file);
60 }
61
62 wxMetaFile::~wxMetaFile(void)
63 {
64 if (m_metaFile)
65 { DeleteMetaFile((HMETAFILE) m_metaFile); m_metaFile = 0; }
66 }
67
68 bool wxMetaFile::SetClipboard(int width, int height)
69 {
70 bool alreadyOpen=wxClipboardOpen();
71 if (!alreadyOpen)
72 {
73 wxOpenClipboard();
74 if (!wxEmptyClipboard()) return FALSE;
75 }
76 bool success = wxSetClipboardData(wxDF_METAFILE,this, width,height);
77 if (!alreadyOpen) wxCloseClipboard();
78 return (bool) success;
79 }
80
81 bool wxMetaFile::Play(wxDC *dc)
82 {
83 dc->BeginDrawing();
84
85 if (dc->GetHDC() && m_metaFile)
86 PlayMetaFile((HDC) dc->GetHDC(), (HMETAFILE) m_metaFile);
87
88 dc->EndDrawing();
89
90 return TRUE;
91 }
92
93 /*
94 * Metafile device context
95 *
96 */
97
98 // Original constructor that does not takes origin and extent. If you use this,
99 // *DO* give origin/extent arguments to wxMakeMetaFilePlaceable.
100 wxMetaFileDC::wxMetaFileDC(const wxString& file)
101 {
102 m_metaFile = NULL;
103 m_minX = 10000;
104 m_minY = 10000;
105 m_maxX = -10000;
106 m_maxY = -10000;
107 // m_title = NULL;
108
109 if (!file.IsNull() && wxFileExists(file))
110 wxRemoveFile(file);
111
112 if (!file.IsNull() && (file != ""))
113 m_hDC = (WXHDC) CreateMetaFile(file);
114 else
115 m_hDC = (WXHDC) CreateMetaFile(NULL);
116
117 m_ok = (m_hDC != (WXHDC) 0) ;
118
119 // Actual Windows mapping mode, for future reference.
120 m_windowsMappingMode = MM_TEXT;
121
122 SetMapMode(MM_TEXT); // NOTE: does not set HDC mapmode (this is correct)
123 }
124
125 // New constructor that takes origin and extent. If you use this, don't
126 // give origin/extent arguments to wxMakeMetaFilePlaceable.
127 wxMetaFileDC::wxMetaFileDC(const wxString& file, int xext, int yext, int xorg, int yorg)
128 {
129 m_minX = 10000;
130 m_minY = 10000;
131 m_maxX = -10000;
132 m_maxY = -10000;
133 if (file != "" && wxFileExists(file)) wxRemoveFile(file);
134 m_hDC = (WXHDC) CreateMetaFile(file);
135
136 m_ok = TRUE;
137
138 ::SetWindowOrgEx((HDC) m_hDC,xorg,yorg, NULL);
139 ::SetWindowExtEx((HDC) m_hDC,xext,yext, NULL);
140
141 // Actual Windows mapping mode, for future reference.
142 m_windowsMappingMode = MM_ANISOTROPIC;
143
144 SetMapMode(MM_TEXT); // NOTE: does not set HDC mapmode (this is correct)
145 }
146
147 wxMetaFileDC::~wxMetaFileDC(void)
148 {
149 m_hDC = 0;
150 }
151
152 void wxMetaFileDC::GetTextExtent(const wxString& string, long *x, long *y,
153 long *descent, long *externalLeading, wxFont *theFont, bool use16bit) const
154 {
155 wxFont *fontToUse = theFont;
156 if (!fontToUse)
157 fontToUse = (wxFont*) &m_font;
158
159 HDC dc = GetDC(NULL);
160
161 SIZE sizeRect;
162 TEXTMETRIC tm;
163 GetTextExtentPoint(dc, (char *)(const char *) string, strlen((char *)(const char *) string), &sizeRect);
164 GetTextMetrics(dc, &tm);
165
166 ReleaseDC(NULL, dc);
167
168 *x = XDEV2LOGREL(sizeRect.cx);
169 *y = YDEV2LOGREL(sizeRect.cy);
170 if (descent) *descent = tm.tmDescent;
171 if (externalLeading) *externalLeading = tm.tmExternalLeading;
172 }
173
174 wxMetaFile *wxMetaFileDC::Close(void)
175 {
176 SelectOldObjects(m_hDC);
177 HANDLE mf = CloseMetaFile((HDC) m_hDC);
178 m_hDC = 0;
179 if (mf)
180 {
181 wxMetaFile *wx_mf = new wxMetaFile;
182 wx_mf->SetHMETAFILE((WXHANDLE) mf);
183 wx_mf->SetWindowsMappingMode(m_windowsMappingMode);
184 return wx_mf;
185 }
186 return NULL;
187 }
188
189 void wxMetaFileDC::SetMapMode(int mode)
190 {
191 m_mappingMode = mode;
192
193 // int pixel_width = 0;
194 // int pixel_height = 0;
195 // int mm_width = 0;
196 // int mm_height = 0;
197
198 float mm2pixelsX = 10.0;
199 float mm2pixelsY = 10.0;
200
201 switch (mode)
202 {
203 case MM_TWIPS:
204 {
205 m_logicalScaleX = (float)(twips2mm * mm2pixelsX);
206 m_logicalScaleY = (float)(twips2mm * mm2pixelsY);
207 break;
208 }
209 case MM_POINTS:
210 {
211 m_logicalScaleX = (float)(pt2mm * mm2pixelsX);
212 m_logicalScaleY = (float)(pt2mm * mm2pixelsY);
213 break;
214 }
215 case MM_METRIC:
216 {
217 m_logicalScaleX = mm2pixelsX;
218 m_logicalScaleY = mm2pixelsY;
219 break;
220 }
221 case MM_LOMETRIC:
222 {
223 m_logicalScaleX = (float)(mm2pixelsX/10.0);
224 m_logicalScaleY = (float)(mm2pixelsY/10.0);
225 break;
226 }
227 default:
228 case MM_TEXT:
229 {
230 m_logicalScaleX = 1.0;
231 m_logicalScaleY = 1.0;
232 break;
233 }
234 }
235 m_windowExtX = 100;
236 m_windowExtY = 100;
237 }
238
239 #ifdef __WIN32__
240 struct RECT32
241 {
242 short left;
243 short top;
244 short right;
245 short bottom;
246 };
247
248 struct mfPLACEABLEHEADER {
249 DWORD key;
250 short hmf;
251 RECT32 bbox;
252 WORD inch;
253 DWORD reserved;
254 WORD checksum;
255 };
256 #else
257 struct mfPLACEABLEHEADER {
258 DWORD key;
259 HANDLE hmf;
260 RECT bbox;
261 WORD inch;
262 DWORD reserved;
263 WORD checksum;
264 };
265 #endif
266
267 /*
268 * Pass filename of existing non-placeable metafile, and bounding box.
269 * Adds a placeable metafile header, sets the mapping mode to anisotropic,
270 * and sets the window origin and extent to mimic the MM_TEXT mapping mode.
271 *
272 */
273
274 bool wxMakeMetaFilePlaceable(const wxString& filename, float scale)
275 {
276 return wxMakeMetaFilePlaceable(filename, 0, 0, 0, 0, scale, FALSE);
277 }
278
279 bool wxMakeMetaFilePlaceable(const wxString& filename, int x1, int y1, int x2, int y2, float scale, bool useOriginAndExtent)
280 {
281 // I'm not sure if this is the correct way of suggesting a scale
282 // to the client application, but it's the only way I can find.
283 int unitsPerInch = (int)(576/scale);
284
285 mfPLACEABLEHEADER header;
286 header.key = 0x9AC6CDD7L;
287 header.hmf = 0;
288 header.bbox.left = (int)(x1);
289 header.bbox.top = (int)(y1);
290 header.bbox.right = (int)(x2);
291 header.bbox.bottom = (int)(y2);
292 header.inch = unitsPerInch;
293 header.reserved = 0;
294
295 // Calculate checksum
296 WORD *p;
297 mfPLACEABLEHEADER *pMFHead = &header;
298 for (p =(WORD *)pMFHead,pMFHead -> checksum = 0;
299 p < (WORD *)&pMFHead ->checksum; ++p)
300 pMFHead ->checksum ^= *p;
301
302 FILE *fd = fopen((char *)(const char *)filename, "rb");
303 if (!fd) return FALSE;
304
305 char tempFileBuf[256];
306 wxGetTempFileName("mf", tempFileBuf);
307 FILE *fHandle = fopen(tempFileBuf, "wb");
308 if (!fHandle)
309 return FALSE;
310 fwrite((void *)&header, sizeof(unsigned char), sizeof(mfPLACEABLEHEADER), fHandle);
311
312 // Calculate origin and extent
313 int originX = x1;
314 int originY = y1;
315 int extentX = x2 - x1;
316 int extentY = (y2 - y1);
317
318 // Read metafile header and write
319 METAHEADER metaHeader;
320 fread((void *)&metaHeader, sizeof(unsigned char), sizeof(metaHeader), fd);
321
322 if (useOriginAndExtent)
323 metaHeader.mtSize += 15;
324 else
325 metaHeader.mtSize += 5;
326
327 fwrite((void *)&metaHeader, sizeof(unsigned char), sizeof(metaHeader), fHandle);
328
329 // Write SetMapMode, SetWindowOrigin and SetWindowExt records
330 char modeBuffer[8];
331 char originBuffer[10];
332 char extentBuffer[10];
333 METARECORD *modeRecord = (METARECORD *)&modeBuffer;
334
335 METARECORD *originRecord = (METARECORD *)&originBuffer;
336 METARECORD *extentRecord = (METARECORD *)&extentBuffer;
337
338 modeRecord->rdSize = 4;
339 modeRecord->rdFunction = META_SETMAPMODE;
340 modeRecord->rdParm[0] = MM_ANISOTROPIC;
341
342 originRecord->rdSize = 5;
343 originRecord->rdFunction = META_SETWINDOWORG;
344 originRecord->rdParm[0] = originY;
345 originRecord->rdParm[1] = originX;
346
347 extentRecord->rdSize = 5;
348 extentRecord->rdFunction = META_SETWINDOWEXT;
349 extentRecord->rdParm[0] = extentY;
350 extentRecord->rdParm[1] = extentX;
351
352 fwrite((void *)modeBuffer, sizeof(char), 8, fHandle);
353
354 if (useOriginAndExtent)
355 {
356 fwrite((void *)originBuffer, sizeof(char), 10, fHandle);
357 fwrite((void *)extentBuffer, sizeof(char), 10, fHandle);
358 }
359
360 int ch = -2;
361 while (ch != EOF)
362 {
363 ch = getc(fd);
364 if (ch != EOF)
365 {
366 putc(ch, fHandle);
367 }
368 }
369 fclose(fHandle);
370 fclose(fd);
371 wxRemoveFile(filename);
372 wxCopyFile(tempFileBuf, filename);
373 wxRemoveFile(tempFileBuf);
374 return TRUE;
375 }
376
377 #endif // USE_METAFILE