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