1///////////////////////////////////////////////////////////////////////////// 2// Name: src/msw/dc.cpp 3// Purpose: wxDC class for MSW port 4// Author: Julian Smart 5// Modified by: 6// Created: 01/02/97 7// RCS-ID: $Id: dc.cpp 63769 2010-03-28 22:34:08Z 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/msw/wrapcdlg.h" 29 #include "wx/image.h" 30 #include "wx/window.h" 31 #include "wx/dc.h" 32 #include "wx/utils.h" 33 #include "wx/dialog.h" 34 #include "wx/app.h" 35 #include "wx/bitmap.h" 36 #include "wx/dcmemory.h" 37 #include "wx/log.h" 38 #include "wx/icon.h" 39 #include "wx/dcprint.h" 40 #include "wx/module.h" 41#endif 42 43#include "wx/sysopt.h" 44#include "wx/dynlib.h" 45 46#ifdef wxHAVE_RAW_BITMAP 47#include "wx/rawbmp.h" 48#endif 49 50#include <string.h> 51 52#ifndef __WIN32__ 53 #include <print.h> 54#endif 55 56#ifndef AC_SRC_ALPHA 57 #define AC_SRC_ALPHA 1 58#endif 59 60#ifndef LAYOUT_RTL 61 #define LAYOUT_RTL 1 62#endif 63 64/* Quaternary raster codes */ 65#ifndef MAKEROP4 66#define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore)) 67#endif 68 69// apparently with MicroWindows it is possible that HDC is 0 so we have to 70// check for this ourselves 71#ifdef __WXMICROWIN__ 72 #define WXMICROWIN_CHECK_HDC if ( !GetHDC() ) return; 73 #define WXMICROWIN_CHECK_HDC_RET(x) if ( !GetHDC() ) return x; 74#else 75 #define WXMICROWIN_CHECK_HDC 76 #define WXMICROWIN_CHECK_HDC_RET(x) 77#endif 78 79IMPLEMENT_ABSTRACT_CLASS(wxDC, wxDCBase) 80 81// --------------------------------------------------------------------------- 82// constants 83// --------------------------------------------------------------------------- 84 85static const int VIEWPORT_EXTENT = 1000; 86 87static const int MM_POINTS = 9; 88static const int MM_METRIC = 10; 89 90// ROPs which don't have standard names (see "Ternary Raster Operations" in the 91// MSDN docs for how this and other numbers in wxDC::Blit() are obtained) 92#define DSTCOPY 0x00AA0029 // a.k.a. NOP operation 93 94// ---------------------------------------------------------------------------- 95// macros for logical <-> device coords conversion 96// ---------------------------------------------------------------------------- 97 98/* 99 We currently let Windows do all the translations itself so these macros are 100 not really needed (any more) but keep them to enhance readability of the 101 code by allowing to see where are the logical and where are the device 102 coordinates used. 103 */ 104 105#ifdef __WXWINCE__ 106 #define XLOG2DEV(x) ((x-m_logicalOriginX)*m_signX) 107 #define YLOG2DEV(y) ((y-m_logicalOriginY)*m_signY) 108 #define XDEV2LOG(x) ((x)*m_signX+m_logicalOriginX) 109 #define YDEV2LOG(y) ((y)*m_signY+m_logicalOriginY) 110#else 111 #define XLOG2DEV(x) (x) 112 #define YLOG2DEV(y) (y) 113 #define XDEV2LOG(x) (x) 114 #define YDEV2LOG(y) (y) 115#endif 116 117// --------------------------------------------------------------------------- 118// private functions 119// --------------------------------------------------------------------------- 120 121// convert degrees to radians 122static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; } 123 124// call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha 125// 126// NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed 127// to pass it to this function but as we already have it at the point 128// of call anyhow we do 129// 130// return true if we could draw the bitmap in one way or the other, false 131// otherwise 132static bool AlphaBlt(HDC hdcDst, 133 int x, int y, int w, int h, 134 int srcX, int srcY, HDC hdcSrc, 135 const wxBitmap& bmpSrc); 136 137#ifdef wxHAVE_RAW_BITMAP 138 139// our (limited) AlphaBlend() replacement for Windows versions not providing it 140static void 141wxAlphaBlend(HDC hdcDst, int x, int y, int w, int h, 142 int srcX, int srcY, const wxBitmap& bmp); 143 144#endif // wxHAVE_RAW_BITMAP 145 146// ---------------------------------------------------------------------------- 147// private classes 148// ---------------------------------------------------------------------------- 149 150// instead of duplicating the same code which sets and then restores text 151// colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes, 152// encapsulate this in a small helper class 153 154// wxColourChanger: changes the text colours in the ctor if required and 155// restores them in the dtor 156class wxColourChanger 157{ 158public: 159 wxColourChanger(wxDC& dc); 160 ~wxColourChanger(); 161 162private: 163 wxDC& m_dc; 164 165 COLORREF m_colFgOld, m_colBgOld; 166 167 bool m_changed; 168 169 DECLARE_NO_COPY_CLASS(wxColourChanger) 170}; 171 172// this class saves the old stretch blit mode during its life time 173class StretchBltModeChanger 174{ 175public: 176 StretchBltModeChanger(HDC hdc, 177 int WXUNUSED_IN_WINCE(mode)) 178 : m_hdc(hdc) 179 { 180#ifndef __WXWINCE__ 181 m_modeOld = ::SetStretchBltMode(m_hdc, mode); 182 if ( !m_modeOld ) 183 wxLogLastError(_T("SetStretchBltMode")); 184#endif 185 } 186 187 ~StretchBltModeChanger() 188 { 189#ifndef __WXWINCE__ 190 if ( !::SetStretchBltMode(m_hdc, m_modeOld) ) 191 wxLogLastError(_T("SetStretchBltMode")); 192#endif 193 } 194 195private: 196 const HDC m_hdc; 197 198 int m_modeOld; 199 200 DECLARE_NO_COPY_CLASS(StretchBltModeChanger) 201}; 202 203// helper class to cache dynamically loaded libraries and not attempt reloading 204// them if it fails 205class wxOnceOnlyDLLLoader 206{ 207public: 208 // ctor argument must be a literal string as we don't make a copy of it! 209 wxOnceOnlyDLLLoader(const wxChar *dllName) 210 : m_dllName(dllName) 211 { 212 } 213 214 215 // return the symbol with the given name or NULL if the DLL not loaded 216 // or symbol not present 217 void *GetSymbol(const wxChar *name) 218 { 219 // we're prepared to handle errors here 220 wxLogNull noLog; 221 222 if ( m_dllName ) 223 { 224 m_dll.Load(m_dllName); 225 226 // reset the name whether we succeeded or failed so that we don't 227 // try again the next time 228 m_dllName = NULL; 229 } 230 231 return m_dll.IsLoaded() ? m_dll.GetSymbol(name) : NULL; 232 } 233 234private: 235 wxDynamicLibrary m_dll; 236 const wxChar *m_dllName; 237}; 238 239static wxOnceOnlyDLLLoader wxGDI32DLL(_T("gdi32")); 240static wxOnceOnlyDLLLoader wxMSIMG32DLL(_T("msimg32")); 241 242// =========================================================================== 243// implementation 244// =========================================================================== 245 246// ---------------------------------------------------------------------------- 247// wxColourChanger 248// ---------------------------------------------------------------------------- 249 250wxColourChanger::wxColourChanger(wxDC& dc) : m_dc(dc) 251{ 252 const wxBrush& brush = dc.GetBrush(); 253 if ( brush.Ok() && brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE ) 254 { 255 HDC hdc = GetHdcOf(dc); 256 m_colFgOld = ::GetTextColor(hdc); 257 m_colBgOld = ::GetBkColor(hdc); 258 259 // note that Windows convention is opposite to wxWidgets one, this is 260 // why text colour becomes the background one and vice versa 261 const wxColour& colFg = dc.GetTextForeground(); 262 if ( colFg.Ok() ) 263 { 264 ::SetBkColor(hdc, colFg.GetPixel()); 265 } 266 267 const wxColour& colBg = dc.GetTextBackground(); 268 if ( colBg.Ok() ) 269 { 270 ::SetTextColor(hdc, colBg.GetPixel()); 271 } 272 273 SetBkMode(hdc, 274 dc.GetBackgroundMode() == wxTRANSPARENT ? TRANSPARENT 275 : OPAQUE); 276 277 // flag which telsl us to undo changes in the dtor 278 m_changed = true; 279 } 280 else 281 { 282 // nothing done, nothing to undo 283 m_changed = false; 284 } 285} 286 287wxColourChanger::~wxColourChanger() 288{ 289 if ( m_changed ) 290 { 291 // restore the colours we changed 292 HDC hdc = GetHdcOf(m_dc); 293 294 ::SetBkMode(hdc, TRANSPARENT); 295 ::SetTextColor(hdc, m_colFgOld); 296 ::SetBkColor(hdc, m_colBgOld); 297 } 298} 299 300// --------------------------------------------------------------------------- 301// wxDC 302// --------------------------------------------------------------------------- 303 304wxDC::~wxDC() 305{ 306 if ( m_hDC != 0 ) 307 { 308 SelectOldObjects(m_hDC); 309 310 // if we own the HDC, we delete it, otherwise we just release it 311 312 if ( m_bOwnsDC ) 313 { 314 ::DeleteDC(GetHdc()); 315 } 316 else // we don't own our HDC 317 { 318 if (m_canvas) 319 { 320 ::ReleaseDC(GetHwndOf(m_canvas), GetHdc()); 321 } 322 else 323 { 324 // Must have been a wxScreenDC 325 ::ReleaseDC((HWND) NULL, GetHdc()); 326 } 327 } 328 } 329} 330 331// This will select current objects out of the DC, 332// which is what you have to do before deleting the 333// DC. 334void wxDC::SelectOldObjects(WXHDC dc) 335{ 336 if (dc) 337 { 338 if (m_oldBitmap) 339 { 340 ::SelectObject((HDC) dc, (HBITMAP) m_oldBitmap); 341#ifdef __WXDEBUG__ 342 if (m_selectedBitmap.Ok()) 343 { 344 m_selectedBitmap.SetSelectedInto(NULL); 345 } 346#endif 347 } 348 m_oldBitmap = 0; 349 if (m_oldPen) 350 { 351 ::SelectObject((HDC) dc, (HPEN) m_oldPen); 352 } 353 m_oldPen = 0; 354 if (m_oldBrush) 355 { 356 ::SelectObject((HDC) dc, (HBRUSH) m_oldBrush); 357 } 358 m_oldBrush = 0; 359 if (m_oldFont) 360 { 361 ::SelectObject((HDC) dc, (HFONT) m_oldFont); 362 } 363 m_oldFont = 0; 364 365#if wxUSE_PALETTE 366 if (m_oldPalette) 367 { 368 ::SelectPalette((HDC) dc, (HPALETTE) m_oldPalette, FALSE); 369 } 370 m_oldPalette = 0; 371#endif // wxUSE_PALETTE 372 } 373 374 m_brush = wxNullBrush; 375 m_pen = wxNullPen; 376#if wxUSE_PALETTE 377 m_palette = wxNullPalette; 378#endif // wxUSE_PALETTE 379 m_font = wxNullFont; 380 m_backgroundBrush = wxNullBrush; 381 m_selectedBitmap = wxNullBitmap; 382} 383 384// --------------------------------------------------------------------------- 385// clipping 386// --------------------------------------------------------------------------- 387 388void wxDC::UpdateClipBox() 389{ 390 WXMICROWIN_CHECK_HDC 391 392 RECT rect; 393 ::GetClipBox(GetHdc(), &rect); 394 395 m_clipX1 = (wxCoord) XDEV2LOG(rect.left); 396 m_clipY1 = (wxCoord) YDEV2LOG(rect.top); 397 m_clipX2 = (wxCoord) XDEV2LOG(rect.right); 398 m_clipY2 = (wxCoord) YDEV2LOG(rect.bottom); 399} 400 401void 402wxDC::DoGetClippingBox(wxCoord *x, wxCoord *y, wxCoord *w, wxCoord *h) const 403{ 404 // check if we should try to retrieve the clipping region possibly not set 405 // by our SetClippingRegion() but preset by Windows:this can only happen 406 // when we're associated with an existing HDC usign SetHDC(), see there 407 if ( m_clipping && !m_clipX1 && !m_clipX2 ) 408 { 409 wxDC *self = wxConstCast(this, wxDC); 410 self->UpdateClipBox(); 411 412 if ( !m_clipX1 && !m_clipX2 ) 413 self->m_clipping = false; 414 } 415 416 wxDCBase::DoGetClippingBox(x, y, w, h); 417} 418 419// common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion() 420void wxDC::SetClippingHrgn(WXHRGN hrgn) 421{ 422 wxCHECK_RET( hrgn, wxT("invalid clipping region") ); 423 424 WXMICROWIN_CHECK_HDC 425 426 // note that we combine the new clipping region with the existing one: this 427 // is compatible with what the other ports do and is the documented 428 // behaviour now (starting with 2.3.3) 429#if defined(__WXWINCE__) 430 RECT rectClip; 431 if ( !::GetClipBox(GetHdc(), &rectClip) ) 432 return; 433 434 // GetClipBox returns logical coordinates, so transform to device 435 rectClip.left = LogicalToDeviceX(rectClip.left); 436 rectClip.top = LogicalToDeviceY(rectClip.top); 437 rectClip.right = LogicalToDeviceX(rectClip.right); 438 rectClip.bottom = LogicalToDeviceY(rectClip.bottom); 439 440 HRGN hrgnDest = ::CreateRectRgn(0, 0, 0, 0); 441 HRGN hrgnClipOld = ::CreateRectRgn(rectClip.left, rectClip.top, 442 rectClip.right, rectClip.bottom); 443 444 if ( ::CombineRgn(hrgnDest, hrgnClipOld, (HRGN)hrgn, RGN_AND) != ERROR ) 445 { 446 ::SelectClipRgn(GetHdc(), hrgnDest); 447 } 448 449 ::DeleteObject(hrgnClipOld); 450 ::DeleteObject(hrgnDest); 451#else // !WinCE 452 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN)hrgn, RGN_AND) == ERROR ) 453 { 454 wxLogLastError(_T("ExtSelectClipRgn")); 455 456 return; 457 } 458#endif // WinCE/!WinCE 459 460 m_clipping = true; 461 462 UpdateClipBox(); 463} 464 465void wxDC::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h) 466{ 467 // the region coords are always the device ones, so do the translation 468 // manually 469 // 470 // FIXME: possible +/-1 error here, to check! 471 HRGN hrgn = ::CreateRectRgn(LogicalToDeviceX(x), 472 LogicalToDeviceY(y), 473 LogicalToDeviceX(x + w), 474 LogicalToDeviceY(y + h)); 475 if ( !hrgn ) 476 { 477 wxLogLastError(_T("CreateRectRgn")); 478 } 479 else 480 { 481 SetClippingHrgn((WXHRGN)hrgn); 482 483 ::DeleteObject(hrgn); 484 } 485} 486 487void wxDC::DoSetClippingRegionAsRegion(const wxRegion& region) 488{ 489 SetClippingHrgn(region.GetHRGN()); 490} 491 492void wxDC::DestroyClippingRegion() 493{ 494 WXMICROWIN_CHECK_HDC 495 496 if (m_clipping && m_hDC) 497 { 498#if 1 499 // On a PocketPC device (not necessarily emulator), resetting 500 // the clip region as per the old method causes bad display 501 // problems. In fact setting a null region is probably OK 502 // on desktop WIN32 also, since the WIN32 docs imply that the user 503 // clipping region is independent from the paint clipping region. 504 ::SelectClipRgn(GetHdc(), 0); 505#else 506 // TODO: this should restore the previous clipping region, 507 // so that OnPaint processing works correctly, and the update 508 // clipping region doesn't get destroyed after the first 509 // DestroyClippingRegion. 510 HRGN rgn = CreateRectRgn(0, 0, 32000, 32000); 511 ::SelectClipRgn(GetHdc(), rgn); 512 ::DeleteObject(rgn); 513#endif 514 } 515 516 wxDCBase::DestroyClippingRegion(); 517} 518 519// --------------------------------------------------------------------------- 520// query capabilities 521// --------------------------------------------------------------------------- 522 523bool wxDC::CanDrawBitmap() const 524{ 525 return true; 526} 527 528bool wxDC::CanGetTextExtent() const 529{ 530#ifdef __WXMICROWIN__ 531 // TODO Extend MicroWindows' GetDeviceCaps function 532 return true; 533#else 534 // What sort of display is it? 535 int technology = ::GetDeviceCaps(GetHdc(), TECHNOLOGY); 536 537 return (technology == DT_RASDISPLAY) || (technology == DT_RASPRINTER); 538#endif 539} 540 541int wxDC::GetDepth() const 542{ 543 WXMICROWIN_CHECK_HDC_RET(16) 544 545 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL); 546} 547 548// --------------------------------------------------------------------------- 549// drawing 550// --------------------------------------------------------------------------- 551 552void wxDC::Clear() 553{ 554 WXMICROWIN_CHECK_HDC 555 556 RECT rect; 557 if ( m_canvas ) 558 { 559 GetClientRect((HWND) m_canvas->GetHWND(), &rect); 560 } 561 else 562 { 563 // No, I think we should simply ignore this if printing on e.g. 564 // a printer DC. 565 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") ); 566 if (!m_selectedBitmap.Ok()) 567 return; 568 569 rect.left = -m_deviceOriginX; rect.top = -m_deviceOriginY; 570 rect.right = m_selectedBitmap.GetWidth()-m_deviceOriginX; 571 rect.bottom = m_selectedBitmap.GetHeight()-m_deviceOriginY; 572 } 573 574#ifndef __WXWINCE__ 575 (void) ::SetMapMode(GetHdc(), MM_TEXT); 576#endif 577 578 DWORD colour = ::GetBkColor(GetHdc()); 579 HBRUSH brush = ::CreateSolidBrush(colour); 580 ::FillRect(GetHdc(), &rect, brush); 581 ::DeleteObject(brush); 582 583#ifndef __WXWINCE__ 584 int width = DeviceToLogicalXRel(VIEWPORT_EXTENT)*m_signX, 585 height = DeviceToLogicalYRel(VIEWPORT_EXTENT)*m_signY; 586 587 ::SetMapMode(GetHdc(), MM_ANISOTROPIC); 588 589 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT, VIEWPORT_EXTENT, NULL); 590 ::SetWindowExtEx(GetHdc(), width, height, NULL); 591 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL); 592 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX, (int)m_logicalOriginY, NULL); 593#endif 594} 595 596bool wxDC::DoFloodFill(wxCoord WXUNUSED_IN_WINCE(x), 597 wxCoord WXUNUSED_IN_WINCE(y), 598 const wxColour& WXUNUSED_IN_WINCE(col), 599 int WXUNUSED_IN_WINCE(style)) 600{ 601#ifdef __WXWINCE__ 602 return false; 603#else 604 WXMICROWIN_CHECK_HDC_RET(false) 605 606 bool success = (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), 607 col.GetPixel(), 608 style == wxFLOOD_SURFACE ? FLOODFILLSURFACE 609 : FLOODFILLBORDER) ) ; 610 if (!success) 611 { 612 // quoting from the MSDN docs: 613 // 614 // Following are some of the reasons this function might fail: 615 // 616 // * The filling could not be completed. 617 // * The specified point has the boundary color specified by the 618 // crColor parameter (if FLOODFILLBORDER was requested). 619 // * The specified point does not have the color specified by 620 // crColor (if FLOODFILLSURFACE was requested) 621 // * The point is outside the clipping region that is, it is not 622 // visible on the device. 623 // 624 wxLogLastError(wxT("ExtFloodFill")); 625 } 626 627 CalcBoundingBox(x, y); 628 629 return success; 630#endif 631} 632 633bool wxDC::DoGetPixel(wxCoord x, wxCoord y, wxColour *col) const 634{ 635 WXMICROWIN_CHECK_HDC_RET(false) 636 637 wxCHECK_MSG( col, false, _T("NULL colour parameter in wxDC::GetPixel") ); 638 639 // get the color of the pixel 640 COLORREF pixelcolor = ::GetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y)); 641 642 wxRGBToColour(*col, pixelcolor); 643 644 return true; 645} 646 647void wxDC::DoCrossHair(wxCoord x, wxCoord y) 648{ 649 WXMICROWIN_CHECK_HDC 650 651 wxCoord x1 = x-VIEWPORT_EXTENT; 652 wxCoord y1 = y-VIEWPORT_EXTENT; 653 wxCoord x2 = x+VIEWPORT_EXTENT; 654 wxCoord y2 = y+VIEWPORT_EXTENT; 655 656 wxDrawLine(GetHdc(), XLOG2DEV(x1), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y)); 657 wxDrawLine(GetHdc(), XLOG2DEV(x), YLOG2DEV(y1), XLOG2DEV(x), YLOG2DEV(y2)); 658 659 CalcBoundingBox(x1, y1); 660 CalcBoundingBox(x2, y2); 661} 662 663void wxDC::DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2) 664{ 665 WXMICROWIN_CHECK_HDC 666 667 wxDrawLine(GetHdc(), XLOG2DEV(x1), YLOG2DEV(y1), XLOG2DEV(x2), YLOG2DEV(y2)); 668 669 CalcBoundingBox(x1, y1); 670 CalcBoundingBox(x2, y2); 671} 672 673// Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1) 674// and ending at (x2, y2) 675void wxDC::DoDrawArc(wxCoord x1, wxCoord y1, 676 wxCoord x2, wxCoord y2, 677 wxCoord xc, wxCoord yc) 678{ 679 double dx = xc - x1; 680 double dy = yc - y1; 681 wxCoord r = (wxCoord)sqrt(dx*dx + dy*dy); 682 683#ifdef __WXWINCE__ 684 // Slower emulation since WinCE doesn't support Pie and Arc 685 double sa = acos((x1-xc)/r)/M_PI*180; // between 0 and 180 686 if( y1>yc ) sa = -sa; // below center 687 double ea = atan2(yc-y2, x2-xc)/M_PI*180; 688 DoDrawEllipticArcRot( xc-r, yc-r, 2*r, 2*r, sa, ea ); 689#else 690 691 WXMICROWIN_CHECK_HDC 692 693 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 694 695 // treat the special case of full circle separately 696 if ( x1 == x2 && y1 == y2 ) 697 { 698 DrawEllipse(xc - r, yc - r, 2*r, 2*r); 699 return; 700 } 701 702 wxCoord xx1 = XLOG2DEV(x1); 703 wxCoord yy1 = YLOG2DEV(y1); 704 wxCoord xx2 = XLOG2DEV(x2); 705 wxCoord yy2 = YLOG2DEV(y2); 706 wxCoord xxc = XLOG2DEV(xc); 707 wxCoord yyc = YLOG2DEV(yc); 708 dx = xxc - xx1; 709 dy = yyc - yy1; 710 wxCoord ray = (wxCoord)sqrt(dx*dx + dy*dy); 711 712 wxCoord xxx1 = (wxCoord) (xxc-ray); 713 wxCoord yyy1 = (wxCoord) (yyc-ray); 714 wxCoord xxx2 = (wxCoord) (xxc+ray); 715 wxCoord yyy2 = (wxCoord) (yyc+ray); 716 717 if ( m_brush.Ok() && m_brush.GetStyle() != wxTRANSPARENT ) 718 { 719 // Have to add 1 to bottom-right corner of rectangle 720 // to make semi-circles look right (crooked line otherwise). 721 // Unfortunately this is not a reliable method, depends 722 // on the size of shape. 723 // TODO: figure out why this happens! 724 Pie(GetHdc(),xxx1,yyy1,xxx2+1,yyy2+1, xx1,yy1,xx2,yy2); 725 } 726 else 727 { 728 Arc(GetHdc(),xxx1,yyy1,xxx2,yyy2, xx1,yy1,xx2,yy2); 729 } 730 731 CalcBoundingBox(xc - r, yc - r); 732 CalcBoundingBox(xc + r, yc + r); 733#endif 734} 735 736void wxDC::DoDrawCheckMark(wxCoord x1, wxCoord y1, 737 wxCoord width, wxCoord height) 738{ 739 // cases when we don't have DrawFrameControl() 740#if defined(__SYMANTEC__) || defined(__WXMICROWIN__) 741 return wxDCBase::DoDrawCheckMark(x1, y1, width, height); 742#else // normal case 743 wxCoord x2 = x1 + width, 744 y2 = y1 + height; 745 746 RECT rect; 747 rect.left = x1; 748 rect.top = y1; 749 rect.right = x2; 750 rect.bottom = y2; 751 752#ifdef __WXWINCE__ 753 DrawFrameControl(GetHdc(), &rect, DFC_BUTTON, DFCS_BUTTONCHECK); 754#else 755 DrawFrameControl(GetHdc(), &rect, DFC_MENU, DFCS_MENUCHECK); 756#endif 757 758 CalcBoundingBox(x1, y1); 759 CalcBoundingBox(x2, y2); 760#endif // Microwin/Normal 761} 762 763void wxDC::DoDrawPoint(wxCoord x, wxCoord y) 764{ 765 WXMICROWIN_CHECK_HDC 766 767 COLORREF color = 0x00ffffff; 768 if (m_pen.Ok()) 769 { 770 color = m_pen.GetColour().GetPixel(); 771 } 772 773 SetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), color); 774 775 CalcBoundingBox(x, y); 776} 777 778void wxDC::DoDrawPolygon(int n, 779 wxPoint points[], 780 wxCoord xoffset, 781 wxCoord yoffset, 782 int WXUNUSED_IN_WINCE(fillStyle)) 783{ 784 WXMICROWIN_CHECK_HDC 785 786 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 787 788 // Do things less efficiently if we have offsets 789 if (xoffset != 0 || yoffset != 0) 790 { 791 POINT *cpoints = new POINT[n]; 792 int i; 793 for (i = 0; i < n; i++) 794 { 795 cpoints[i].x = (int)(points[i].x + xoffset); 796 cpoints[i].y = (int)(points[i].y + yoffset); 797 798 CalcBoundingBox(cpoints[i].x, cpoints[i].y); 799 } 800#ifndef __WXWINCE__ 801 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING); 802#endif 803 (void)Polygon(GetHdc(), cpoints, n); 804#ifndef __WXWINCE__ 805 SetPolyFillMode(GetHdc(),prev); 806#endif 807 delete[] cpoints; 808 } 809 else 810 { 811 int i; 812 for (i = 0; i < n; i++) 813 CalcBoundingBox(points[i].x, points[i].y); 814 815#ifndef __WXWINCE__ 816 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING); 817#endif 818 (void)Polygon(GetHdc(), (POINT*) points, n); 819#ifndef __WXWINCE__ 820 SetPolyFillMode(GetHdc(),prev); 821#endif 822 } 823} 824 825void 826wxDC::DoDrawPolyPolygon(int n, 827 int count[], 828 wxPoint points[], 829 wxCoord xoffset, 830 wxCoord yoffset, 831 int fillStyle) 832{ 833#ifdef __WXWINCE__ 834 wxDCBase::DoDrawPolyPolygon(n, count, points, xoffset, yoffset, fillStyle); 835#else 836 WXMICROWIN_CHECK_HDC 837 838 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 839 int i, cnt; 840 for (i = cnt = 0; i < n; i++) 841 cnt += count[i]; 842 843 // Do things less efficiently if we have offsets 844 if (xoffset != 0 || yoffset != 0) 845 { 846 POINT *cpoints = new POINT[cnt]; 847 for (i = 0; i < cnt; i++) 848 { 849 cpoints[i].x = (int)(points[i].x + xoffset); 850 cpoints[i].y = (int)(points[i].y + yoffset); 851 852 CalcBoundingBox(cpoints[i].x, cpoints[i].y); 853 } 854#ifndef __WXWINCE__ 855 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING); 856#endif 857 (void)PolyPolygon(GetHdc(), cpoints, count, n); 858#ifndef __WXWINCE__ 859 SetPolyFillMode(GetHdc(),prev); 860#endif 861 delete[] cpoints; 862 } 863 else 864 { 865 for (i = 0; i < cnt; i++) 866 CalcBoundingBox(points[i].x, points[i].y); 867 868#ifndef __WXWINCE__ 869 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING); 870#endif 871 (void)PolyPolygon(GetHdc(), (POINT*) points, count, n); 872#ifndef __WXWINCE__ 873 SetPolyFillMode(GetHdc(),prev); 874#endif 875 } 876#endif 877 // __WXWINCE__ 878} 879 880void wxDC::DoDrawLines(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset) 881{ 882 WXMICROWIN_CHECK_HDC 883 884 // Do things less efficiently if we have offsets 885 if (xoffset != 0 || yoffset != 0) 886 { 887 POINT *cpoints = new POINT[n]; 888 int i; 889 for (i = 0; i < n; i++) 890 { 891 cpoints[i].x = (int)(points[i].x + xoffset); 892 cpoints[i].y = (int)(points[i].y + yoffset); 893 894 CalcBoundingBox(cpoints[i].x, cpoints[i].y); 895 } 896 (void)Polyline(GetHdc(), cpoints, n); 897 delete[] cpoints; 898 } 899 else 900 { 901 int i; 902 for (i = 0; i < n; i++) 903 CalcBoundingBox(points[i].x, points[i].y); 904 905 (void)Polyline(GetHdc(), (POINT*) points, n); 906 } 907} 908 909void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height) 910{ 911 WXMICROWIN_CHECK_HDC 912 913 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 914 915 wxCoord x2 = x + width; 916 wxCoord y2 = y + height; 917 918 if ((m_logicalFunction == wxCOPY) && (m_pen.GetStyle() == wxTRANSPARENT)) 919 { 920 RECT rect; 921 rect.left = XLOG2DEV(x); 922 rect.top = YLOG2DEV(y); 923 rect.right = XLOG2DEV(x2); 924 rect.bottom = YLOG2DEV(y2); 925 (void)FillRect(GetHdc(), &rect, (HBRUSH)m_brush.GetResourceHandle() ); 926 } 927 else 928 { 929 // Windows draws the filled rectangles without outline (i.e. drawn with a 930 // transparent pen) one pixel smaller in both directions and we want them 931 // to have the same size regardless of which pen is used - adjust 932 933 // I wonder if this shouldnt be done after the LOG2DEV() conversions. RR. 934 if ( m_pen.GetStyle() == wxTRANSPARENT ) 935 { 936 // Apparently not needed for WinCE (see e.g. Life! demo) 937#ifndef __WXWINCE__ 938 x2++; 939 y2++; 940#endif 941 } 942 943 (void)Rectangle(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2)); 944 } 945 946 947 CalcBoundingBox(x, y); 948 CalcBoundingBox(x2, y2); 949} 950 951void wxDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius) 952{ 953 WXMICROWIN_CHECK_HDC 954 955 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 956 957 // Now, a negative radius value is interpreted to mean 958 // 'the proportion of the smallest X or Y dimension' 959 960 if (radius < 0.0) 961 { 962 double smallest = (width < height) ? width : height; 963 radius = (- radius * smallest); 964 } 965 966 wxCoord x2 = (x+width); 967 wxCoord y2 = (y+height); 968 969 // Windows draws the filled rectangles without outline (i.e. drawn with a 970 // transparent pen) one pixel smaller in both directions and we want them 971 // to have the same size regardless of which pen is used - adjust 972 if ( m_pen.GetStyle() == wxTRANSPARENT ) 973 { 974 x2++; 975 y2++; 976 } 977 978 (void)RoundRect(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), 979 YLOG2DEV(y2), (int) (2*XLOG2DEV(radius)), (int)( 2*YLOG2DEV(radius))); 980 981 CalcBoundingBox(x, y); 982 CalcBoundingBox(x2, y2); 983} 984 985void wxDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height) 986{ 987 WXMICROWIN_CHECK_HDC 988 989 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 990 991 wxCoord x2 = (x+width); 992 wxCoord y2 = (y+height); 993 994 (void)Ellipse(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2)); 995 996 CalcBoundingBox(x, y); 997 CalcBoundingBox(x2, y2); 998} 999 1000#if wxUSE_SPLINES 1001void wxDC::DoDrawSpline(wxList *points) 1002{ 1003#ifdef __WXWINCE__ 1004 // WinCE does not support ::PolyBezier so use generic version 1005 wxDCBase::DoDrawSpline(points); 1006#else 1007 // quadratic b-spline to cubic bezier spline conversion 1008 // 1009 // quadratic spline with control points P0,P1,P2 1010 // P(s) = P0*(1-s)^2 + P1*2*(1-s)*s + P2*s^2 1011 // 1012 // bezier spline with control points B0,B1,B2,B3 1013 // B(s) = B0*(1-s)^3 + B1*3*(1-s)^2*s + B2*3*(1-s)*s^2 + B3*s^3 1014 // 1015 // control points of bezier spline calculated from b-spline 1016 // B0 = P0 1017 // B1 = (2*P1 + P0)/3 1018 // B2 = (2*P1 + P2)/3 1019 // B3 = P2 1020 1021 WXMICROWIN_CHECK_HDC 1022 1023 wxASSERT_MSG( points, wxT("NULL pointer to spline points?") ); 1024 1025 const size_t n_points = points->GetCount(); 1026 wxASSERT_MSG( n_points > 2 , wxT("incomplete list of spline points?") ); 1027 1028 const size_t n_bezier_points = n_points * 3 + 1; 1029 POINT *lppt = (POINT *)malloc(n_bezier_points*sizeof(POINT)); 1030 size_t bezier_pos = 0; 1031 wxCoord x1, y1, x2, y2, cx1, cy1, cx4, cy4; 1032 1033 wxList::compatibility_iterator node = points->GetFirst(); 1034 wxPoint *p = (wxPoint *)node->GetData(); 1035 lppt[ bezier_pos ].x = x1 = p->x; 1036 lppt[ bezier_pos ].y = y1 = p->y; 1037 bezier_pos++; 1038 lppt[ bezier_pos ] = lppt[ bezier_pos-1 ]; 1039 bezier_pos++; 1040 1041 node = node->GetNext(); 1042 p = (wxPoint *)node->GetData(); 1043 1044 x2 = p->x; 1045 y2 = p->y; 1046 cx1 = ( x1 + x2 ) / 2; 1047 cy1 = ( y1 + y2 ) / 2; 1048 lppt[ bezier_pos ].x = XLOG2DEV(cx1); 1049 lppt[ bezier_pos ].y = YLOG2DEV(cy1); 1050 bezier_pos++; 1051 lppt[ bezier_pos ] = lppt[ bezier_pos-1 ]; 1052 bezier_pos++; 1053 1054#if !wxUSE_STL 1055 while ((node = node->GetNext()) != NULL) 1056#else 1057 while ((node = node->GetNext())) 1058#endif // !wxUSE_STL 1059 { 1060 p = (wxPoint *)node->GetData(); 1061 x1 = x2; 1062 y1 = y2; 1063 x2 = p->x; 1064 y2 = p->y; 1065 cx4 = (x1 + x2) / 2; 1066 cy4 = (y1 + y2) / 2; 1067 // B0 is B3 of previous segment 1068 // B1: 1069 lppt[ bezier_pos ].x = XLOG2DEV((x1*2+cx1)/3); 1070 lppt[ bezier_pos ].y = YLOG2DEV((y1*2+cy1)/3); 1071 bezier_pos++; 1072 // B2: 1073 lppt[ bezier_pos ].x = XLOG2DEV((x1*2+cx4)/3); 1074 lppt[ bezier_pos ].y = YLOG2DEV((y1*2+cy4)/3); 1075 bezier_pos++; 1076 // B3: 1077 lppt[ bezier_pos ].x = XLOG2DEV(cx4); 1078 lppt[ bezier_pos ].y = YLOG2DEV(cy4); 1079 bezier_pos++; 1080 cx1 = cx4; 1081 cy1 = cy4; 1082 } 1083 1084 lppt[ bezier_pos ] = lppt[ bezier_pos-1 ]; 1085 bezier_pos++; 1086 lppt[ bezier_pos ].x = XLOG2DEV(x2); 1087 lppt[ bezier_pos ].y = YLOG2DEV(y2); 1088 bezier_pos++; 1089 lppt[ bezier_pos ] = lppt[ bezier_pos-1 ]; 1090 bezier_pos++; 1091 1092 ::PolyBezier( GetHdc(), lppt, bezier_pos ); 1093 1094 free(lppt); 1095#endif 1096} 1097#endif 1098 1099// Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows 1100void wxDC::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea) 1101{ 1102#ifdef __WXWINCE__ 1103 DoDrawEllipticArcRot( x, y, w, h, sa, ea ); 1104#else 1105 1106 WXMICROWIN_CHECK_HDC 1107 1108 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 1109 1110 wxCoord x2 = x + w; 1111 wxCoord y2 = y + h; 1112 1113 int rx1 = XLOG2DEV(x+w/2); 1114 int ry1 = YLOG2DEV(y+h/2); 1115 int rx2 = rx1; 1116 int ry2 = ry1; 1117 1118 sa = DegToRad(sa); 1119 ea = DegToRad(ea); 1120 1121 rx1 += (int)(100.0 * abs(w) * cos(sa)); 1122 ry1 -= (int)(100.0 * abs(h) * m_signY * sin(sa)); 1123 rx2 += (int)(100.0 * abs(w) * cos(ea)); 1124 ry2 -= (int)(100.0 * abs(h) * m_signY * sin(ea)); 1125 1126 // Swap start and end positions if the end angle is less than the start angle. 1127 if (ea < sa) { 1128 int temp; 1129 temp = rx2; 1130 rx2 = rx1; 1131 rx1 = temp; 1132 temp = ry2; 1133 ry2 = ry1; 1134 ry1 = temp; 1135 } 1136 1137 // draw pie with NULL_PEN first and then outline otherwise a line is 1138 // drawn from the start and end points to the centre 1139 HPEN hpenOld = (HPEN) ::SelectObject(GetHdc(), (HPEN) ::GetStockObject(NULL_PEN)); 1140 if (m_signY > 0) 1141 { 1142 (void)Pie(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2)+1, YLOG2DEV(y2)+1, 1143 rx1, ry1, rx2, ry2); 1144 } 1145 else 1146 { 1147 (void)Pie(GetHdc(), XLOG2DEV(x), YLOG2DEV(y)-1, XLOG2DEV(x2)+1, YLOG2DEV(y2), 1148 rx1, ry1-1, rx2, ry2-1); 1149 } 1150 1151 ::SelectObject(GetHdc(), hpenOld); 1152 1153 (void)Arc(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2), 1154 rx1, ry1, rx2, ry2); 1155 1156 CalcBoundingBox(x, y); 1157 CalcBoundingBox(x2, y2); 1158#endif 1159} 1160 1161void wxDC::DoDrawIcon(const wxIcon& icon, wxCoord x, wxCoord y) 1162{ 1163 WXMICROWIN_CHECK_HDC 1164 1165 wxCHECK_RET( icon.Ok(), wxT("invalid icon in DrawIcon") ); 1166 1167#ifdef __WIN32__ 1168 ::DrawIconEx(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), GetHiconOf(icon), icon.GetWidth(), icon.GetHeight(), 0, NULL, DI_NORMAL); 1169#else 1170 ::DrawIcon(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), GetHiconOf(icon)); 1171#endif 1172 1173 CalcBoundingBox(x, y); 1174 CalcBoundingBox(x + icon.GetWidth(), y + icon.GetHeight()); 1175} 1176 1177void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask ) 1178{ 1179 WXMICROWIN_CHECK_HDC 1180 1181 wxCHECK_RET( bmp.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") ); 1182 1183 int width = bmp.GetWidth(), 1184 height = bmp.GetHeight(); 1185 1186 HBITMAP hbmpMask = 0; 1187 1188#if wxUSE_PALETTE 1189 HPALETTE oldPal = 0; 1190#endif // wxUSE_PALETTE 1191 1192 if ( bmp.HasAlpha() ) 1193 { 1194 MemoryHDC hdcMem; 1195 SelectInHDC select(hdcMem, GetHbitmapOf(bmp)); 1196 1197 if ( AlphaBlt(GetHdc(), x, y, width, height, 0, 0, hdcMem, bmp) ) 1198 return; 1199 } 1200 1201#ifndef __WXWINCE__ 1202 StretchBltModeChanger changeMode(GetHdc(), COLORONCOLOR); 1203#endif 1204 1205 if ( useMask ) 1206 { 1207 wxMask *mask = bmp.GetMask(); 1208 if ( mask ) 1209 hbmpMask = (HBITMAP)mask->GetMaskBitmap(); 1210 1211 if ( !hbmpMask ) 1212 { 1213 // don't give assert here because this would break existing 1214 // programs - just silently ignore useMask parameter 1215 useMask = false; 1216 } 1217 } 1218 if ( useMask ) 1219 { 1220#ifdef __WIN32__ 1221 // use MaskBlt() with ROP which doesn't do anything to dst in the mask 1222 // points 1223 // On some systems, MaskBlt succeeds yet is much much slower 1224 // than the wxWidgets fall-back implementation. So we need 1225 // to be able to switch this on and off at runtime. 1226 bool ok = false; 1227#if wxUSE_SYSTEM_OPTIONS 1228 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0) 1229#endif 1230 { 1231 HDC cdc = GetHdc(); 1232 HDC hdcMem = ::CreateCompatibleDC(GetHdc()); 1233 HGDIOBJ hOldBitmap = ::SelectObject(hdcMem, GetHbitmapOf(bmp)); 1234#if wxUSE_PALETTE 1235 wxPalette *pal = bmp.GetPalette(); 1236 if ( pal && ::GetDeviceCaps(cdc,BITSPIXEL) <= 8 ) 1237 { 1238 oldPal = ::SelectPalette(hdcMem, GetHpaletteOf(*pal), FALSE); 1239 ::RealizePalette(hdcMem); 1240 } 1241#endif // wxUSE_PALETTE 1242 1243 ok = ::MaskBlt(cdc, x, y, width, height, 1244 hdcMem, 0, 0, 1245 hbmpMask, 0, 0, 1246 MAKEROP4(SRCCOPY, DSTCOPY)) != 0; 1247 1248#if wxUSE_PALETTE 1249 if (oldPal) 1250 ::SelectPalette(hdcMem, oldPal, FALSE); 1251#endif // wxUSE_PALETTE 1252 1253 ::SelectObject(hdcMem, hOldBitmap); 1254 ::DeleteDC(hdcMem); 1255 } 1256 1257 if ( !ok ) 1258#endif // Win32 1259 { 1260 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API 1261 // level 1262 wxMemoryDC memDC; 1263 1264 memDC.SelectObjectAsSource(bmp); 1265 1266 Blit(x, y, width, height, &memDC, 0, 0, wxCOPY, useMask); 1267 1268 memDC.SelectObject(wxNullBitmap); 1269 } 1270 } 1271 else // no mask, just use BitBlt() 1272 { 1273 HDC cdc = GetHdc(); 1274 HDC memdc = ::CreateCompatibleDC( cdc ); 1275 HBITMAP hbitmap = (HBITMAP) bmp.GetHBITMAP( ); 1276 1277 wxASSERT_MSG( hbitmap, wxT("bitmap is ok but HBITMAP is NULL?") ); 1278 1279 COLORREF old_textground = ::GetTextColor(GetHdc()); 1280 COLORREF old_background = ::GetBkColor(GetHdc()); 1281 if (m_textForegroundColour.Ok()) 1282 { 1283 ::SetTextColor(GetHdc(), m_textForegroundColour.GetPixel() ); 1284 } 1285 if (m_textBackgroundColour.Ok()) 1286 { 1287 ::SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() ); 1288 } 1289 1290#if wxUSE_PALETTE 1291 wxPalette *pal = bmp.GetPalette(); 1292 if ( pal && ::GetDeviceCaps(cdc,BITSPIXEL) <= 8 ) 1293 { 1294 oldPal = ::SelectPalette(memdc, GetHpaletteOf(*pal), FALSE); 1295 ::RealizePalette(memdc); 1296 } 1297#endif // wxUSE_PALETTE 1298 1299 HGDIOBJ hOldBitmap = ::SelectObject( memdc, hbitmap ); 1300 ::BitBlt( cdc, x, y, width, height, memdc, 0, 0, SRCCOPY); 1301 1302#if wxUSE_PALETTE 1303 if (oldPal) 1304 ::SelectPalette(memdc, oldPal, FALSE); 1305#endif // wxUSE_PALETTE 1306 1307 ::SelectObject( memdc, hOldBitmap ); 1308 ::DeleteDC( memdc ); 1309 1310 ::SetTextColor(GetHdc(), old_textground); 1311 ::SetBkColor(GetHdc(), old_background); 1312 } 1313} 1314 1315void wxDC::DoDrawText(const wxString& text, wxCoord x, wxCoord y) 1316{ 1317 WXMICROWIN_CHECK_HDC 1318 1319 DrawAnyText(text, x, y); 1320 1321 // update the bounding box 1322 CalcBoundingBox(x, y); 1323 1324 wxCoord w, h; 1325 GetTextExtent(text, &w, &h); 1326 CalcBoundingBox(x + w, y + h); 1327} 1328 1329void wxDC::DrawAnyText(const wxString& text, wxCoord x, wxCoord y) 1330{ 1331 WXMICROWIN_CHECK_HDC 1332 1333 // prepare for drawing the text 1334 if ( m_textForegroundColour.Ok() ) 1335 SetTextColor(GetHdc(), m_textForegroundColour.GetPixel()); 1336 1337 DWORD old_background = 0; 1338 if ( m_textBackgroundColour.Ok() ) 1339 { 1340 old_background = SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() ); 1341 } 1342 1343 SetBkMode(GetHdc(), m_backgroundMode == wxTRANSPARENT ? TRANSPARENT 1344 : OPAQUE); 1345 1346#ifdef __WXWINCE__ 1347 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), 0, NULL, 1348 text.c_str(), text.length(), NULL) == 0 ) 1349 { 1350 wxLogLastError(wxT("TextOut")); 1351 } 1352#else 1353 if ( ::TextOut(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), 1354 text.c_str(), text.length()) == 0 ) 1355 { 1356 wxLogLastError(wxT("TextOut")); 1357 } 1358#endif 1359 1360 // restore the old parameters (text foreground colour may be left because 1361 // it never is set to anything else, but background should remain 1362 // transparent even if we just drew an opaque string) 1363 if ( m_textBackgroundColour.Ok() ) 1364 (void)SetBkColor(GetHdc(), old_background); 1365 1366 SetBkMode(GetHdc(), TRANSPARENT); 1367} 1368 1369void wxDC::DoDrawRotatedText(const wxString& text, 1370 wxCoord x, wxCoord y, 1371 double angle) 1372{ 1373 WXMICROWIN_CHECK_HDC 1374 1375 // we test that we have some font because otherwise we should still use the 1376 // "else" part below to avoid that DrawRotatedText(angle = 180) and 1377 // DrawRotatedText(angle = 0) use different fonts (we can't use the default 1378 // font for drawing rotated fonts unfortunately) 1379 if ( (angle == 0.0) && m_font.Ok() ) 1380 { 1381 DoDrawText(text, x, y); 1382 } 1383#ifndef __WXMICROWIN__ 1384 else 1385 { 1386 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT) 1387 // because it's not TrueType and so can't have non zero 1388 // orientation/escapement under Win9x 1389 wxFont font = m_font.Ok() ? m_font : *wxSWISS_FONT; 1390 HFONT hfont = (HFONT)font.GetResourceHandle(); 1391 LOGFONT lf; 1392 if ( ::GetObject(hfont, sizeof(lf), &lf) == 0 ) 1393 { 1394 wxLogLastError(wxT("GetObject(hfont)")); 1395 } 1396 1397 // GDI wants the angle in tenth of degree 1398 long angle10 = (long)(angle * 10); 1399 lf.lfEscapement = angle10; 1400 lf. lfOrientation = angle10; 1401 1402 hfont = ::CreateFontIndirect(&lf); 1403 if ( !hfont ) 1404 { 1405 wxLogLastError(wxT("CreateFont")); 1406 } 1407 else 1408 { 1409 HFONT hfontOld = (HFONT)::SelectObject(GetHdc(), hfont); 1410 1411 DrawAnyText(text, x, y); 1412 1413 (void)::SelectObject(GetHdc(), hfontOld); 1414 (void)::DeleteObject(hfont); 1415 } 1416 1417 // call the bounding box by adding all four vertices of the rectangle 1418 // containing the text to it (simpler and probably not slower than 1419 // determining which of them is really topmost/leftmost/...) 1420 wxCoord w, h; 1421 GetTextExtent(text, &w, &h); 1422 1423 double rad = DegToRad(angle); 1424 1425 // "upper left" and "upper right" 1426 CalcBoundingBox(x, y); 1427 CalcBoundingBox(x + wxCoord(w*cos(rad)), y - wxCoord(w*sin(rad))); 1428 1429 // "bottom left" and "bottom right" 1430 x += (wxCoord)(h*sin(rad)); 1431 y += (wxCoord)(h*cos(rad)); 1432 CalcBoundingBox(x, y); 1433 CalcBoundingBox(x + wxCoord(w*cos(rad)), y - wxCoord(w*sin(rad))); 1434 } 1435#endif 1436} 1437 1438// --------------------------------------------------------------------------- 1439// set GDI objects 1440// --------------------------------------------------------------------------- 1441 1442#if wxUSE_PALETTE 1443 1444void wxDC::DoSelectPalette(bool realize) 1445{ 1446 WXMICROWIN_CHECK_HDC 1447 1448 // Set the old object temporarily, in case the assignment deletes an object 1449 // that's not yet selected out. 1450 if (m_oldPalette) 1451 { 1452 ::SelectPalette(GetHdc(), (HPALETTE) m_oldPalette, FALSE); 1453 m_oldPalette = 0; 1454 } 1455 1456 if ( m_palette.Ok() ) 1457 { 1458 HPALETTE oldPal = ::SelectPalette(GetHdc(), 1459 GetHpaletteOf(m_palette), 1460 false); 1461 if (!m_oldPalette) 1462 m_oldPalette = (WXHPALETTE) oldPal; 1463 1464 if (realize) 1465 ::RealizePalette(GetHdc()); 1466 } 1467} 1468 1469void wxDC::SetPalette(const wxPalette& palette) 1470{ 1471 if ( palette.Ok() ) 1472 { 1473 m_palette = palette; 1474 DoSelectPalette(true); 1475 } 1476} 1477 1478void wxDC::InitializePalette() 1479{ 1480 if ( wxDisplayDepth() <= 8 ) 1481 { 1482 // look for any window or parent that has a custom palette. If any has 1483 // one then we need to use it in drawing operations 1484 wxWindow *win = m_canvas->GetAncestorWithCustomPalette(); 1485 1486 m_hasCustomPalette = win && win->HasCustomPalette(); 1487 if ( m_hasCustomPalette ) 1488 { 1489 m_palette = win->GetPalette(); 1490 1491 // turn on MSW translation for this palette 1492 DoSelectPalette(); 1493 } 1494 } 1495} 1496 1497#endif // wxUSE_PALETTE 1498 1499// SetFont/Pen/Brush() really ask to be implemented as a single template 1500// function... but doing it is not worth breaking OpenWatcom build <sigh> 1501 1502void wxDC::SetFont(const wxFont& font) 1503{ 1504 WXMICROWIN_CHECK_HDC 1505 1506 if ( font == m_font ) 1507 return; 1508 1509 if ( font.Ok() ) 1510 { 1511 HGDIOBJ hfont = ::SelectObject(GetHdc(), GetHfontOf(font)); 1512 if ( hfont == HGDI_ERROR ) 1513 { 1514 wxLogLastError(_T("SelectObject(font)")); 1515 } 1516 else // selected ok 1517 { 1518 if ( !m_oldFont ) 1519 m_oldFont = (WXHFONT)hfont; 1520 1521 m_font = font; 1522 } 1523 } 1524 else // invalid font, reset the current font 1525 { 1526 if ( m_oldFont ) 1527 { 1528 if ( ::SelectObject(GetHdc(), (HPEN) m_oldFont) == HGDI_ERROR ) 1529 { 1530 wxLogLastError(_T("SelectObject(old font)")); 1531 } 1532 1533 m_oldFont = 0; 1534 } 1535 1536 m_font = wxNullFont; 1537 } 1538} 1539 1540void wxDC::SetPen(const wxPen& pen) 1541{ 1542 WXMICROWIN_CHECK_HDC 1543 1544 if ( pen == m_pen ) 1545 return; 1546 1547 if ( pen.Ok() ) 1548 { 1549 HGDIOBJ hpen = ::SelectObject(GetHdc(), GetHpenOf(pen)); 1550 if ( hpen == HGDI_ERROR ) 1551 { 1552 wxLogLastError(_T("SelectObject(pen)")); 1553 } 1554 else // selected ok 1555 { 1556 if ( !m_oldPen ) 1557 m_oldPen = (WXHPEN)hpen; 1558 1559 m_pen = pen; 1560 } 1561 } 1562 else // invalid pen, reset the current pen 1563 { 1564 if ( m_oldPen ) 1565 { 1566 if ( ::SelectObject(GetHdc(), (HPEN) m_oldPen) == HGDI_ERROR ) 1567 { 1568 wxLogLastError(_T("SelectObject(old pen)")); 1569 } 1570 1571 m_oldPen = 0; 1572 } 1573 1574 m_pen = wxNullPen; 1575 } 1576} 1577 1578void wxDC::SetBrush(const wxBrush& brush) 1579{ 1580 WXMICROWIN_CHECK_HDC 1581 1582 if ( brush == m_brush ) 1583 return; 1584 1585 if ( brush.Ok() ) 1586 { 1587 // we must make sure the brush is aligned with the logical coordinates 1588 // before selecting it 1589 wxBitmap *stipple = brush.GetStipple(); 1590 if ( stipple && stipple->Ok() ) 1591 { 1592 if ( !::SetBrushOrgEx 1593 ( 1594 GetHdc(), 1595 m_deviceOriginX % stipple->GetWidth(), 1596 m_deviceOriginY % stipple->GetHeight(), 1597 NULL // [out] previous brush origin 1598 ) ) 1599 { 1600 wxLogLastError(_T("SetBrushOrgEx()")); 1601 } 1602 } 1603 1604 HGDIOBJ hbrush = ::SelectObject(GetHdc(), GetHbrushOf(brush)); 1605 if ( hbrush == HGDI_ERROR ) 1606 { 1607 wxLogLastError(_T("SelectObject(brush)")); 1608 } 1609 else // selected ok 1610 { 1611 if ( !m_oldBrush ) 1612 m_oldBrush = (WXHBRUSH)hbrush; 1613 1614 m_brush = brush; 1615 } 1616 } 1617 else // invalid brush, reset the current brush 1618 { 1619 if ( m_oldBrush ) 1620 { 1621 if ( ::SelectObject(GetHdc(), (HPEN) m_oldBrush) == HGDI_ERROR ) 1622 { 1623 wxLogLastError(_T("SelectObject(old brush)")); 1624 } 1625 1626 m_oldBrush = 0; 1627 } 1628 1629 m_brush = wxNullBrush; 1630 } 1631} 1632 1633void wxDC::SetBackground(const wxBrush& brush) 1634{ 1635 WXMICROWIN_CHECK_HDC 1636 1637 m_backgroundBrush = brush; 1638 1639 if ( m_backgroundBrush.Ok() ) 1640 { 1641 (void)SetBkColor(GetHdc(), m_backgroundBrush.GetColour().GetPixel()); 1642 } 1643} 1644 1645void wxDC::SetBackgroundMode(int mode) 1646{ 1647 WXMICROWIN_CHECK_HDC 1648 1649 m_backgroundMode = mode; 1650 1651 // SetBackgroundColour now only refers to text background 1652 // and m_backgroundMode is used there 1653} 1654 1655void wxDC::SetLogicalFunction(int function) 1656{ 1657 WXMICROWIN_CHECK_HDC 1658 1659 m_logicalFunction = function; 1660 1661 SetRop(m_hDC); 1662} 1663 1664void wxDC::SetRop(WXHDC dc) 1665{ 1666 if ( !dc || m_logicalFunction < 0 ) 1667 return; 1668 1669 int rop; 1670 1671 switch (m_logicalFunction) 1672 { 1673 case wxCLEAR: rop = R2_BLACK; break; 1674 case wxXOR: rop = R2_XORPEN; break; 1675 case wxINVERT: rop = R2_NOT; break; 1676 case wxOR_REVERSE: rop = R2_MERGEPENNOT; break; 1677 case wxAND_REVERSE: rop = R2_MASKPENNOT; break; 1678 case wxCOPY: rop = R2_COPYPEN; break; 1679 case wxAND: rop = R2_MASKPEN; break; 1680 case wxAND_INVERT: rop = R2_MASKNOTPEN; break; 1681 case wxNO_OP: rop = R2_NOP; break; 1682 case wxNOR: rop = R2_NOTMERGEPEN; break; 1683 case wxEQUIV: rop = R2_NOTXORPEN; break; 1684 case wxSRC_INVERT: rop = R2_NOTCOPYPEN; break; 1685 case wxOR_INVERT: rop = R2_MERGENOTPEN; break; 1686 case wxNAND: rop = R2_NOTMASKPEN; break; 1687 case wxOR: rop = R2_MERGEPEN; break; 1688 case wxSET: rop = R2_WHITE; break; 1689 1690 default: 1691 wxFAIL_MSG( wxT("unsupported logical function") ); 1692 return; 1693 } 1694 1695 SetROP2(GetHdc(), rop); 1696} 1697 1698bool wxDC::StartDoc(const wxString& WXUNUSED(message)) 1699{ 1700 // We might be previewing, so return true to let it continue. 1701 return true; 1702} 1703 1704void wxDC::EndDoc() 1705{ 1706} 1707 1708void wxDC::StartPage() 1709{ 1710} 1711 1712void wxDC::EndPage() 1713{ 1714} 1715 1716// --------------------------------------------------------------------------- 1717// text metrics 1718// --------------------------------------------------------------------------- 1719 1720wxCoord wxDC::GetCharHeight() const 1721{ 1722 WXMICROWIN_CHECK_HDC_RET(0) 1723 1724 TEXTMETRIC lpTextMetric; 1725 1726 GetTextMetrics(GetHdc(), &lpTextMetric); 1727 1728 return lpTextMetric.tmHeight; 1729} 1730 1731wxCoord wxDC::GetCharWidth() const 1732{ 1733 WXMICROWIN_CHECK_HDC_RET(0) 1734 1735 TEXTMETRIC lpTextMetric; 1736 1737 GetTextMetrics(GetHdc(), &lpTextMetric); 1738 1739 return lpTextMetric.tmAveCharWidth; 1740} 1741 1742void wxDC::DoGetTextExtent(const wxString& string, wxCoord *x, wxCoord *y, 1743 wxCoord *descent, wxCoord *externalLeading, 1744 wxFont *font) const 1745{ 1746#ifdef __WXMICROWIN__ 1747 if (!GetHDC()) 1748 { 1749 if (x) *x = 0; 1750 if (y) *y = 0; 1751 if (descent) *descent = 0; 1752 if (externalLeading) *externalLeading = 0; 1753 return; 1754 } 1755#endif // __WXMICROWIN__ 1756 1757 HFONT hfontOld; 1758 if ( font ) 1759 { 1760 wxASSERT_MSG( font->Ok(), _T("invalid font in wxDC::GetTextExtent") ); 1761 1762 hfontOld = (HFONT)::SelectObject(GetHdc(), GetHfontOf(*font)); 1763 } 1764 else // don't change the font 1765 { 1766 hfontOld = 0; 1767 } 1768 1769 SIZE sizeRect; 1770 const size_t len = string.length(); 1771 if ( !::GetTextExtentPoint32(GetHdc(), string, len, &sizeRect) ) 1772 { 1773 wxLogLastError(_T("GetTextExtentPoint32()")); 1774 } 1775 1776#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) 1777 // the result computed by GetTextExtentPoint32() may be too small as it 1778 // accounts for under/overhang of the first/last character while we want 1779 // just the bounding rect for this string so adjust the width as needed 1780 // (using API not available in 2002 SDKs of WinCE) 1781 if ( len > 0 ) 1782 { 1783 ABC width; 1784 const wxChar chFirst = *string.begin(); 1785 if ( ::GetCharABCWidths(GetHdc(), chFirst, chFirst, &width) ) 1786 { 1787 if ( width.abcA < 0 ) 1788 sizeRect.cx -= width.abcA; 1789 1790 if ( len > 1 ) 1791 { 1792 const wxChar chLast = *string.rbegin(); 1793 ::GetCharABCWidths(GetHdc(), chLast, chLast, &width); 1794 } 1795 //else: we already have the width of the last character 1796 1797 if ( width.abcC < 0 ) 1798 sizeRect.cx -= width.abcC; 1799 } 1800 //else: GetCharABCWidths() failed, not a TrueType font? 1801 } 1802#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) 1803 1804 TEXTMETRIC tm; 1805 ::GetTextMetrics(GetHdc(), &tm); 1806 1807 if (x) 1808 *x = sizeRect.cx; 1809 if (y) 1810 *y = sizeRect.cy; 1811 if (descent) 1812 *descent = tm.tmDescent; 1813 if (externalLeading) 1814 *externalLeading = tm.tmExternalLeading; 1815 1816 if ( hfontOld ) 1817 { 1818 ::SelectObject(GetHdc(), hfontOld); 1819 } 1820} 1821 1822 1823// Each element of the array will be the width of the string up to and 1824// including the coresoponding character in text. 1825 1826bool wxDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const 1827{ 1828 static int maxLenText = -1; 1829 static int maxWidth = -1; 1830 int fit = 0; 1831 SIZE sz = {0,0}; 1832 int stlen = text.length(); 1833 1834 if (maxLenText == -1) 1835 { 1836 // Win9x and WinNT+ have different limits 1837 int version = wxGetOsVersion(); 1838 maxLenText = version == wxOS_WINDOWS_NT ? 65535 : 8192; 1839 maxWidth = version == wxOS_WINDOWS_NT ? INT_MAX : 32767; 1840 } 1841 1842 widths.Empty(); 1843 widths.Add(0, stlen); // fill the array with zeros 1844 if (stlen == 0) 1845 return true; 1846 1847 if (!::GetTextExtentExPoint(GetHdc(), 1848 text.c_str(), // string to check 1849 wxMin(stlen, maxLenText), 1850 maxWidth, 1851 &fit, // [out] count of chars 1852 // that will fit 1853 &widths[0], // array to fill 1854 &sz)) 1855 { 1856 // API failed 1857 wxLogLastError(wxT("GetTextExtentExPoint")); 1858 return false; 1859 } 1860 1861 return true; 1862} 1863 1864 1865 1866 1867void wxDC::SetMapMode(int mode) 1868{ 1869 WXMICROWIN_CHECK_HDC 1870 1871 m_mappingMode = mode; 1872 1873 if ( mode == wxMM_TEXT ) 1874 { 1875 m_logicalScaleX = 1876 m_logicalScaleY = 1.0; 1877 } 1878 else // need to do some calculations 1879 { 1880 int pixel_width = ::GetDeviceCaps(GetHdc(), HORZRES), 1881 pixel_height = ::GetDeviceCaps(GetHdc(), VERTRES), 1882 mm_width = ::GetDeviceCaps(GetHdc(), HORZSIZE), 1883 mm_height = ::GetDeviceCaps(GetHdc(), VERTSIZE); 1884 1885 if ( (mm_width == 0) || (mm_height == 0) ) 1886 { 1887 // we can't calculate mm2pixels[XY] then! 1888 return; 1889 } 1890 1891 double mm2pixelsX = (double)pixel_width / mm_width, 1892 mm2pixelsY = (double)pixel_height / mm_height; 1893 1894 switch (mode) 1895 { 1896 case wxMM_TWIPS: 1897 m_logicalScaleX = twips2mm * mm2pixelsX; 1898 m_logicalScaleY = twips2mm * mm2pixelsY; 1899 break; 1900 1901 case wxMM_POINTS: 1902 m_logicalScaleX = pt2mm * mm2pixelsX; 1903 m_logicalScaleY = pt2mm * mm2pixelsY; 1904 break; 1905 1906 case wxMM_METRIC: 1907 m_logicalScaleX = mm2pixelsX; 1908 m_logicalScaleY = mm2pixelsY; 1909 break; 1910 1911 case wxMM_LOMETRIC: 1912 m_logicalScaleX = mm2pixelsX / 10.0; 1913 m_logicalScaleY = mm2pixelsY / 10.0; 1914 break; 1915 1916 default: 1917 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") ); 1918 } 1919 } 1920 1921 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of 1922 // cases we could do with MM_TEXT and in the remaining 0.9% with 1923 // MM_ISOTROPIC (TODO!) 1924#ifndef __WXWINCE__ 1925 ::SetMapMode(GetHdc(), MM_ANISOTROPIC); 1926 1927 int width = DeviceToLogicalXRel(VIEWPORT_EXTENT)*m_signX, 1928 height = DeviceToLogicalYRel(VIEWPORT_EXTENT)*m_signY; 1929 1930 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT, VIEWPORT_EXTENT, NULL); 1931 ::SetWindowExtEx(GetHdc(), width, height, NULL); 1932 1933 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX, m_deviceOriginY, NULL); 1934 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX, m_logicalOriginY, NULL); 1935#endif 1936} 1937 1938void wxDC::SetUserScale(double x, double y) 1939{ 1940 WXMICROWIN_CHECK_HDC 1941 1942 if ( x == m_userScaleX && y == m_userScaleY ) 1943 return; 1944 1945 m_userScaleX = x; 1946 m_userScaleY = y; 1947 1948 this->SetMapMode(m_mappingMode); 1949} 1950 1951void wxDC::SetAxisOrientation(bool WXUNUSED_IN_WINCE(xLeftRight), 1952 bool WXUNUSED_IN_WINCE(yBottomUp)) 1953{ 1954 WXMICROWIN_CHECK_HDC 1955 1956#ifndef __WXWINCE__ 1957 int signX = xLeftRight ? 1 : -1, 1958 signY = yBottomUp ? -1 : 1; 1959 1960 if ( signX != m_signX || signY != m_signY ) 1961 { 1962 m_signX = signX; 1963 m_signY = signY; 1964 1965 SetMapMode(m_mappingMode); 1966 } 1967#endif 1968} 1969 1970void wxDC::SetSystemScale(double x, double y) 1971{ 1972 WXMICROWIN_CHECK_HDC 1973 1974 if ( x == m_scaleX && y == m_scaleY ) 1975 return; 1976 1977 m_scaleX = x; 1978 m_scaleY = y; 1979 1980#ifndef __WXWINCE__ 1981 SetMapMode(m_mappingMode); 1982#endif 1983} 1984 1985void wxDC::SetLogicalOrigin(wxCoord x, wxCoord y) 1986{ 1987 WXMICROWIN_CHECK_HDC 1988 1989 if ( x == m_logicalOriginX && y == m_logicalOriginY ) 1990 return; 1991 1992 m_logicalOriginX = x; 1993 m_logicalOriginY = y; 1994 1995#ifndef __WXWINCE__ 1996 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX, (int)m_logicalOriginY, NULL); 1997#endif 1998} 1999 2000void wxDC::SetDeviceOrigin(wxCoord x, wxCoord y) 2001{ 2002 WXMICROWIN_CHECK_HDC 2003 2004 if ( x == m_deviceOriginX && y == m_deviceOriginY ) 2005 return; 2006 2007 m_deviceOriginX = x; 2008 m_deviceOriginY = y; 2009 2010 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL); 2011} 2012 2013// --------------------------------------------------------------------------- 2014// coordinates transformations 2015// --------------------------------------------------------------------------- 2016 2017wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const 2018{ 2019 return DeviceToLogicalXRel(x - m_deviceOriginX)*m_signX + m_logicalOriginX; 2020} 2021 2022wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const 2023{ 2024 // axis orientation is not taken into account for conversion of a distance 2025 return (wxCoord)(x / (m_logicalScaleX*m_userScaleX*m_scaleX)); 2026} 2027 2028wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const 2029{ 2030 return DeviceToLogicalYRel(y - m_deviceOriginY)*m_signY + m_logicalOriginY; 2031} 2032 2033wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const 2034{ 2035 // axis orientation is not taken into account for conversion of a distance 2036 return (wxCoord)( y / (m_logicalScaleY*m_userScaleY*m_scaleY)); 2037} 2038 2039wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const 2040{ 2041 return LogicalToDeviceXRel(x - m_logicalOriginX)*m_signX + m_deviceOriginX; 2042} 2043 2044wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const 2045{ 2046 // axis orientation is not taken into account for conversion of a distance 2047 return (wxCoord) (x*m_logicalScaleX*m_userScaleX*m_scaleX); 2048} 2049 2050wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const 2051{ 2052 return LogicalToDeviceYRel(y - m_logicalOriginY)*m_signY + m_deviceOriginY; 2053} 2054 2055wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const 2056{ 2057 // axis orientation is not taken into account for conversion of a distance 2058 return (wxCoord) (y*m_logicalScaleY*m_userScaleY*m_scaleY); 2059} 2060 2061// --------------------------------------------------------------------------- 2062// bit blit 2063// --------------------------------------------------------------------------- 2064 2065bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest, 2066 wxCoord width, wxCoord height, 2067 wxDC *source, wxCoord xsrc, wxCoord ysrc, 2068 int rop, bool useMask, 2069 wxCoord xsrcMask, wxCoord ysrcMask) 2070{ 2071 wxCHECK_MSG( source, false, _T("wxDC::Blit(): NULL wxDC pointer") ); 2072 2073 WXMICROWIN_CHECK_HDC_RET(false) 2074 2075 // if either the source or destination has alpha channel, we must use 2076 // AlphaBlt() as other function don't handle it correctly 2077 const wxBitmap& bmpSrc = source->m_selectedBitmap; 2078 if ( bmpSrc.Ok() && (bmpSrc.HasAlpha() || 2079 (m_selectedBitmap.Ok() && m_selectedBitmap.HasAlpha())) ) 2080 { 2081 if ( AlphaBlt(GetHdc(), xdest, ydest, width, height, 2082 xsrc, ysrc, GetHdcOf(*source), bmpSrc) ) 2083 return true; 2084 } 2085 2086 wxMask *mask = NULL; 2087 if ( useMask ) 2088 { 2089 mask = bmpSrc.GetMask(); 2090 2091 if ( !(bmpSrc.Ok() && mask && mask->GetMaskBitmap()) ) 2092 { 2093 // don't give assert here because this would break existing 2094 // programs - just silently ignore useMask parameter 2095 useMask = false; 2096 } 2097 } 2098 2099 if (xsrcMask == -1 && ysrcMask == -1) 2100 { 2101 xsrcMask = xsrc; ysrcMask = ysrc; 2102 } 2103 2104 COLORREF old_textground = ::GetTextColor(GetHdc()); 2105 COLORREF old_background = ::GetBkColor(GetHdc()); 2106 if (m_textForegroundColour.Ok()) 2107 { 2108 ::SetTextColor(GetHdc(), m_textForegroundColour.GetPixel() ); 2109 } 2110 if (m_textBackgroundColour.Ok()) 2111 { 2112 ::SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() ); 2113 } 2114 2115 DWORD dwRop; 2116 switch (rop) 2117 { 2118 case wxXOR: dwRop = SRCINVERT; break; 2119 case wxINVERT: dwRop = DSTINVERT; break; 2120 case wxOR_REVERSE: dwRop = 0x00DD0228; break; 2121 case wxAND_REVERSE: dwRop = SRCERASE; break; 2122 case wxCLEAR: dwRop = BLACKNESS; break; 2123 case wxSET: dwRop = WHITENESS; break; 2124 case wxOR_INVERT: dwRop = MERGEPAINT; break; 2125 case wxAND: dwRop = SRCAND; break; 2126 case wxOR: dwRop = SRCPAINT; break; 2127 case wxEQUIV: dwRop = 0x00990066; break; 2128 case wxNAND: dwRop = 0x007700E6; break; 2129 case wxAND_INVERT: dwRop = 0x00220326; break; 2130 case wxCOPY: dwRop = SRCCOPY; break; 2131 case wxNO_OP: dwRop = DSTCOPY; break; 2132 case wxSRC_INVERT: dwRop = NOTSRCCOPY; break; 2133 case wxNOR: dwRop = NOTSRCCOPY; break; 2134 default: 2135 wxFAIL_MSG( wxT("unsupported logical function") ); 2136 return false; 2137 } 2138 2139 bool success = false; 2140 2141 if (useMask) 2142 { 2143#ifdef __WIN32__ 2144 // we want the part of the image corresponding to the mask to be 2145 // transparent, so use "DSTCOPY" ROP for the mask points (the usual 2146 // meaning of fg and bg is inverted which corresponds to wxWin notion 2147 // of the mask which is also contrary to the Windows one) 2148 2149 // On some systems, MaskBlt succeeds yet is much much slower 2150 // than the wxWidgets fall-back implementation. So we need 2151 // to be able to switch this on and off at runtime. 2152#if wxUSE_SYSTEM_OPTIONS 2153 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0) 2154#endif 2155 { 2156 success = ::MaskBlt 2157 ( 2158 GetHdc(), 2159 xdest, ydest, width, height, 2160 GetHdcOf(*source), 2161 xsrc, ysrc, 2162 (HBITMAP)mask->GetMaskBitmap(), 2163 xsrcMask, ysrcMask, 2164 MAKEROP4(dwRop, DSTCOPY) 2165 ) != 0; 2166 } 2167 2168 if ( !success ) 2169#endif // Win32 2170 { 2171 // Blit bitmap with mask 2172 HDC dc_mask ; 2173 HDC dc_buffer ; 2174 HBITMAP buffer_bmap ; 2175 2176#if wxUSE_DC_CACHEING 2177 // create a temp buffer bitmap and DCs to access it and the mask 2178 wxDCCacheEntry* dcCacheEntry1 = FindDCInCache(NULL, source->GetHDC()); 2179 dc_mask = (HDC) dcCacheEntry1->m_dc; 2180 2181 wxDCCacheEntry* dcCacheEntry2 = FindDCInCache(dcCacheEntry1, GetHDC()); 2182 dc_buffer = (HDC) dcCacheEntry2->m_dc; 2183 2184 wxDCCacheEntry* bitmapCacheEntry = FindBitmapInCache(GetHDC(), 2185 width, height); 2186 2187 buffer_bmap = (HBITMAP) bitmapCacheEntry->m_bitmap; 2188#else // !wxUSE_DC_CACHEING 2189 // create a temp buffer bitmap and DCs to access it and the mask 2190 dc_mask = ::CreateCompatibleDC(GetHdcOf(*source)); 2191 dc_buffer = ::CreateCompatibleDC(GetHdc()); 2192 buffer_bmap = ::CreateCompatibleBitmap(GetHdc(), width, height); 2193#endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING 2194 HGDIOBJ hOldMaskBitmap = ::SelectObject(dc_mask, (HBITMAP) mask->GetMaskBitmap()); 2195 HGDIOBJ hOldBufferBitmap = ::SelectObject(dc_buffer, buffer_bmap); 2196 2197 // copy dest to buffer 2198 if ( !::BitBlt(dc_buffer, 0, 0, (int)width, (int)height, 2199 GetHdc(), xdest, ydest, SRCCOPY) ) 2200 { 2201 wxLogLastError(wxT("BitBlt")); 2202 } 2203 2204 // copy src to buffer using selected raster op 2205 if ( !::BitBlt(dc_buffer, 0, 0, (int)width, (int)height, 2206 GetHdcOf(*source), xsrc, ysrc, dwRop) ) 2207 { 2208 wxLogLastError(wxT("BitBlt")); 2209 } 2210 2211 // set masked area in buffer to BLACK (pixel value 0) 2212 COLORREF prevBkCol = ::SetBkColor(GetHdc(), RGB(255, 255, 255)); 2213 COLORREF prevCol = ::SetTextColor(GetHdc(), RGB(0, 0, 0)); 2214 if ( !::BitBlt(dc_buffer, 0, 0, (int)width, (int)height, 2215 dc_mask, xsrcMask, ysrcMask, SRCAND) ) 2216 { 2217 wxLogLastError(wxT("BitBlt")); 2218 } 2219 2220 // set unmasked area in dest to BLACK 2221 ::SetBkColor(GetHdc(), RGB(0, 0, 0)); 2222 ::SetTextColor(GetHdc(), RGB(255, 255, 255)); 2223 if ( !::BitBlt(GetHdc(), xdest, ydest, (int)width, (int)height, 2224 dc_mask, xsrcMask, ysrcMask, SRCAND) ) 2225 { 2226 wxLogLastError(wxT("BitBlt")); 2227 } 2228 ::SetBkColor(GetHdc(), prevBkCol); // restore colours to original values 2229 ::SetTextColor(GetHdc(), prevCol); 2230 2231 // OR buffer to dest 2232 success = ::BitBlt(GetHdc(), xdest, ydest, 2233 (int)width, (int)height, 2234 dc_buffer, 0, 0, SRCPAINT) != 0; 2235 if ( !success ) 2236 { 2237 wxLogLastError(wxT("BitBlt")); 2238 } 2239 2240 // tidy up temporary DCs and bitmap 2241 ::SelectObject(dc_mask, hOldMaskBitmap); 2242 ::SelectObject(dc_buffer, hOldBufferBitmap); 2243 2244#if !wxUSE_DC_CACHEING 2245 { 2246 ::DeleteDC(dc_mask); 2247 ::DeleteDC(dc_buffer); 2248 ::DeleteObject(buffer_bmap); 2249 } 2250#endif 2251 } 2252 } 2253 else // no mask, just BitBlt() it 2254 { 2255 // if we already have a DIB, draw it using StretchDIBits(), otherwise 2256 // use StretchBlt() if available and finally fall back to BitBlt() 2257 2258 // FIXME: use appropriate WinCE functions 2259#ifndef __WXWINCE__ 2260 const int caps = ::GetDeviceCaps(GetHdc(), RASTERCAPS); 2261 if ( bmpSrc.Ok() && (caps & RC_STRETCHDIB) ) 2262 { 2263 DIBSECTION ds; 2264 wxZeroMemory(ds); 2265 2266 if ( ::GetObject(GetHbitmapOf(bmpSrc), 2267 sizeof(ds), 2268 &ds) == sizeof(ds) ) 2269 { 2270 StretchBltModeChanger changeMode(GetHdc(), COLORONCOLOR); 2271 2272 // Figure out what co-ordinate system we're supposed to specify 2273 // ysrc in. 2274 const LONG hDIB = ds.dsBmih.biHeight; 2275 if ( hDIB > 0 ) 2276 { 2277 // reflect ysrc 2278 ysrc = hDIB - (ysrc + height); 2279 } 2280 2281 if ( ::StretchDIBits(GetHdc(), 2282 xdest, ydest, 2283 width, height, 2284 xsrc, ysrc, 2285 width, height, 2286 ds.dsBm.bmBits, 2287 (LPBITMAPINFO)&ds.dsBmih, 2288 DIB_RGB_COLORS, 2289 dwRop 2290 ) == (int)GDI_ERROR ) 2291 { 2292 // On Win9x this API fails most (all?) of the time, so 2293 // logging it becomes quite distracting. Since it falls 2294 // back to the code below this is not really serious, so 2295 // don't log it. 2296 //wxLogLastError(wxT("StretchDIBits")); 2297 } 2298 else 2299 { 2300 success = true; 2301 } 2302 } 2303 } 2304 2305 if ( !success && (caps & RC_STRETCHBLT) ) 2306#endif 2307 // __WXWINCE__ 2308 { 2309#ifndef __WXWINCE__ 2310 StretchBltModeChanger changeMode(GetHdc(), COLORONCOLOR); 2311#endif 2312 2313 if ( !::StretchBlt 2314 ( 2315 GetHdc(), 2316 xdest, ydest, width, height, 2317 GetHdcOf(*source), 2318 xsrc, ysrc, width, height, 2319 dwRop 2320 ) ) 2321 { 2322 wxLogLastError(_T("StretchBlt")); 2323 } 2324 else 2325 { 2326 success = true; 2327 } 2328 } 2329 2330 if ( !success ) 2331 { 2332 if ( !::BitBlt 2333 ( 2334 GetHdc(), 2335 xdest, ydest, 2336 (int)width, (int)height, 2337 GetHdcOf(*source), 2338 xsrc, ysrc, 2339 dwRop 2340 ) ) 2341 { 2342 wxLogLastError(_T("BitBlt")); 2343 } 2344 else 2345 { 2346 success = true; 2347 } 2348 } 2349 } 2350 2351 ::SetTextColor(GetHdc(), old_textground); 2352 ::SetBkColor(GetHdc(), old_background); 2353 2354 return success; 2355} 2356 2357void wxDC::GetDeviceSize(int *width, int *height) const 2358{ 2359 WXMICROWIN_CHECK_HDC 2360 2361 if ( width ) 2362 *width = ::GetDeviceCaps(GetHdc(), HORZRES); 2363 if ( height ) 2364 *height = ::GetDeviceCaps(GetHdc(), VERTRES); 2365} 2366 2367void wxDC::DoGetSizeMM(int *w, int *h) const 2368{ 2369 WXMICROWIN_CHECK_HDC 2370 2371 // if we implement it in terms of DoGetSize() instead of directly using the 2372 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it 2373 // will also work for wxWindowDC and wxClientDC even though their size is 2374 // not the same as the total size of the screen 2375 int wPixels, hPixels; 2376 DoGetSize(&wPixels, &hPixels); 2377 2378 if ( w ) 2379 { 2380 int wTotal = ::GetDeviceCaps(GetHdc(), HORZRES); 2381 2382 wxCHECK_RET( wTotal, _T("0 width device?") ); 2383 2384 *w = (wPixels * ::GetDeviceCaps(GetHdc(), HORZSIZE)) / wTotal; 2385 } 2386 2387 if ( h ) 2388 { 2389 int hTotal = ::GetDeviceCaps(GetHdc(), VERTRES); 2390 2391 wxCHECK_RET( hTotal, _T("0 height device?") ); 2392 2393 *h = (hPixels * ::GetDeviceCaps(GetHdc(), VERTSIZE)) / hTotal; 2394 } 2395} 2396 2397wxSize wxDC::GetPPI() const 2398{ 2399 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0)) 2400 2401 int x = ::GetDeviceCaps(GetHdc(), LOGPIXELSX); 2402 int y = ::GetDeviceCaps(GetHdc(), LOGPIXELSY); 2403 2404 return wxSize(x, y); 2405} 2406 2407// For use by wxWidgets only, unless custom units are required. 2408void wxDC::SetLogicalScale(double x, double y) 2409{ 2410 WXMICROWIN_CHECK_HDC 2411 2412 m_logicalScaleX = x; 2413 m_logicalScaleY = y; 2414} 2415 2416// ---------------------------------------------------------------------------- 2417// DC caching 2418// ---------------------------------------------------------------------------- 2419 2420#if wxUSE_DC_CACHEING 2421 2422/* 2423 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will 2424 * improve it in due course, either using arrays, or simply storing pointers to one 2425 * entry for the bitmap, and two for the DCs. -- JACS 2426 */ 2427 2428wxList wxDC::sm_bitmapCache; 2429wxList wxDC::sm_dcCache; 2430 2431wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap, int w, int h, int depth) 2432{ 2433 m_bitmap = hBitmap; 2434 m_dc = 0; 2435 m_width = w; 2436 m_height = h; 2437 m_depth = depth; 2438} 2439 2440wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC, int depth) 2441{ 2442 m_bitmap = 0; 2443 m_dc = hDC; 2444 m_width = 0; 2445 m_height = 0; 2446 m_depth = depth; 2447} 2448 2449wxDCCacheEntry::~wxDCCacheEntry() 2450{ 2451 if (m_bitmap) 2452 ::DeleteObject((HBITMAP) m_bitmap); 2453 if (m_dc) 2454 ::DeleteDC((HDC) m_dc); 2455} 2456 2457wxDCCacheEntry* wxDC::FindBitmapInCache(WXHDC dc, int w, int h) 2458{ 2459 int depth = ::GetDeviceCaps((HDC) dc, PLANES) * ::GetDeviceCaps((HDC) dc, BITSPIXEL); 2460 wxList::compatibility_iterator node = sm_bitmapCache.GetFirst(); 2461 while (node) 2462 { 2463 wxDCCacheEntry* entry = (wxDCCacheEntry*) node->GetData(); 2464 2465 if (entry->m_depth == depth) 2466 { 2467 if (entry->m_width < w || entry->m_height < h) 2468 { 2469 ::DeleteObject((HBITMAP) entry->m_bitmap); 2470 entry->m_bitmap = (WXHBITMAP) ::CreateCompatibleBitmap((HDC) dc, w, h); 2471 if ( !entry->m_bitmap) 2472 { 2473 wxLogLastError(wxT("CreateCompatibleBitmap")); 2474 } 2475 entry->m_width = w; entry->m_height = h; 2476 return entry; 2477 } 2478 return entry; 2479 } 2480 2481 node = node->GetNext(); 2482 } 2483 WXHBITMAP hBitmap = (WXHBITMAP) ::CreateCompatibleBitmap((HDC) dc, w, h); 2484 if ( !hBitmap) 2485 { 2486 wxLogLastError(wxT("CreateCompatibleBitmap")); 2487 } 2488 wxDCCacheEntry* entry = new wxDCCacheEntry(hBitmap, w, h, depth); 2489 AddToBitmapCache(entry); 2490 return entry; 2491} 2492 2493wxDCCacheEntry* wxDC::FindDCInCache(wxDCCacheEntry* notThis, WXHDC dc) 2494{ 2495 int depth = ::GetDeviceCaps((HDC) dc, PLANES) * ::GetDeviceCaps((HDC) dc, BITSPIXEL); 2496 wxList::compatibility_iterator node = sm_dcCache.GetFirst(); 2497 while (node) 2498 { 2499 wxDCCacheEntry* entry = (wxDCCacheEntry*) node->GetData(); 2500 2501 // Don't return the same one as we already have 2502 if (!notThis || (notThis != entry)) 2503 { 2504 if (entry->m_depth == depth) 2505 { 2506 return entry; 2507 } 2508 } 2509 2510 node = node->GetNext(); 2511 } 2512 WXHDC hDC = (WXHDC) ::CreateCompatibleDC((HDC) dc); 2513 if ( !hDC) 2514 { 2515 wxLogLastError(wxT("CreateCompatibleDC")); 2516 } 2517 wxDCCacheEntry* entry = new wxDCCacheEntry(hDC, depth); 2518 AddToDCCache(entry); 2519 return entry; 2520} 2521 2522void wxDC::AddToBitmapCache(wxDCCacheEntry* entry) 2523{ 2524 sm_bitmapCache.Append(entry); 2525} 2526 2527void wxDC::AddToDCCache(wxDCCacheEntry* entry) 2528{ 2529 sm_dcCache.Append(entry); 2530} 2531 2532void wxDC::ClearCache() 2533{ 2534 WX_CLEAR_LIST(wxList, sm_dcCache); 2535 WX_CLEAR_LIST(wxList, sm_bitmapCache); 2536} 2537 2538// Clean up cache at app exit 2539class wxDCModule : public wxModule 2540{ 2541public: 2542 virtual bool OnInit() { return true; } 2543 virtual void OnExit() { wxDC::ClearCache(); } 2544 2545private: 2546 DECLARE_DYNAMIC_CLASS(wxDCModule) 2547}; 2548 2549IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule) 2550 2551#endif // wxUSE_DC_CACHEING 2552 2553// ---------------------------------------------------------------------------- 2554// alpha channel support 2555// ---------------------------------------------------------------------------- 2556 2557static bool AlphaBlt(HDC hdcDst, 2558 int x, int y, int width, int height, 2559 int srcX, int srcY, HDC hdcSrc, 2560 const wxBitmap& bmp) 2561{ 2562 wxASSERT_MSG( bmp.Ok() && bmp.HasAlpha(), _T("AlphaBlt(): invalid bitmap") ); 2563 wxASSERT_MSG( hdcDst && hdcSrc, _T("AlphaBlt(): invalid HDC") ); 2564 2565 // do we have AlphaBlend() and company in the headers? 2566#if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS 2567 // yes, now try to see if we have it during run-time 2568 typedef BOOL (WINAPI *AlphaBlend_t)(HDC,int,int,int,int, 2569 HDC,int,int,int,int, 2570 BLENDFUNCTION); 2571 2572 static AlphaBlend_t 2573 pfnAlphaBlend = (AlphaBlend_t)wxMSIMG32DLL.GetSymbol(_T("AlphaBlend")); 2574 if ( pfnAlphaBlend ) 2575 { 2576 BLENDFUNCTION bf; 2577 bf.BlendOp = AC_SRC_OVER; 2578 bf.BlendFlags = 0; 2579 bf.SourceConstantAlpha = 0xff; 2580 bf.AlphaFormat = AC_SRC_ALPHA; 2581 2582 if ( pfnAlphaBlend(hdcDst, x, y, width, height, 2583 hdcSrc, srcX, srcY, width, height, 2584 bf) ) 2585 { 2586 // skip wxAlphaBlend() call below 2587 return true; 2588 } 2589 2590 wxLogLastError(_T("AlphaBlend")); 2591 } 2592#else 2593 wxUnusedVar(hdcSrc); 2594#endif // defined(AC_SRC_OVER) 2595 2596 // AlphaBlend() unavailable of failed: use our own (probably much slower) 2597 // implementation 2598#ifdef wxHAVE_RAW_BITMAP 2599 wxAlphaBlend(hdcDst, x, y, width, height, srcX, srcY, bmp); 2600 2601 return true; 2602#else // !wxHAVE_RAW_BITMAP 2603 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose 2604 // alpha but at least something will be shown like this) 2605 wxUnusedVar(bmp); 2606 return false; 2607#endif // wxHAVE_RAW_BITMAP 2608} 2609 2610 2611// wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable 2612#ifdef wxHAVE_RAW_BITMAP 2613 2614static void 2615wxAlphaBlend(HDC hdcDst, int xDst, int yDst, 2616 int w, int h, 2617 int srcX, int srcY, const wxBitmap& bmpSrc) 2618{ 2619 // get the destination DC pixels 2620 wxBitmap bmpDst(w, h, 32 /* force creating RGBA DIB */); 2621 MemoryHDC hdcMem; 2622 SelectInHDC select(hdcMem, GetHbitmapOf(bmpDst)); 2623 2624 if ( !::BitBlt(hdcMem, 0, 0, w, h, hdcDst, xDst, yDst, SRCCOPY) ) 2625 { 2626 wxLogLastError(_T("BitBlt")); 2627 } 2628 2629 // combine them with the source bitmap using alpha 2630 wxAlphaPixelData dataDst(bmpDst), 2631 dataSrc((wxBitmap &)bmpSrc); 2632 2633 wxCHECK_RET( dataDst && dataSrc, 2634 _T("failed to get raw data in wxAlphaBlend") ); 2635 2636 wxAlphaPixelData::Iterator pDst(dataDst), 2637 pSrc(dataSrc); 2638 2639 pSrc.Offset(dataSrc, srcX, srcY); 2640 2641 for ( int y = 0; y < h; y++ ) 2642 { 2643 wxAlphaPixelData::Iterator pDstRowStart = pDst, 2644 pSrcRowStart = pSrc; 2645 2646 for ( int x = 0; x < w; x++ ) 2647 { 2648 // note that source bitmap uses premultiplied alpha (as required by 2649 // the real AlphaBlend) 2650 const unsigned beta = 255 - pSrc.Alpha(); 2651 2652 pDst.Red() = pSrc.Red() + (beta * pDst.Red() + 127) / 255; 2653 pDst.Blue() = pSrc.Blue() + (beta * pDst.Blue() + 127) / 255; 2654 pDst.Green() = pSrc.Green() + (beta * pDst.Green() + 127) / 255; 2655 2656 ++pDst; 2657 ++pSrc; 2658 } 2659 2660 pDst = pDstRowStart; 2661 pSrc = pSrcRowStart; 2662 pDst.OffsetY(dataDst, 1); 2663 pSrc.OffsetY(dataSrc, 1); 2664 } 2665 2666 // and finally blit them back to the destination DC 2667 if ( !::BitBlt(hdcDst, xDst, yDst, w, h, hdcMem, 0, 0, SRCCOPY) ) 2668 { 2669 wxLogLastError(_T("BitBlt")); 2670 } 2671} 2672 2673#endif // #ifdef wxHAVE_RAW_BITMAP 2674 2675void wxDC::DoGradientFillLinear (const wxRect& rect, 2676 const wxColour& initialColour, 2677 const wxColour& destColour, 2678 wxDirection nDirection) 2679{ 2680 // use native function if we have compile-time support it and can load it 2681 // during run-time (linking to it statically would make the program 2682 // unusable on earlier Windows versions) 2683#if defined(GRADIENT_FILL_RECT_H) && wxUSE_DYNLIB_CLASS 2684 typedef BOOL 2685 (WINAPI *GradientFill_t)(HDC, PTRIVERTEX, ULONG, PVOID, ULONG, ULONG); 2686 static GradientFill_t pfnGradientFill = 2687 (GradientFill_t)wxMSIMG32DLL.GetSymbol(_T("GradientFill")); 2688 2689 if ( pfnGradientFill ) 2690 { 2691 GRADIENT_RECT grect; 2692 grect.UpperLeft = 0; 2693 grect.LowerRight = 1; 2694 2695 // invert colours direction if not filling from left-to-right or 2696 // top-to-bottom 2697 int firstVertex = nDirection == wxNORTH || nDirection == wxWEST ? 1 : 0; 2698 2699 // one vertex for upper left and one for upper-right 2700 TRIVERTEX vertices[2]; 2701 2702 vertices[0].x = rect.GetLeft(); 2703 vertices[0].y = rect.GetTop(); 2704 vertices[1].x = rect.GetRight()+1; 2705 vertices[1].y = rect.GetBottom()+1; 2706 2707 vertices[firstVertex].Red = (COLOR16)(initialColour.Red() << 8); 2708 vertices[firstVertex].Green = (COLOR16)(initialColour.Green() << 8); 2709 vertices[firstVertex].Blue = (COLOR16)(initialColour.Blue() << 8); 2710 vertices[firstVertex].Alpha = 0; 2711 vertices[1 - firstVertex].Red = (COLOR16)(destColour.Red() << 8); 2712 vertices[1 - firstVertex].Green = (COLOR16)(destColour.Green() << 8); 2713 vertices[1 - firstVertex].Blue = (COLOR16)(destColour.Blue() << 8); 2714 vertices[1 - firstVertex].Alpha = 0; 2715 2716 if ( (*pfnGradientFill) 2717 ( 2718 GetHdc(), 2719 vertices, 2720 WXSIZEOF(vertices), 2721 &grect, 2722 1, 2723 nDirection == wxWEST || nDirection == wxEAST 2724 ? GRADIENT_FILL_RECT_H 2725 : GRADIENT_FILL_RECT_V 2726 ) ) 2727 { 2728 // skip call of the base class version below 2729 return; 2730 } 2731 2732 wxLogLastError(_T("GradientFill")); 2733 } 2734#endif // wxUSE_DYNLIB_CLASS 2735 2736 wxDCBase::DoGradientFillLinear(rect, initialColour, destColour, nDirection); 2737} 2738 2739static DWORD wxGetDCLayout(HDC hdc) 2740{ 2741 typedef DWORD (WINAPI *GetLayout_t)(HDC); 2742 static GetLayout_t 2743 pfnGetLayout = (GetLayout_t)wxGDI32DLL.GetSymbol(_T("GetLayout")); 2744 2745 return pfnGetLayout ? pfnGetLayout(hdc) : (DWORD)-1; 2746} 2747 2748wxLayoutDirection wxDC::GetLayoutDirection() const 2749{ 2750 DWORD layout = wxGetDCLayout(GetHdc()); 2751 2752 if ( layout == (DWORD)-1 ) 2753 return wxLayout_Default; 2754 2755 return layout & LAYOUT_RTL ? wxLayout_RightToLeft : wxLayout_LeftToRight; 2756} 2757 2758void wxDC::SetLayoutDirection(wxLayoutDirection dir) 2759{ 2760 typedef DWORD (WINAPI *SetLayout_t)(HDC, DWORD); 2761 static SetLayout_t 2762 pfnSetLayout = (SetLayout_t)wxGDI32DLL.GetSymbol(_T("SetLayout")); 2763 if ( !pfnSetLayout ) 2764 return; 2765 2766 if ( dir == wxLayout_Default ) 2767 { 2768 dir = wxTheApp->GetLayoutDirection(); 2769 if ( dir == wxLayout_Default ) 2770 return; 2771 } 2772 2773 DWORD layout = wxGetDCLayout(GetHdc()); 2774 if ( dir == wxLayout_RightToLeft ) 2775 layout |= LAYOUT_RTL; 2776 else 2777 layout &= ~LAYOUT_RTL; 2778 2779 pfnSetLayout(GetHdc(), layout); 2780} 2781