]>
git.saurik.com Git - wxWidgets.git/blob - src/msw/metafile.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/metafile.cpp
3 // Purpose: wxMetafileDC etc.
4 // Author: Julian Smart
5 // Modified by: VZ 07.01.00: implemented wxMetaFileDataObject
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
32 #include "wx/metafile.h"
33 #include "wx/filename.h"
35 #if wxUSE_METAFILE && !defined(wxMETAFILE_IS_ENH)
37 #include "wx/clipbrd.h"
38 #include "wx/msw/private.h"
43 // ----------------------------------------------------------------------------
45 // ----------------------------------------------------------------------------
47 IMPLEMENT_DYNAMIC_CLASS(wxMetafile
, wxObject
)
48 IMPLEMENT_ABSTRACT_CLASS(wxMetafileDC
, wxDC
)
50 // ============================================================================
52 // ============================================================================
54 // ----------------------------------------------------------------------------
56 // ----------------------------------------------------------------------------
60 * Currently, the only purpose for making a metafile is to put
61 * it on the clipboard.
64 wxMetafileRefData::wxMetafileRefData()
67 m_windowsMappingMode
= MM_ANISOTROPIC
;
68 m_width
= m_height
= 0;
71 wxMetafileRefData::~wxMetafileRefData()
75 DeleteMetaFile((HMETAFILE
) m_metafile
);
80 // ----------------------------------------------------------------------------
82 // ----------------------------------------------------------------------------
84 wxMetafile::wxMetafile(const wxString
& file
)
86 m_refData
= new wxMetafileRefData
;
88 M_METAFILEDATA
->m_windowsMappingMode
= MM_ANISOTROPIC
;
89 M_METAFILEDATA
->m_metafile
= 0;
91 M_METAFILEDATA
->m_metafile
= (WXHANDLE
) GetMetaFile(file
);
94 wxMetafile::~wxMetafile()
98 wxGDIRefData
*wxMetafile::CreateGDIRefData() const
100 return new wxMetafileRefData
;
103 wxGDIRefData
*wxMetafile::CloneGDIRefData(const wxGDIRefData
*data
) const
105 return new wxMetafileRefData(*static_cast<const wxMetafileRefData
*>(data
));
108 bool wxMetafile::SetClipboard(int width
, int height
)
116 bool alreadyOpen
= wxClipboardOpen();
120 if (!wxEmptyClipboard())
123 bool success
= wxSetClipboardData(wxDF_METAFILE
, this, width
,height
);
131 bool wxMetafile::Play(wxDC
*dc
)
136 if (dc
->GetHDC() && M_METAFILEDATA
->m_metafile
)
138 if ( !::PlayMetaFile(GetHdcOf(*dc
), (HMETAFILE
)
139 M_METAFILEDATA
->m_metafile
) )
141 wxLogLastError(wxT("PlayMetaFile"));
148 void wxMetafile::SetHMETAFILE(WXHANDLE mf
)
151 m_refData
= new wxMetafileRefData
;
153 M_METAFILEDATA
->m_metafile
= mf
;
156 void wxMetafile::SetWindowsMappingMode(int mm
)
159 m_refData
= new wxMetafileRefData
;
161 M_METAFILEDATA
->m_windowsMappingMode
= mm
;
164 // ----------------------------------------------------------------------------
165 // Metafile device context
166 // ----------------------------------------------------------------------------
168 // Original constructor that does not takes origin and extent. If you use this,
169 // *DO* give origin/extent arguments to wxMakeMetafilePlaceable.
170 wxMetafileDCImpl::wxMetafileDCImpl(wxDC
*owner
, const wxString
& file
)
180 if ( wxFileExists(file
) )
184 m_hDC
= (WXHDC
) CreateMetaFile(NULL
);
186 m_hDC
= (WXHDC
) CreateMetaFile(file
);
188 m_ok
= (m_hDC
!= (WXHDC
) 0) ;
190 // Actual Windows mapping mode, for future reference.
191 m_windowsMappingMode
= wxMM_TEXT
;
193 SetMapMode(wxMM_TEXT
); // NOTE: does not set HDC mapmode (this is correct)
196 // New constructor that takes origin and extent. If you use this, don't
197 // give origin/extent arguments to wxMakeMetafilePlaceable.
198 wxMetafileDCImpl::wxMetafileDCImpl(wxDC
*owner
, const wxString
& file
,
199 int xext
, int yext
, int xorg
, int yorg
)
206 if ( !file
.empty() && wxFileExists(file
) )
208 m_hDC
= (WXHDC
) CreateMetaFile(file
.empty() ? NULL
: file
.wx_str());
212 ::SetWindowOrgEx((HDC
) m_hDC
,xorg
,yorg
, NULL
);
213 ::SetWindowExtEx((HDC
) m_hDC
,xext
,yext
, NULL
);
215 // Actual Windows mapping mode, for future reference.
216 m_windowsMappingMode
= MM_ANISOTROPIC
;
218 SetMapMode(wxMM_TEXT
); // NOTE: does not set HDC mapmode (this is correct)
221 wxMetafileDCImpl::~wxMetafileDCImpl()
226 void wxMetafileDCImpl::DoGetTextExtent(const wxString
& string
,
227 wxCoord
*x
, wxCoord
*y
,
228 wxCoord
*descent
, wxCoord
*externalLeading
,
229 const wxFont
*theFont
) const
231 const wxFont
*fontToUse
= theFont
;
236 SelectInHDC
selFont(dc
, GetHfontOf(*fontToUse
));
240 ::GetTextExtentPoint32(dc
, WXSTRINGCAST string
, wxStrlen(WXSTRINGCAST string
), &sizeRect
);
241 ::GetTextMetrics(dc
, &tm
);
248 *descent
= tm
.tmDescent
;
249 if ( externalLeading
)
250 *externalLeading
= tm
.tmExternalLeading
;
253 void wxMetafileDCImpl::DoGetSize(int *width
, int *height
) const
255 wxCHECK_RET( m_refData
, wxT("invalid wxMetafileDC") );
258 *width
= M_METAFILEDATA
->m_width
;
260 *height
= M_METAFILEDATA
->m_height
;
263 wxMetafile
*wxMetafileDCImpl::Close()
265 SelectOldObjects(m_hDC
);
266 HANDLE mf
= CloseMetaFile((HDC
) m_hDC
);
270 wxMetafile
*wx_mf
= new wxMetafile
;
271 wx_mf
->SetHMETAFILE((WXHANDLE
) mf
);
272 wx_mf
->SetWindowsMappingMode(m_windowsMappingMode
);
278 void wxMetafileDCImpl::SetMapMode(wxMappingMode mode
)
280 m_mappingMode
= mode
;
282 // int pixel_width = 0;
283 // int pixel_height = 0;
285 // int mm_height = 0;
287 float mm2pixelsX
= 10.0;
288 float mm2pixelsY
= 10.0;
294 m_logicalScaleX
= (float)(twips2mm
* mm2pixelsX
);
295 m_logicalScaleY
= (float)(twips2mm
* mm2pixelsY
);
300 m_logicalScaleX
= (float)(pt2mm
* mm2pixelsX
);
301 m_logicalScaleY
= (float)(pt2mm
* mm2pixelsY
);
306 m_logicalScaleX
= mm2pixelsX
;
307 m_logicalScaleY
= mm2pixelsY
;
312 m_logicalScaleX
= (float)(mm2pixelsX
/10.0);
313 m_logicalScaleY
= (float)(mm2pixelsY
/10.0);
319 m_logicalScaleX
= 1.0;
320 m_logicalScaleY
= 1.0;
326 // ----------------------------------------------------------------------------
327 // wxMakeMetafilePlaceable
328 // ----------------------------------------------------------------------------
339 struct mfPLACEABLEHEADER
{
348 struct mfPLACEABLEHEADER
{
359 * Pass filename of existing non-placeable metafile, and bounding box.
360 * Adds a placeable metafile header, sets the mapping mode to anisotropic,
361 * and sets the window origin and extent to mimic the wxMM_TEXT mapping mode.
365 bool wxMakeMetafilePlaceable(const wxString
& filename
, float scale
)
367 return wxMakeMetafilePlaceable(filename
, 0, 0, 0, 0, scale
, false);
370 bool wxMakeMetafilePlaceable(const wxString
& filename
, int x1
, int y1
, int x2
, int y2
, float scale
, bool useOriginAndExtent
)
372 // I'm not sure if this is the correct way of suggesting a scale
373 // to the client application, but it's the only way I can find.
374 int unitsPerInch
= (int)(576/scale
);
376 mfPLACEABLEHEADER header
;
377 header
.key
= 0x9AC6CDD7L
;
379 header
.bbox
.left
= (int)(x1
);
380 header
.bbox
.top
= (int)(y1
);
381 header
.bbox
.right
= (int)(x2
);
382 header
.bbox
.bottom
= (int)(y2
);
383 header
.inch
= unitsPerInch
;
386 // Calculate checksum
388 mfPLACEABLEHEADER
*pMFHead
= &header
;
389 for (p
=(WORD
*)pMFHead
,pMFHead
-> checksum
= 0;
390 p
< (WORD
*)&pMFHead
->checksum
; ++p
)
391 pMFHead
->checksum
^= *p
;
393 FILE *fd
= wxFopen(filename
.fn_str(), wxT("rb"));
394 if (!fd
) return false;
396 wxString tempFileBuf
= wxFileName::CreateTempFileName(wxT("mf"));
397 if (tempFileBuf
.empty())
400 FILE *fHandle
= wxFopen(tempFileBuf
.fn_str(), wxT("wb"));
403 fwrite((void *)&header
, sizeof(unsigned char), sizeof(mfPLACEABLEHEADER
), fHandle
);
405 // Calculate origin and extent
408 int extentX
= x2
- x1
;
409 int extentY
= (y2
- y1
);
411 // Read metafile header and write
412 METAHEADER metaHeader
;
413 fread((void *)&metaHeader
, sizeof(unsigned char), sizeof(metaHeader
), fd
);
415 if (useOriginAndExtent
)
416 metaHeader
.mtSize
+= 15;
418 metaHeader
.mtSize
+= 5;
420 fwrite((void *)&metaHeader
, sizeof(unsigned char), sizeof(metaHeader
), fHandle
);
422 // Write SetMapMode, SetWindowOrigin and SetWindowExt records
424 char originBuffer
[10];
425 char extentBuffer
[10];
426 METARECORD
*modeRecord
= (METARECORD
*)&modeBuffer
;
428 METARECORD
*originRecord
= (METARECORD
*)&originBuffer
;
429 METARECORD
*extentRecord
= (METARECORD
*)&extentBuffer
;
431 modeRecord
->rdSize
= 4;
432 modeRecord
->rdFunction
= META_SETMAPMODE
;
433 modeRecord
->rdParm
[0] = MM_ANISOTROPIC
;
435 originRecord
->rdSize
= 5;
436 originRecord
->rdFunction
= META_SETWINDOWORG
;
437 originRecord
->rdParm
[0] = originY
;
438 originRecord
->rdParm
[1] = originX
;
440 extentRecord
->rdSize
= 5;
441 extentRecord
->rdFunction
= META_SETWINDOWEXT
;
442 extentRecord
->rdParm
[0] = extentY
;
443 extentRecord
->rdParm
[1] = extentX
;
445 fwrite((void *)modeBuffer
, sizeof(char), 8, fHandle
);
447 if (useOriginAndExtent
)
449 fwrite((void *)originBuffer
, sizeof(char), 10, fHandle
);
450 fwrite((void *)extentBuffer
, sizeof(char), 10, fHandle
);
464 wxRemoveFile(filename
);
465 wxCopyFile(tempFileBuf
, filename
);
466 wxRemoveFile(tempFileBuf
);
471 #if wxUSE_DRAG_AND_DROP
473 // ----------------------------------------------------------------------------
474 // wxMetafileDataObject
475 // ----------------------------------------------------------------------------
477 size_t wxMetafileDataObject::GetDataSize() const
479 return sizeof(METAFILEPICT
);
482 bool wxMetafileDataObject::GetDataHere(void *buf
) const
484 METAFILEPICT
*mfpict
= (METAFILEPICT
*)buf
;
485 const wxMetafile
& mf
= GetMetafile();
487 wxCHECK_MSG( mf
.GetHMETAFILE(), false, wxT("copying invalid metafile") );
489 // doesn't seem to work with any other mapping mode...
490 mfpict
->mm
= MM_ANISOTROPIC
; //mf.GetWindowsMappingMode();
491 mfpict
->xExt
= mf
.GetWidth();
492 mfpict
->yExt
= mf
.GetHeight();
494 // transform the picture size to HIMETRIC units (0.01mm) - as we don't know
495 // what DC the picture will be rendered to, use the default display one
496 PixelToHIMETRIC(&mfpict
->xExt
, &mfpict
->yExt
);
498 mfpict
->hMF
= CopyMetaFile((HMETAFILE
)mf
.GetHMETAFILE(), NULL
);
503 bool wxMetafileDataObject::SetData(size_t WXUNUSED(len
), const void *buf
)
505 const METAFILEPICT
*mfpict
= (const METAFILEPICT
*)buf
;
508 mf
.SetWindowsMappingMode(mfpict
->mm
);
510 LONG w
= mfpict
->xExt
,
512 if ( mfpict
->mm
== MM_ANISOTROPIC
)
514 // in this case xExt and yExt contain suggested size in HIMETRIC units
515 // (0.01 mm) - transform this to something more reasonable (pixels)
516 HIMETRICToPixel(&w
, &h
);
521 mf
.SetHMETAFILE((WXHANDLE
)mfpict
->hMF
);
523 wxCHECK_MSG( mfpict
->hMF
, false, wxT("pasting invalid metafile") );
530 #endif // wxUSE_DRAG_AND_DROP
532 #endif // wxUSE_METAFILE