X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/73974df1f951f176f592fd900352c41281eb5df2..b960795ea82b702f302e99e547416cb573865413:/src/msw/metafile.cpp diff --git a/src/msw/metafile.cpp b/src/msw/metafile.cpp index 72bf474c32..3cbb79fb63 100644 --- a/src/msw/metafile.cpp +++ b/src/msw/metafile.cpp @@ -1,49 +1,59 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: metafile.cpp +// Name: src/msw/metafile.cpp // Purpose: wxMetafileDC etc. // Author: Julian Smart -// Modified by: +// Modified by: VZ 07.01.00: implemented wxMetaFileDataObject // Created: 04/01/98 // RCS-ID: $Id$ -// Copyright: (c) Julian Smart and Markus Holzem -// Licence: wxWindows license +// Copyright: (c) Julian Smart +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -#pragma implementation "metafile.h" -#endif +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ -#pragma hdrstop + #pragma hdrstop #endif #ifndef WX_PRECOMP -#include "wx/setup.h" + #include "wx/utils.h" + #include "wx/app.h" #endif -#if wxUSE_METAFILE +#include "wx/metafile.h" +#include "wx/filename.h" -#ifndef WX_PRECOMP -#include "wx/utils.h" -#include "wx/app.h" -#endif +#if wxUSE_METAFILE && !defined(wxMETAFILE_IS_ENH) -#include "wx/metafile.h" #include "wx/clipbrd.h" #include "wx/msw/private.h" #include #include -extern bool wxClipboardIsOpen; +// ---------------------------------------------------------------------------- +// wxWin macros +// ---------------------------------------------------------------------------- -#if !USE_SHARED_LIBRARY IMPLEMENT_DYNAMIC_CLASS(wxMetafile, wxObject) IMPLEMENT_ABSTRACT_CLASS(wxMetafileDC, wxDC) -#endif + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxMetafileRefData +// ---------------------------------------------------------------------------- /* * Metafiles @@ -51,13 +61,14 @@ IMPLEMENT_ABSTRACT_CLASS(wxMetafileDC, wxDC) * it on the clipboard. */ -wxMetafileRefData::wxMetafileRefData(void) +wxMetafileRefData::wxMetafileRefData() { m_metafile = 0; - m_windowsMappingMode = wxMM_ANISOTROPIC; + m_windowsMappingMode = MM_ANISOTROPIC; + m_width = m_height = 0; } -wxMetafileRefData::~wxMetafileRefData(void) +wxMetafileRefData::~wxMetafileRefData() { if (m_metafile) { @@ -66,54 +77,77 @@ wxMetafileRefData::~wxMetafileRefData(void) } } +// ---------------------------------------------------------------------------- +// wxMetafile +// ---------------------------------------------------------------------------- + wxMetafile::wxMetafile(const wxString& file) { m_refData = new wxMetafileRefData; - M_METAFILEDATA->m_windowsMappingMode = wxMM_ANISOTROPIC; + M_METAFILEDATA->m_windowsMappingMode = MM_ANISOTROPIC; M_METAFILEDATA->m_metafile = 0; - if (!file.IsNull() && (file.Cmp(T("")) == 0)) + if (!file.empty()) M_METAFILEDATA->m_metafile = (WXHANDLE) GetMetaFile(file); } -wxMetafile::~wxMetafile(void) +wxMetafile::~wxMetafile() { } +wxGDIRefData *wxMetafile::CreateGDIRefData() const +{ + return new wxMetafileRefData; +} + +wxGDIRefData *wxMetafile::CloneGDIRefData(const wxGDIRefData *data) const +{ + return new wxMetafileRefData(*static_cast(data)); +} + bool wxMetafile::SetClipboard(int width, int height) { +#if !wxUSE_CLIPBOARD + return false; +#else if (!m_refData) - return FALSE; + return false; - bool alreadyOpen=wxClipboardOpen(); + bool alreadyOpen = wxClipboardOpen(); if (!alreadyOpen) { wxOpenClipboard(); - if (!wxEmptyClipboard()) return FALSE; + if (!wxEmptyClipboard()) + return false; } bool success = wxSetClipboardData(wxDF_METAFILE, this, width,height); - if (!alreadyOpen) wxCloseClipboard(); - return (bool) success; + if (!alreadyOpen) + wxCloseClipboard(); + + return success; +#endif } bool wxMetafile::Play(wxDC *dc) { if (!m_refData) - return FALSE; - - dc->BeginDrawing(); + return false; if (dc->GetHDC() && M_METAFILEDATA->m_metafile) - PlayMetaFile((HDC) dc->GetHDC(), (HMETAFILE) M_METAFILEDATA->m_metafile); - - dc->EndDrawing(); + { + if ( !::PlayMetaFile(GetHdcOf(*dc), (HMETAFILE) + M_METAFILEDATA->m_metafile) ) + { + wxLogLastError(wxT("PlayMetaFile")); + } + } - return TRUE; + return true; } void wxMetafile::SetHMETAFILE(WXHANDLE mf) { - if (m_refData) + if (!m_refData) m_refData = new wxMetafileRefData; M_METAFILEDATA->m_metafile = mf; @@ -121,162 +155,178 @@ void wxMetafile::SetHMETAFILE(WXHANDLE mf) void wxMetafile::SetWindowsMappingMode(int mm) { - if (m_refData) + if (!m_refData) m_refData = new wxMetafileRefData; M_METAFILEDATA->m_windowsMappingMode = mm; } -/* - * Metafile device context - * - */ +// ---------------------------------------------------------------------------- +// Metafile device context +// ---------------------------------------------------------------------------- // Original constructor that does not takes origin and extent. If you use this, // *DO* give origin/extent arguments to wxMakeMetafilePlaceable. -wxMetafileDC::wxMetafileDC(const wxString& file) +wxMetafileDCImpl::wxMetafileDCImpl(wxDC *owner, const wxString& file) + : wxMSWDCImpl(owner) { - m_metaFile = NULL; - m_minX = 10000; - m_minY = 10000; - m_maxX = -10000; - m_maxY = -10000; -// m_title = NULL; + m_metaFile = NULL; + m_minX = 10000; + m_minY = 10000; + m_maxX = -10000; + m_maxY = -10000; + // m_title = NULL; - if (!file.IsNull() && wxFileExists(file)) - wxRemoveFile(file); + if ( wxFileExists(file) ) + wxRemoveFile(file); - if (!file.IsNull() && (file != T(""))) - m_hDC = (WXHDC) CreateMetaFile(file); - else - m_hDC = (WXHDC) CreateMetaFile(NULL); + if ( file.empty() ) + m_hDC = (WXHDC) CreateMetaFile(NULL); + else + m_hDC = (WXHDC) CreateMetaFile(file); - m_ok = (m_hDC != (WXHDC) 0) ; + m_ok = (m_hDC != (WXHDC) 0) ; - // Actual Windows mapping mode, for future reference. - m_windowsMappingMode = wxMM_TEXT; + // Actual Windows mapping mode, for future reference. + m_windowsMappingMode = wxMM_TEXT; - SetMapMode(wxMM_TEXT); // NOTE: does not set HDC mapmode (this is correct) + SetMapMode(wxMM_TEXT); // NOTE: does not set HDC mapmode (this is correct) } // New constructor that takes origin and extent. If you use this, don't // give origin/extent arguments to wxMakeMetafilePlaceable. -wxMetafileDC::wxMetafileDC(const wxString& file, int xext, int yext, int xorg, int yorg) +wxMetafileDCImpl::wxMetafileDCImpl(wxDC *owner, const wxString& file, + int xext, int yext, int xorg, int yorg) + : wxMSWDCImpl(owner) { - m_minX = 10000; - m_minY = 10000; - m_maxX = -10000; - m_maxY = -10000; - if (file != T("") && wxFileExists(file)) wxRemoveFile(file); - m_hDC = (WXHDC) CreateMetaFile(file); + m_minX = 10000; + m_minY = 10000; + m_maxX = -10000; + m_maxY = -10000; + if ( !file.empty() && wxFileExists(file) ) + wxRemoveFile(file); + m_hDC = (WXHDC) CreateMetaFile(file.empty() ? NULL : wxMSW_CONV_LPCTSTR(file)); - m_ok = TRUE; + m_ok = true; - ::SetWindowOrgEx((HDC) m_hDC,xorg,yorg, NULL); - ::SetWindowExtEx((HDC) m_hDC,xext,yext, NULL); + ::SetWindowOrgEx((HDC) m_hDC,xorg,yorg, NULL); + ::SetWindowExtEx((HDC) m_hDC,xext,yext, NULL); - // Actual Windows mapping mode, for future reference. - m_windowsMappingMode = wxMM_ANISOTROPIC; + // Actual Windows mapping mode, for future reference. + m_windowsMappingMode = MM_ANISOTROPIC; - SetMapMode(wxMM_TEXT); // NOTE: does not set HDC mapmode (this is correct) + SetMapMode(wxMM_TEXT); // NOTE: does not set HDC mapmode (this is correct) } -wxMetafileDC::~wxMetafileDC(void) +wxMetafileDCImpl::~wxMetafileDCImpl() { - m_hDC = 0; + m_hDC = 0; } -void wxMetafileDC::GetTextExtent(const wxString& string, long *x, long *y, - long *descent, long *externalLeading, wxFont *theFont, bool use16bit) const +void wxMetafileDCImpl::DoGetTextExtent(const wxString& string, + wxCoord *x, wxCoord *y, + wxCoord *descent, wxCoord *externalLeading, + const wxFont *theFont) const { - wxFont *fontToUse = theFont; - if (!fontToUse) - fontToUse = (wxFont*) &m_font; - - HDC dc = GetDC(NULL); - - SIZE sizeRect; - TEXTMETRIC tm; - GetTextExtentPoint(dc, WXSTRINGCAST string, wxStrlen(WXSTRINGCAST string), &sizeRect); - GetTextMetrics(dc, &tm); - - ReleaseDC(NULL, dc); - - if ( x ) - *x = sizeRect.cx; - if ( y ) - *y = sizeRect.cy; - if ( descent ) - *descent = tm.tmDescent; - if ( externalLeading ) - *externalLeading = tm.tmExternalLeading; + const wxFont *fontToUse = theFont; + if (!fontToUse) + fontToUse = &m_font; + + ScreenHDC dc; + SelectInHDC selFont(dc, GetHfontOf(*fontToUse)); + + SIZE sizeRect; + TEXTMETRIC tm; + ::GetTextExtentPoint32(dc, WXSTRINGCAST string, wxStrlen(WXSTRINGCAST string), &sizeRect); + ::GetTextMetrics(dc, &tm); + + if ( x ) + *x = sizeRect.cx; + if ( y ) + *y = sizeRect.cy; + if ( descent ) + *descent = tm.tmDescent; + if ( externalLeading ) + *externalLeading = tm.tmExternalLeading; } -wxMetafile *wxMetafileDC::Close(void) +void wxMetafileDCImpl::DoGetSize(int *width, int *height) const { - SelectOldObjects(m_hDC); - HANDLE mf = CloseMetaFile((HDC) m_hDC); - m_hDC = 0; - if (mf) - { - wxMetafile *wx_mf = new wxMetafile; - wx_mf->SetHMETAFILE((WXHANDLE) mf); - wx_mf->SetWindowsMappingMode(m_windowsMappingMode); - return wx_mf; - } - return NULL; + wxCHECK_RET( m_refData, wxT("invalid wxMetafileDC") ); + + if ( width ) + *width = M_METAFILEDATA->m_width; + if ( height ) + *height = M_METAFILEDATA->m_height; } -void wxMetafileDC::SetMapMode(int mode) +wxMetafile *wxMetafileDCImpl::Close() { - m_mappingMode = mode; + SelectOldObjects(m_hDC); + HANDLE mf = CloseMetaFile((HDC) m_hDC); + m_hDC = 0; + if (mf) + { + wxMetafile *wx_mf = new wxMetafile; + wx_mf->SetHMETAFILE((WXHANDLE) mf); + wx_mf->SetWindowsMappingMode(m_windowsMappingMode); + return wx_mf; + } + return NULL; +} -// int pixel_width = 0; -// int pixel_height = 0; -// int mm_width = 0; -// int mm_height = 0; +void wxMetafileDCImpl::SetMapMode(wxMappingMode mode) +{ + m_mappingMode = mode; - float mm2pixelsX = 10.0; - float mm2pixelsY = 10.0; + // int pixel_width = 0; + // int pixel_height = 0; + // int mm_width = 0; + // int mm_height = 0; - switch (mode) - { - case wxMM_TWIPS: - { - m_logicalScaleX = (float)(twips2mm * mm2pixelsX); - m_logicalScaleY = (float)(twips2mm * mm2pixelsY); - break; - } - case wxMM_POINTS: - { - m_logicalScaleX = (float)(pt2mm * mm2pixelsX); - m_logicalScaleY = (float)(pt2mm * mm2pixelsY); - break; - } - case wxMM_METRIC: - { - m_logicalScaleX = mm2pixelsX; - m_logicalScaleY = mm2pixelsY; - break; - } - case wxMM_LOMETRIC: - { - m_logicalScaleX = (float)(mm2pixelsX/10.0); - m_logicalScaleY = (float)(mm2pixelsY/10.0); - break; - } - default: - case wxMM_TEXT: + float mm2pixelsX = 10.0; + float mm2pixelsY = 10.0; + + switch (mode) { - m_logicalScaleX = 1.0; - m_logicalScaleY = 1.0; - break; + case wxMM_TWIPS: + { + m_logicalScaleX = (float)(twips2mm * mm2pixelsX); + m_logicalScaleY = (float)(twips2mm * mm2pixelsY); + break; + } + case wxMM_POINTS: + { + m_logicalScaleX = (float)(pt2mm * mm2pixelsX); + m_logicalScaleY = (float)(pt2mm * mm2pixelsY); + break; + } + case wxMM_METRIC: + { + m_logicalScaleX = mm2pixelsX; + m_logicalScaleY = mm2pixelsY; + break; + } + case wxMM_LOMETRIC: + { + m_logicalScaleX = (float)(mm2pixelsX/10.0); + m_logicalScaleY = (float)(mm2pixelsY/10.0); + break; + } + default: + case wxMM_TEXT: + { + m_logicalScaleX = 1.0; + m_logicalScaleY = 1.0; + break; + } } - } - m_windowExtX = 100; - m_windowExtY = 100; } +// ---------------------------------------------------------------------------- +// wxMakeMetafilePlaceable +// ---------------------------------------------------------------------------- + #ifdef __WIN32__ struct RECT32 { @@ -287,21 +337,21 @@ struct RECT32 }; struct mfPLACEABLEHEADER { - DWORD key; - short hmf; - RECT32 bbox; - WORD inch; - DWORD reserved; - WORD checksum; + DWORD key; + short hmf; + RECT32 bbox; + WORD inch; + DWORD reserved; + WORD checksum; }; #else struct mfPLACEABLEHEADER { - DWORD key; - HANDLE hmf; - RECT bbox; - WORD inch; - DWORD reserved; - WORD checksum; + DWORD key; + HANDLE hmf; + RECT bbox; + WORD inch; + DWORD reserved; + WORD checksum; }; #endif @@ -311,109 +361,172 @@ struct mfPLACEABLEHEADER { * and sets the window origin and extent to mimic the wxMM_TEXT mapping mode. * */ - + bool wxMakeMetafilePlaceable(const wxString& filename, float scale) { - return wxMakeMetafilePlaceable(filename, 0, 0, 0, 0, scale, FALSE); + return wxMakeMetafilePlaceable(filename, 0, 0, 0, 0, scale, false); } bool wxMakeMetafilePlaceable(const wxString& filename, int x1, int y1, int x2, int y2, float scale, bool useOriginAndExtent) { - // I'm not sure if this is the correct way of suggesting a scale - // to the client application, but it's the only way I can find. - int unitsPerInch = (int)(576/scale); - - mfPLACEABLEHEADER header; - header.key = 0x9AC6CDD7L; - header.hmf = 0; - header.bbox.left = (int)(x1); - header.bbox.top = (int)(y1); - header.bbox.right = (int)(x2); - header.bbox.bottom = (int)(y2); - header.inch = unitsPerInch; - header.reserved = 0; - - // Calculate checksum - WORD *p; - mfPLACEABLEHEADER *pMFHead = &header; - for (p =(WORD *)pMFHead,pMFHead -> checksum = 0; - p < (WORD *)&pMFHead ->checksum; ++p) - pMFHead ->checksum ^= *p; - - FILE *fd = fopen(filename.fn_str(), "rb"); - if (!fd) return FALSE; - - wxChar tempFileBuf[256]; - wxGetTempFileName(T("mf"), tempFileBuf); - FILE *fHandle = fopen(wxConvFile.cWX2MB(tempFileBuf), "wb"); - if (!fHandle) - return FALSE; - fwrite((void *)&header, sizeof(unsigned char), sizeof(mfPLACEABLEHEADER), fHandle); - - // Calculate origin and extent - int originX = x1; - int originY = y1; - int extentX = x2 - x1; - int extentY = (y2 - y1); - - // Read metafile header and write - METAHEADER metaHeader; - fread((void *)&metaHeader, sizeof(unsigned char), sizeof(metaHeader), fd); - - if (useOriginAndExtent) - metaHeader.mtSize += 15; - else - metaHeader.mtSize += 5; - - fwrite((void *)&metaHeader, sizeof(unsigned char), sizeof(metaHeader), fHandle); - - // Write SetMapMode, SetWindowOrigin and SetWindowExt records - char modeBuffer[8]; - char originBuffer[10]; - char extentBuffer[10]; - METARECORD *modeRecord = (METARECORD *)&modeBuffer; - - METARECORD *originRecord = (METARECORD *)&originBuffer; - METARECORD *extentRecord = (METARECORD *)&extentBuffer; - - modeRecord->rdSize = 4; - modeRecord->rdFunction = META_SETMAPMODE; - modeRecord->rdParm[0] = MM_ANISOTROPIC; - - originRecord->rdSize = 5; - originRecord->rdFunction = META_SETWINDOWORG; - originRecord->rdParm[0] = originY; - originRecord->rdParm[1] = originX; - - extentRecord->rdSize = 5; - extentRecord->rdFunction = META_SETWINDOWEXT; - extentRecord->rdParm[0] = extentY; - extentRecord->rdParm[1] = extentX; - - fwrite((void *)modeBuffer, sizeof(char), 8, fHandle); - - if (useOriginAndExtent) - { - fwrite((void *)originBuffer, sizeof(char), 10, fHandle); - fwrite((void *)extentBuffer, sizeof(char), 10, fHandle); - } - - int ch = -2; - while (ch != EOF) - { - ch = getc(fd); - if (ch != EOF) + // I'm not sure if this is the correct way of suggesting a scale + // to the client application, but it's the only way I can find. + int unitsPerInch = (int)(576/scale); + + mfPLACEABLEHEADER header; + header.key = 0x9AC6CDD7L; + header.hmf = 0; + header.bbox.left = (int)(x1); + header.bbox.top = (int)(y1); + header.bbox.right = (int)(x2); + header.bbox.bottom = (int)(y2); + header.inch = unitsPerInch; + header.reserved = 0; + + // Calculate checksum + WORD *p; + mfPLACEABLEHEADER *pMFHead = &header; + for (p =(WORD *)pMFHead,pMFHead -> checksum = 0; + p < (WORD *)&pMFHead ->checksum; ++p) + pMFHead ->checksum ^= *p; + + FILE *fd = wxFopen(filename.fn_str(), wxT("rb")); + if (!fd) return false; + + wxString tempFileBuf = wxFileName::CreateTempFileName(wxT("mf")); + if (tempFileBuf.empty()) + return false; + + FILE *fHandle = wxFopen(tempFileBuf.fn_str(), wxT("wb")); + if (!fHandle) + return false; + fwrite((void *)&header, 1, sizeof(mfPLACEABLEHEADER), fHandle); + + // Calculate origin and extent + int originX = x1; + int originY = y1; + int extentX = x2 - x1; + int extentY = (y2 - y1); + + // Read metafile header and write + METAHEADER metaHeader; + fread((void *)&metaHeader, 1, sizeof(metaHeader), fd); + + if (useOriginAndExtent) + metaHeader.mtSize += 15; + else + metaHeader.mtSize += 5; + + fwrite((void *)&metaHeader, 1, sizeof(metaHeader), fHandle); + + // Write SetMapMode, SetWindowOrigin and SetWindowExt records + char modeBuffer[8]; + char originBuffer[10]; + char extentBuffer[10]; + METARECORD *modeRecord = (METARECORD *)&modeBuffer; + + METARECORD *originRecord = (METARECORD *)&originBuffer; + METARECORD *extentRecord = (METARECORD *)&extentBuffer; + + modeRecord->rdSize = 4; + modeRecord->rdFunction = META_SETMAPMODE; + modeRecord->rdParm[0] = MM_ANISOTROPIC; + + originRecord->rdSize = 5; + originRecord->rdFunction = META_SETWINDOWORG; + originRecord->rdParm[0] = originY; + originRecord->rdParm[1] = originX; + + extentRecord->rdSize = 5; + extentRecord->rdFunction = META_SETWINDOWEXT; + extentRecord->rdParm[0] = extentY; + extentRecord->rdParm[1] = extentX; + + fwrite((void *)modeBuffer, 1, 8, fHandle); + + if (useOriginAndExtent) + { + fwrite((void *)originBuffer, 1, 10, fHandle); + fwrite((void *)extentBuffer, 1, 10, fHandle); + } + + int ch = -2; + while (ch != EOF) { - putc(ch, fHandle); + ch = getc(fd); + if (ch != EOF) + { + putc(ch, fHandle); + } } - } - fclose(fHandle); - fclose(fd); - wxRemoveFile(filename); - wxCopyFile(tempFileBuf, filename); - wxRemoveFile(tempFileBuf); - return TRUE; + fclose(fHandle); + fclose(fd); + wxRemoveFile(filename); + wxCopyFile(tempFileBuf, filename); + wxRemoveFile(tempFileBuf); + return true; } -#endif // wxUSE_METAFILE +#if wxUSE_DRAG_AND_DROP + +// ---------------------------------------------------------------------------- +// wxMetafileDataObject +// ---------------------------------------------------------------------------- + +size_t wxMetafileDataObject::GetDataSize() const +{ + return sizeof(METAFILEPICT); +} + +bool wxMetafileDataObject::GetDataHere(void *buf) const +{ + METAFILEPICT *mfpict = (METAFILEPICT *)buf; + const wxMetafile& mf = GetMetafile(); + + wxCHECK_MSG( mf.GetHMETAFILE(), false, wxT("copying invalid metafile") ); + + // doesn't seem to work with any other mapping mode... + mfpict->mm = MM_ANISOTROPIC; //mf.GetWindowsMappingMode(); + mfpict->xExt = mf.GetWidth(); + mfpict->yExt = mf.GetHeight(); + + // transform the picture size to HIMETRIC units (0.01mm) - as we don't know + // what DC the picture will be rendered to, use the default display one + PixelToHIMETRIC(&mfpict->xExt, &mfpict->yExt); + + mfpict->hMF = CopyMetaFile((HMETAFILE)mf.GetHMETAFILE(), NULL); + + return true; +} + +bool wxMetafileDataObject::SetData(size_t WXUNUSED(len), const void *buf) +{ + const METAFILEPICT *mfpict = (const METAFILEPICT *)buf; + + wxMetafile mf; + mf.SetWindowsMappingMode(mfpict->mm); + + LONG w = mfpict->xExt, + h = mfpict->yExt; + if ( mfpict->mm == MM_ANISOTROPIC ) + { + // in this case xExt and yExt contain suggested size in HIMETRIC units + // (0.01 mm) - transform this to something more reasonable (pixels) + HIMETRICToPixel(&w, &h); + } + + mf.SetWidth(w); + mf.SetHeight(h); + mf.SetHMETAFILE((WXHANDLE)mfpict->hMF); + + wxCHECK_MSG( mfpict->hMF, false, wxT("pasting invalid metafile") ); + + SetMetafile(mf); + + return true; +} + +#endif // wxUSE_DRAG_AND_DROP + +#endif // wxUSE_METAFILE