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