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