]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/metafile.cpp
Misc small mods
[wxWidgets.git] / src / msw / metafile.cpp
... / ...
CommitLineData
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 wxUSE_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
41extern bool wxClipboardIsOpen;
42
43IMPLEMENT_DYNAMIC_CLASS(wxMetafile, wxObject)
44IMPLEMENT_ABSTRACT_CLASS(wxMetafileDC, wxDC)
45
46/*
47 * Metafiles
48 * Currently, the only purpose for making a metafile is to put
49 * it on the clipboard.
50 */
51
52wxMetafileRefData::wxMetafileRefData(void)
53{
54 m_metafile = 0;
55 m_windowsMappingMode = wxMM_ANISOTROPIC;
56}
57
58wxMetafileRefData::~wxMetafileRefData(void)
59{
60 if (m_metafile)
61 {
62 DeleteMetaFile((HMETAFILE) m_metafile);
63 m_metafile = 0;
64 }
65}
66
67wxMetafile::wxMetafile(const wxString& file)
68{
69 m_refData = new wxMetafileRefData;
70
71 M_METAFILEDATA->m_windowsMappingMode = wxMM_ANISOTROPIC;
72 M_METAFILEDATA->m_metafile = 0;
73 if (!file.IsNull() && (file.Cmp(wxT("")) == 0))
74 M_METAFILEDATA->m_metafile = (WXHANDLE) GetMetaFile(file);
75}
76
77wxMetafile::~wxMetafile(void)
78{
79}
80
81bool wxMetafile::SetClipboard(int width, int height)
82{
83 if (!m_refData)
84 return FALSE;
85
86 bool alreadyOpen=wxClipboardOpen();
87 if (!alreadyOpen)
88 {
89 wxOpenClipboard();
90 if (!wxEmptyClipboard()) return FALSE;
91 }
92 bool success = wxSetClipboardData(wxDF_METAFILE, this, width,height);
93 if (!alreadyOpen) wxCloseClipboard();
94 return (bool) success;
95}
96
97bool wxMetafile::Play(wxDC *dc)
98{
99 if (!m_refData)
100 return FALSE;
101
102 dc->BeginDrawing();
103
104 if (dc->GetHDC() && M_METAFILEDATA->m_metafile)
105 PlayMetaFile((HDC) dc->GetHDC(), (HMETAFILE) M_METAFILEDATA->m_metafile);
106
107 dc->EndDrawing();
108
109 return TRUE;
110}
111
112void wxMetafile::SetHMETAFILE(WXHANDLE mf)
113{
114 if (m_refData)
115 m_refData = new wxMetafileRefData;
116
117 M_METAFILEDATA->m_metafile = mf;
118}
119
120void wxMetafile::SetWindowsMappingMode(int mm)
121{
122 if (m_refData)
123 m_refData = new wxMetafileRefData;
124
125 M_METAFILEDATA->m_windowsMappingMode = mm;
126}
127
128/*
129 * Metafile device context
130 *
131 */
132
133// Original constructor that does not takes origin and extent. If you use this,
134// *DO* give origin/extent arguments to wxMakeMetafilePlaceable.
135wxMetafileDC::wxMetafileDC(const wxString& file)
136{
137 m_metaFile = NULL;
138 m_minX = 10000;
139 m_minY = 10000;
140 m_maxX = -10000;
141 m_maxY = -10000;
142// m_title = NULL;
143
144 if (!file.IsNull() && wxFileExists(file))
145 wxRemoveFile(file);
146
147 if (!file.IsNull() && (file != wxT("")))
148 m_hDC = (WXHDC) CreateMetaFile(file);
149 else
150 m_hDC = (WXHDC) CreateMetaFile(NULL);
151
152 m_ok = (m_hDC != (WXHDC) 0) ;
153
154 // Actual Windows mapping mode, for future reference.
155 m_windowsMappingMode = wxMM_TEXT;
156
157 SetMapMode(wxMM_TEXT); // NOTE: does not set HDC mapmode (this is correct)
158}
159
160// New constructor that takes origin and extent. If you use this, don't
161// give origin/extent arguments to wxMakeMetafilePlaceable.
162wxMetafileDC::wxMetafileDC(const wxString& file, int xext, int yext, int xorg, int yorg)
163{
164 m_minX = 10000;
165 m_minY = 10000;
166 m_maxX = -10000;
167 m_maxY = -10000;
168 if (file != wxT("") && wxFileExists(file)) wxRemoveFile(file);
169 m_hDC = (WXHDC) CreateMetaFile(file);
170
171 m_ok = TRUE;
172
173 ::SetWindowOrgEx((HDC) m_hDC,xorg,yorg, NULL);
174 ::SetWindowExtEx((HDC) m_hDC,xext,yext, NULL);
175
176 // Actual Windows mapping mode, for future reference.
177 m_windowsMappingMode = wxMM_ANISOTROPIC;
178
179 SetMapMode(wxMM_TEXT); // NOTE: does not set HDC mapmode (this is correct)
180}
181
182wxMetafileDC::~wxMetafileDC(void)
183{
184 m_hDC = 0;
185}
186
187void wxMetafileDC::GetTextExtent(const wxString& string, long *x, long *y,
188 long *descent, long *externalLeading, wxFont *theFont, bool use16bit) const
189{
190 wxFont *fontToUse = theFont;
191 if (!fontToUse)
192 fontToUse = (wxFont*) &m_font;
193
194 HDC dc = GetDC(NULL);
195
196 SIZE sizeRect;
197 TEXTMETRIC tm;
198 GetTextExtentPoint(dc, WXSTRINGCAST string, wxStrlen(WXSTRINGCAST string), &sizeRect);
199 GetTextMetrics(dc, &tm);
200
201 ReleaseDC(NULL, dc);
202
203 if ( x )
204 *x = sizeRect.cx;
205 if ( y )
206 *y = sizeRect.cy;
207 if ( descent )
208 *descent = tm.tmDescent;
209 if ( externalLeading )
210 *externalLeading = tm.tmExternalLeading;
211}
212
213wxMetafile *wxMetafileDC::Close(void)
214{
215 SelectOldObjects(m_hDC);
216 HANDLE mf = CloseMetaFile((HDC) m_hDC);
217 m_hDC = 0;
218 if (mf)
219 {
220 wxMetafile *wx_mf = new wxMetafile;
221 wx_mf->SetHMETAFILE((WXHANDLE) mf);
222 wx_mf->SetWindowsMappingMode(m_windowsMappingMode);
223 return wx_mf;
224 }
225 return NULL;
226}
227
228void wxMetafileDC::SetMapMode(int mode)
229{
230 m_mappingMode = mode;
231
232// int pixel_width = 0;
233// int pixel_height = 0;
234// int mm_width = 0;
235// int mm_height = 0;
236
237 float mm2pixelsX = 10.0;
238 float mm2pixelsY = 10.0;
239
240 switch (mode)
241 {
242 case wxMM_TWIPS:
243 {
244 m_logicalScaleX = (float)(twips2mm * mm2pixelsX);
245 m_logicalScaleY = (float)(twips2mm * mm2pixelsY);
246 break;
247 }
248 case wxMM_POINTS:
249 {
250 m_logicalScaleX = (float)(pt2mm * mm2pixelsX);
251 m_logicalScaleY = (float)(pt2mm * mm2pixelsY);
252 break;
253 }
254 case wxMM_METRIC:
255 {
256 m_logicalScaleX = mm2pixelsX;
257 m_logicalScaleY = mm2pixelsY;
258 break;
259 }
260 case wxMM_LOMETRIC:
261 {
262 m_logicalScaleX = (float)(mm2pixelsX/10.0);
263 m_logicalScaleY = (float)(mm2pixelsY/10.0);
264 break;
265 }
266 default:
267 case wxMM_TEXT:
268 {
269 m_logicalScaleX = 1.0;
270 m_logicalScaleY = 1.0;
271 break;
272 }
273 }
274 m_windowExtX = 100;
275 m_windowExtY = 100;
276}
277
278#ifdef __WIN32__
279struct RECT32
280{
281 short left;
282 short top;
283 short right;
284 short bottom;
285};
286
287struct mfPLACEABLEHEADER {
288 DWORD key;
289 short hmf;
290 RECT32 bbox;
291 WORD inch;
292 DWORD reserved;
293 WORD checksum;
294};
295#else
296struct mfPLACEABLEHEADER {
297 DWORD key;
298 HANDLE hmf;
299 RECT bbox;
300 WORD inch;
301 DWORD reserved;
302 WORD checksum;
303};
304#endif
305
306/*
307 * Pass filename of existing non-placeable metafile, and bounding box.
308 * Adds a placeable metafile header, sets the mapping mode to anisotropic,
309 * and sets the window origin and extent to mimic the wxMM_TEXT mapping mode.
310 *
311 */
312
313bool wxMakeMetafilePlaceable(const wxString& filename, float scale)
314{
315 return wxMakeMetafilePlaceable(filename, 0, 0, 0, 0, scale, FALSE);
316}
317
318bool wxMakeMetafilePlaceable(const wxString& filename, int x1, int y1, int x2, int y2, float scale, bool useOriginAndExtent)
319{
320 // I'm not sure if this is the correct way of suggesting a scale
321 // to the client application, but it's the only way I can find.
322 int unitsPerInch = (int)(576/scale);
323
324 mfPLACEABLEHEADER header;
325 header.key = 0x9AC6CDD7L;
326 header.hmf = 0;
327 header.bbox.left = (int)(x1);
328 header.bbox.top = (int)(y1);
329 header.bbox.right = (int)(x2);
330 header.bbox.bottom = (int)(y2);
331 header.inch = unitsPerInch;
332 header.reserved = 0;
333
334 // Calculate checksum
335 WORD *p;
336 mfPLACEABLEHEADER *pMFHead = &header;
337 for (p =(WORD *)pMFHead,pMFHead -> checksum = 0;
338 p < (WORD *)&pMFHead ->checksum; ++p)
339 pMFHead ->checksum ^= *p;
340
341 FILE *fd = fopen(filename.fn_str(), "rb");
342 if (!fd) return FALSE;
343
344 wxChar tempFileBuf[256];
345 wxGetTempFileName(wxT("mf"), tempFileBuf);
346 FILE *fHandle = fopen(wxConvFile.cWX2MB(tempFileBuf), "wb");
347 if (!fHandle)
348 return FALSE;
349 fwrite((void *)&header, sizeof(unsigned char), sizeof(mfPLACEABLEHEADER), fHandle);
350
351 // Calculate origin and extent
352 int originX = x1;
353 int originY = y1;
354 int extentX = x2 - x1;
355 int extentY = (y2 - y1);
356
357 // Read metafile header and write
358 METAHEADER metaHeader;
359 fread((void *)&metaHeader, sizeof(unsigned char), sizeof(metaHeader), fd);
360
361 if (useOriginAndExtent)
362 metaHeader.mtSize += 15;
363 else
364 metaHeader.mtSize += 5;
365
366 fwrite((void *)&metaHeader, sizeof(unsigned char), sizeof(metaHeader), fHandle);
367
368 // Write SetMapMode, SetWindowOrigin and SetWindowExt records
369 char modeBuffer[8];
370 char originBuffer[10];
371 char extentBuffer[10];
372 METARECORD *modeRecord = (METARECORD *)&modeBuffer;
373
374 METARECORD *originRecord = (METARECORD *)&originBuffer;
375 METARECORD *extentRecord = (METARECORD *)&extentBuffer;
376
377 modeRecord->rdSize = 4;
378 modeRecord->rdFunction = META_SETMAPMODE;
379 modeRecord->rdParm[0] = MM_ANISOTROPIC;
380
381 originRecord->rdSize = 5;
382 originRecord->rdFunction = META_SETWINDOWORG;
383 originRecord->rdParm[0] = originY;
384 originRecord->rdParm[1] = originX;
385
386 extentRecord->rdSize = 5;
387 extentRecord->rdFunction = META_SETWINDOWEXT;
388 extentRecord->rdParm[0] = extentY;
389 extentRecord->rdParm[1] = extentX;
390
391 fwrite((void *)modeBuffer, sizeof(char), 8, fHandle);
392
393 if (useOriginAndExtent)
394 {
395 fwrite((void *)originBuffer, sizeof(char), 10, fHandle);
396 fwrite((void *)extentBuffer, sizeof(char), 10, fHandle);
397 }
398
399 int ch = -2;
400 while (ch != EOF)
401 {
402 ch = getc(fd);
403 if (ch != EOF)
404 {
405 putc(ch, fHandle);
406 }
407 }
408 fclose(fHandle);
409 fclose(fd);
410 wxRemoveFile(filename);
411 wxCopyFile(tempFileBuf, filename);
412 wxRemoveFile(tempFileBuf);
413 return TRUE;
414}
415
416#endif // wxUSE_METAFILE
417