]> git.saurik.com Git - wxWidgets.git/blame - src/msw/dc.cpp
render scrollbar's thumb as stippled bar to distinguish it from controls
[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,
133 int x, int y, int w, int h,
3db79902 134 int srcX, int srcY, HDC hdcSrc,
275a63e3 135 const wxBitmap& bmpSrc);
1e3c12d7
CE
136
137#ifdef wxHAVE_RAW_BITMAP
761598d4
VZ
138
139// our (limited) AlphaBlend() replacement for Windows versions not providing it
878711c0 140static void
761598d4
VZ
141wxAlphaBlend(HDC hdcDst, int x, int y, int w, int h,
142 int srcX, int srcY, const wxBitmap& bmp);
143
144#endif // wxHAVE_RAW_BITMAP
878711c0 145
f6bcfd97
BP
146// ----------------------------------------------------------------------------
147// private classes
148// ----------------------------------------------------------------------------
149
150// instead of duplicating the same code which sets and then restores text
151// colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
152// encapsulate this in a small helper class
153
154// wxColourChanger: changes the text colours in the ctor if required and
155// restores them in the dtor
156class wxColourChanger
157{
158public:
159 wxColourChanger(wxDC& dc);
160 ~wxColourChanger();
161
162private:
163 wxDC& m_dc;
164
165 COLORREF m_colFgOld, m_colBgOld;
166
167 bool m_changed;
2eb10e2a
VZ
168
169 DECLARE_NO_COPY_CLASS(wxColourChanger)
f6bcfd97
BP
170};
171
f178ab7e
VZ
172// this class saves the old stretch blit mode during its life time
173class StretchBltModeChanger
174{
175public:
0c0d1521
WS
176 StretchBltModeChanger(HDC hdc,
177 int WXUNUSED_IN_WINCE(mode))
f178ab7e
VZ
178 : m_hdc(hdc)
179 {
4676948b 180#ifndef __WXWINCE__
f178ab7e
VZ
181 m_modeOld = ::SetStretchBltMode(m_hdc, mode);
182 if ( !m_modeOld )
183 wxLogLastError(_T("SetStretchBltMode"));
4676948b 184#endif
f178ab7e
VZ
185 }
186
187 ~StretchBltModeChanger()
188 {
4676948b 189#ifndef __WXWINCE__
f178ab7e
VZ
190 if ( !::SetStretchBltMode(m_hdc, m_modeOld) )
191 wxLogLastError(_T("SetStretchBltMode"));
4676948b 192#endif
f178ab7e
VZ
193 }
194
195private:
196 const HDC m_hdc;
197
198 int m_modeOld;
2eb10e2a
VZ
199
200 DECLARE_NO_COPY_CLASS(StretchBltModeChanger)
f178ab7e
VZ
201};
202
6ae7410f
VZ
203// helper class to cache dynamically loaded libraries and not attempt reloading
204// them if it fails
205class wxOnceOnlyDLLLoader
213ad8e7
VZ
206{
207public:
6ae7410f
VZ
208 // ctor argument must be a literal string as we don't make a copy of it!
209 wxOnceOnlyDLLLoader(const wxChar *dllName)
210 : m_dllName(dllName)
213ad8e7 211 {
6ae7410f
VZ
212 };
213
214
215 // return the symbol with the given name or NULL if the DLL not loaded
216 // or symbol not present
217 void *GetSymbol(const wxChar *name)
218 {
219 // we're prepared to handle errors here
213ad8e7
VZ
220 wxLogNull noLog;
221
6ae7410f 222 if ( m_dllName )
213ad8e7 223 {
6ae7410f
VZ
224 m_dll.Load(m_dllName);
225
226 // reset the name whether we succeeded or failed so that we don't
227 // try again the next time
228 m_dllName = NULL;
213ad8e7
VZ
229 }
230
6ae7410f 231 return m_dll.IsLoaded() ? m_dll.GetSymbol(name) : NULL;
213ad8e7
VZ
232 }
233
234private:
6ae7410f
VZ
235 wxDynamicLibrary m_dll;
236 const wxChar *m_dllName;
213ad8e7
VZ
237};
238
6ae7410f
VZ
239static wxOnceOnlyDLLLoader wxGDI32DLL(_T("gdi32"));
240static wxOnceOnlyDLLLoader wxMSIMG32DLL(_T("msimg32"));
213ad8e7 241
a23fd0e1
VZ
242// ===========================================================================
243// implementation
244// ===========================================================================
245
f6bcfd97
BP
246// ----------------------------------------------------------------------------
247// wxColourChanger
248// ----------------------------------------------------------------------------
249
250wxColourChanger::wxColourChanger(wxDC& dc) : m_dc(dc)
251{
cafbad8f
VZ
252 const wxBrush& brush = dc.GetBrush();
253 if ( brush.Ok() && brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE )
f6bcfd97
BP
254 {
255 HDC hdc = GetHdcOf(dc);
256 m_colFgOld = ::GetTextColor(hdc);
257 m_colBgOld = ::GetBkColor(hdc);
258
77ffb593 259 // note that Windows convention is opposite to wxWidgets one, this is
f6bcfd97
BP
260 // why text colour becomes the background one and vice versa
261 const wxColour& colFg = dc.GetTextForeground();
262 if ( colFg.Ok() )
263 {
264 ::SetBkColor(hdc, colFg.GetPixel());
265 }
266
267 const wxColour& colBg = dc.GetTextBackground();
268 if ( colBg.Ok() )
269 {
270 ::SetTextColor(hdc, colBg.GetPixel());
271 }
272
273 SetBkMode(hdc,
274 dc.GetBackgroundMode() == wxTRANSPARENT ? TRANSPARENT
275 : OPAQUE);
276
277 // flag which telsl us to undo changes in the dtor
beb966c5 278 m_changed = true;
f6bcfd97
BP
279 }
280 else
281 {
282 // nothing done, nothing to undo
beb966c5 283 m_changed = false;
f6bcfd97
BP
284 }
285}
286
287wxColourChanger::~wxColourChanger()
288{
289 if ( m_changed )
290 {
291 // restore the colours we changed
292 HDC hdc = GetHdcOf(m_dc);
293
294 ::SetBkMode(hdc, TRANSPARENT);
295 ::SetTextColor(hdc, m_colFgOld);
296 ::SetBkColor(hdc, m_colBgOld);
297 }
298}
299
a23fd0e1
VZ
300// ---------------------------------------------------------------------------
301// wxDC
302// ---------------------------------------------------------------------------
2bda0e17 303
a23fd0e1 304wxDC::~wxDC()
2bda0e17 305{
7ba4fbeb
VZ
306 if ( m_hDC != 0 )
307 {
7bcb11d3 308 SelectOldObjects(m_hDC);
7ba4fbeb
VZ
309
310 // if we own the HDC, we delete it, otherwise we just release it
311
312 if ( m_bOwnsDC )
313 {
314 ::DeleteDC(GetHdc());
7bcb11d3 315 }
7ba4fbeb
VZ
316 else // we don't own our HDC
317 {
db400410
JS
318 if (m_canvas)
319 {
320 ::ReleaseDC(GetHwndOf(m_canvas), GetHdc());
321 }
322 else
323 {
324 // Must have been a wxScreenDC
325 ::ReleaseDC((HWND) NULL, GetHdc());
326 }
7ba4fbeb
VZ
327 }
328 }
2bda0e17
KB
329}
330
331// This will select current objects out of the DC,
332// which is what you have to do before deleting the
333// DC.
334void wxDC::SelectOldObjects(WXHDC dc)
335{
7bcb11d3 336 if (dc)
2bda0e17 337 {
7bcb11d3
JS
338 if (m_oldBitmap)
339 {
340 ::SelectObject((HDC) dc, (HBITMAP) m_oldBitmap);
3ca22d5e 341#ifdef __WXDEBUG__
7bcb11d3
JS
342 if (m_selectedBitmap.Ok())
343 {
344 m_selectedBitmap.SetSelectedInto(NULL);
345 }
3ca22d5e 346#endif
7bcb11d3 347 }
a23fd0e1 348 m_oldBitmap = 0;
7bcb11d3
JS
349 if (m_oldPen)
350 {
351 ::SelectObject((HDC) dc, (HPEN) m_oldPen);
352 }
a23fd0e1 353 m_oldPen = 0;
7bcb11d3
JS
354 if (m_oldBrush)
355 {
356 ::SelectObject((HDC) dc, (HBRUSH) m_oldBrush);
357 }
a23fd0e1 358 m_oldBrush = 0;
7bcb11d3
JS
359 if (m_oldFont)
360 {
361 ::SelectObject((HDC) dc, (HFONT) m_oldFont);
362 }
a23fd0e1 363 m_oldFont = 0;
d275c7eb
VZ
364
365#if wxUSE_PALETTE
7bcb11d3
JS
366 if (m_oldPalette)
367 {
19193a2c 368 ::SelectPalette((HDC) dc, (HPALETTE) m_oldPalette, FALSE);
7bcb11d3 369 }
a23fd0e1 370 m_oldPalette = 0;
d275c7eb 371#endif // wxUSE_PALETTE
2bda0e17 372 }
a23fd0e1
VZ
373
374 m_brush = wxNullBrush;
7bcb11d3 375 m_pen = wxNullPen;
d275c7eb 376#if wxUSE_PALETTE
7bcb11d3 377 m_palette = wxNullPalette;
d275c7eb 378#endif // wxUSE_PALETTE
7bcb11d3
JS
379 m_font = wxNullFont;
380 m_backgroundBrush = wxNullBrush;
381 m_selectedBitmap = wxNullBitmap;
2bda0e17
KB
382}
383
a23fd0e1
VZ
384// ---------------------------------------------------------------------------
385// clipping
386// ---------------------------------------------------------------------------
387
1e6feb95
VZ
388void wxDC::UpdateClipBox()
389{
82a306b7 390 WXMICROWIN_CHECK_HDC
d275c7eb 391
1e6feb95 392 RECT rect;
5230934a 393 ::GetClipBox(GetHdc(), &rect);
1e6feb95
VZ
394
395 m_clipX1 = (wxCoord) XDEV2LOG(rect.left);
396 m_clipY1 = (wxCoord) YDEV2LOG(rect.top);
397 m_clipX2 = (wxCoord) XDEV2LOG(rect.right);
398 m_clipY2 = (wxCoord) YDEV2LOG(rect.bottom);
f547e9bb
RL
399}
400
2e76da54
VZ
401void
402wxDC::DoGetClippingBox(wxCoord *x, wxCoord *y, wxCoord *w, wxCoord *h) const
403{
404 // check if we should try to retrieve the clipping region possibly not set
405 // by our SetClippingRegion() but preset by Windows:this can only happen
406 // when we're associated with an existing HDC usign SetHDC(), see there
407 if ( m_clipping && !m_clipX1 && !m_clipX2 )
408 {
395b914e
VZ
409 wxDC *self = wxConstCast(this, wxDC);
410 self->UpdateClipBox();
2e76da54
VZ
411
412 if ( !m_clipX1 && !m_clipX2 )
395b914e 413 self->m_clipping = false;
2e76da54
VZ
414 }
415
f67fe9a4 416 wxDCBase::DoGetClippingBox(x, y, w, h);
2e76da54
VZ
417}
418
5230934a
VZ
419// common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
420void wxDC::SetClippingHrgn(WXHRGN hrgn)
2bda0e17 421{
5230934a
VZ
422 wxCHECK_RET( hrgn, wxT("invalid clipping region") );
423
82a306b7 424 WXMICROWIN_CHECK_HDC
5230934a
VZ
425
426 // note that we combine the new clipping region with the existing one: this
427 // is compatible with what the other ports do and is the documented
428 // behaviour now (starting with 2.3.3)
3a5bcc4d 429#if defined(__WXWINCE__)
5230934a
VZ
430 RECT rectClip;
431 if ( !::GetClipBox(GetHdc(), &rectClip) )
432 return;
433
1d63de4a
JS
434 // GetClipBox returns logical coordinates, so transform to device
435 rectClip.left = LogicalToDeviceX(rectClip.left);
436 rectClip.top = LogicalToDeviceY(rectClip.top);
437 rectClip.right = LogicalToDeviceX(rectClip.right);
438 rectClip.bottom = LogicalToDeviceY(rectClip.bottom);
439
5230934a
VZ
440 HRGN hrgnDest = ::CreateRectRgn(0, 0, 0, 0);
441 HRGN hrgnClipOld = ::CreateRectRgn(rectClip.left, rectClip.top,
442 rectClip.right, rectClip.bottom);
443
444 if ( ::CombineRgn(hrgnDest, hrgnClipOld, (HRGN)hrgn, RGN_AND) != ERROR )
445 {
446 ::SelectClipRgn(GetHdc(), hrgnDest);
447 }
448
449 ::DeleteObject(hrgnClipOld);
450 ::DeleteObject(hrgnDest);
3a5bcc4d 451#else // !WinCE
5230934a
VZ
452 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN)hrgn, RGN_AND) == ERROR )
453 {
454 wxLogLastError(_T("ExtSelectClipRgn"));
455
456 return;
457 }
3a5bcc4d 458#endif // WinCE/!WinCE
d275c7eb 459
beb966c5 460 m_clipping = true;
40a89076 461
5230934a
VZ
462 UpdateClipBox();
463}
464
465void wxDC::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
466{
c4218a74
VZ
467 // the region coords are always the device ones, so do the translation
468 // manually
1e6feb95
VZ
469 //
470 // FIXME: possible +/-1 error here, to check!
c4218a74
VZ
471 HRGN hrgn = ::CreateRectRgn(LogicalToDeviceX(x),
472 LogicalToDeviceY(y),
473 LogicalToDeviceX(x + w),
474 LogicalToDeviceY(y + h));
40a89076
VZ
475 if ( !hrgn )
476 {
477 wxLogLastError(_T("CreateRectRgn"));
478 }
479 else
480 {
5230934a 481 SetClippingHrgn((WXHRGN)hrgn);
40a89076 482
5230934a 483 ::DeleteObject(hrgn);
40a89076 484 }
2bda0e17
KB
485}
486
a23fd0e1 487void wxDC::DoSetClippingRegionAsRegion(const wxRegion& region)
a724d789 488{
5230934a 489 SetClippingHrgn(region.GetHRGN());
2bda0e17
KB
490}
491
a23fd0e1 492void wxDC::DestroyClippingRegion()
2bda0e17 493{
82a306b7 494 WXMICROWIN_CHECK_HDC
d275c7eb 495
7bcb11d3
JS
496 if (m_clipping && m_hDC)
497 {
07225d48
JS
498#if 1
499 // On a PocketPC device (not necessarily emulator), resetting
500 // the clip region as per the old method causes bad display
501 // problems. In fact setting a null region is probably OK
502 // on desktop WIN32 also, since the WIN32 docs imply that the user
503 // clipping region is independent from the paint clipping region.
504 ::SelectClipRgn(GetHdc(), 0);
3cdcf4d4 505#else
7bcb11d3 506 // TODO: this should restore the previous clipping region,
5230934a
VZ
507 // so that OnPaint processing works correctly, and the update
508 // clipping region doesn't get destroyed after the first
509 // DestroyClippingRegion.
7bcb11d3 510 HRGN rgn = CreateRectRgn(0, 0, 32000, 32000);
5230934a
VZ
511 ::SelectClipRgn(GetHdc(), rgn);
512 ::DeleteObject(rgn);
3cdcf4d4 513#endif
7bcb11d3 514 }
1e6feb95 515
2e76da54 516 wxDCBase::DestroyClippingRegion();
2bda0e17
KB
517}
518
a23fd0e1
VZ
519// ---------------------------------------------------------------------------
520// query capabilities
521// ---------------------------------------------------------------------------
522
523bool wxDC::CanDrawBitmap() const
2bda0e17 524{
beb966c5 525 return true;
2bda0e17
KB
526}
527
a23fd0e1 528bool wxDC::CanGetTextExtent() const
2bda0e17 529{
04ef50df
JS
530#ifdef __WXMICROWIN__
531 // TODO Extend MicroWindows' GetDeviceCaps function
beb966c5 532 return true;
04ef50df 533#else
7bcb11d3 534 // What sort of display is it?
a23fd0e1
VZ
535 int technology = ::GetDeviceCaps(GetHdc(), TECHNOLOGY);
536
537 return (technology == DT_RASDISPLAY) || (technology == DT_RASPRINTER);
04ef50df 538#endif
2bda0e17
KB
539}
540
a23fd0e1 541int wxDC::GetDepth() const
2bda0e17 542{
82a306b7 543 WXMICROWIN_CHECK_HDC_RET(16)
d275c7eb 544
a23fd0e1 545 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL);
2bda0e17
KB
546}
547
a23fd0e1
VZ
548// ---------------------------------------------------------------------------
549// drawing
550// ---------------------------------------------------------------------------
551
552void wxDC::Clear()
2bda0e17 553{
82a306b7 554 WXMICROWIN_CHECK_HDC
d275c7eb 555
7bcb11d3 556 RECT rect;
2506aab6
VZ
557 if ( m_canvas )
558 {
7bcb11d3 559 GetClientRect((HWND) m_canvas->GetHWND(), &rect);
2506aab6
VZ
560 }
561 else
7bcb11d3 562 {
eaeb6a3c
JS
563 // No, I think we should simply ignore this if printing on e.g.
564 // a printer DC.
565 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
566 if (!m_selectedBitmap.Ok())
567 return;
2506aab6 568
dbe6f5f0
RD
569 rect.left = -m_deviceOriginX; rect.top = -m_deviceOriginY;
570 rect.right = m_selectedBitmap.GetWidth()-m_deviceOriginX;
571 rect.bottom = m_selectedBitmap.GetHeight()-m_deviceOriginY;
7bcb11d3 572 }
2506aab6 573
4676948b 574#ifndef __WXWINCE__
a23fd0e1 575 (void) ::SetMapMode(GetHdc(), MM_TEXT);
4676948b 576#endif
a23fd0e1 577
1e2081a1
VZ
578 DWORD colour = ::GetBkColor(GetHdc());
579 HBRUSH brush = ::CreateSolidBrush(colour);
580 ::FillRect(GetHdc(), &rect, brush);
581 ::DeleteObject(brush);
582
35bbb0c6 583#ifndef __WXWINCE__
1e2081a1
VZ
584 int width = DeviceToLogicalXRel(VIEWPORT_EXTENT)*m_signX,
585 height = DeviceToLogicalYRel(VIEWPORT_EXTENT)*m_signY;
a23fd0e1
VZ
586
587 ::SetMapMode(GetHdc(), MM_ANISOTROPIC);
4676948b 588
a23fd0e1 589 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT, VIEWPORT_EXTENT, NULL);
1e2081a1 590 ::SetWindowExtEx(GetHdc(), width, height, NULL);
a23fd0e1
VZ
591 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL);
592 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX, (int)m_logicalOriginY, NULL);
4676948b 593#endif
a23fd0e1
VZ
594}
595
0c0d1521
WS
596bool wxDC::DoFloodFill(wxCoord WXUNUSED_IN_WINCE(x),
597 wxCoord WXUNUSED_IN_WINCE(y),
598 const wxColour& WXUNUSED_IN_WINCE(col),
599 int WXUNUSED_IN_WINCE(style))
a23fd0e1 600{
4676948b 601#ifdef __WXWINCE__
beb966c5 602 return false;
4676948b 603#else
beb966c5 604 WXMICROWIN_CHECK_HDC_RET(false)
d275c7eb 605
387ebd3e 606 bool success = (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x), YLOG2DEV(y),
0bafad0c
VZ
607 col.GetPixel(),
608 style == wxFLOOD_SURFACE ? FLOODFILLSURFACE
387ebd3e
JS
609 : FLOODFILLBORDER) ) ;
610 if (!success)
0bafad0c
VZ
611 {
612 // quoting from the MSDN docs:
613 //
614 // Following are some of the reasons this function might fail:
615 //
616 // * The filling could not be completed.
617 // * The specified point has the boundary color specified by the
618 // crColor parameter (if FLOODFILLBORDER was requested).
619 // * The specified point does not have the color specified by
620 // crColor (if FLOODFILLSURFACE was requested)
621 // * The point is outside the clipping region that is, it is not
622 // visible on the device.
623 //
f6bcfd97 624 wxLogLastError(wxT("ExtFloodFill"));
0bafad0c 625 }
a23fd0e1 626
7bcb11d3 627 CalcBoundingBox(x, y);
419430a0 628
387ebd3e 629 return success;
4676948b 630#endif
2bda0e17
KB
631}
632
72cdf4c9 633bool wxDC::DoGetPixel(wxCoord x, wxCoord y, wxColour *col) const
2bda0e17 634{
beb966c5 635 WXMICROWIN_CHECK_HDC_RET(false)
d275c7eb 636
beb966c5 637 wxCHECK_MSG( col, false, _T("NULL colour parameter in wxDC::GetPixel") );
f6bcfd97 638
7bcb11d3 639 // get the color of the pixel
a23fd0e1 640 COLORREF pixelcolor = ::GetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y));
0bafad0c 641
f6bcfd97 642 wxRGBToColour(*col, pixelcolor);
dc1efb1d 643
beb966c5 644 return true;
2bda0e17
KB
645}
646
72cdf4c9 647void wxDC::DoCrossHair(wxCoord x, wxCoord y)
a23fd0e1 648{
82a306b7 649 WXMICROWIN_CHECK_HDC
d275c7eb 650
72cdf4c9
VZ
651 wxCoord x1 = x-VIEWPORT_EXTENT;
652 wxCoord y1 = y-VIEWPORT_EXTENT;
653 wxCoord x2 = x+VIEWPORT_EXTENT;
654 wxCoord y2 = y+VIEWPORT_EXTENT;
a23fd0e1 655
4676948b
JS
656 wxDrawLine(GetHdc(), XLOG2DEV(x1), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y));
657 wxDrawLine(GetHdc(), XLOG2DEV(x), YLOG2DEV(y1), XLOG2DEV(x), YLOG2DEV(y2));
a23fd0e1 658
7bcb11d3
JS
659 CalcBoundingBox(x1, y1);
660 CalcBoundingBox(x2, y2);
2bda0e17
KB
661}
662
72cdf4c9 663void wxDC::DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
2bda0e17 664{
82a306b7 665 WXMICROWIN_CHECK_HDC
d275c7eb 666
4676948b 667 wxDrawLine(GetHdc(), XLOG2DEV(x1), YLOG2DEV(y1), XLOG2DEV(x2), YLOG2DEV(y2));
a23fd0e1 668
7bcb11d3
JS
669 CalcBoundingBox(x1, y1);
670 CalcBoundingBox(x2, y2);
2bda0e17
KB
671}
672
f6bcfd97
BP
673// Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
674// and ending at (x2, y2)
675void wxDC::DoDrawArc(wxCoord x1, wxCoord y1,
676 wxCoord x2, wxCoord y2,
677 wxCoord xc, wxCoord yc)
2bda0e17 678{
4676948b 679#ifdef __WXWINCE__
4f10962b
JS
680 // Slower emulation since WinCE doesn't support Pie and Arc
681 double r = sqrt( (x1-xc)*(x1-xc) + (y1-yc)*(y1-yc) );
682 double sa = acos((x1-xc)/r)/M_PI*180; // between 0 and 180
683 if( y1>yc ) sa = -sa; // below center
684 double ea = atan2(yc-y2, x2-xc)/M_PI*180;
685 DoDrawEllipticArcRot( xc-r, yc-r, 2*r, 2*r, sa, ea );
4676948b
JS
686#else
687
82a306b7 688 WXMICROWIN_CHECK_HDC
d275c7eb 689
f6bcfd97 690 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
2d8a5cb1 691
f6bcfd97
BP
692 double dx = xc - x1;
693 double dy = yc - y1;
694 double radius = (double)sqrt(dx*dx+dy*dy);
695 wxCoord r = (wxCoord)radius;
2d8a5cb1 696
f6bcfd97
BP
697 // treat the special case of full circle separately
698 if ( x1 == x2 && y1 == y2 )
7bcb11d3 699 {
f6bcfd97 700 DrawEllipse(xc - r, yc - r, 2*r, 2*r);
a23fd0e1 701 return;
7bcb11d3 702 }
a23fd0e1 703
72cdf4c9
VZ
704 wxCoord xx1 = XLOG2DEV(x1);
705 wxCoord yy1 = YLOG2DEV(y1);
706 wxCoord xx2 = XLOG2DEV(x2);
707 wxCoord yy2 = YLOG2DEV(y2);
708 wxCoord xxc = XLOG2DEV(xc);
709 wxCoord yyc = YLOG2DEV(yc);
710 wxCoord ray = (wxCoord) sqrt(double((xxc-xx1)*(xxc-xx1)+(yyc-yy1)*(yyc-yy1)));
a23fd0e1 711
72cdf4c9
VZ
712 wxCoord xxx1 = (wxCoord) (xxc-ray);
713 wxCoord yyy1 = (wxCoord) (yyc-ray);
714 wxCoord xxx2 = (wxCoord) (xxc+ray);
715 wxCoord yyy2 = (wxCoord) (yyc+ray);
f6bcfd97
BP
716
717 if ( m_brush.Ok() && m_brush.GetStyle() != wxTRANSPARENT )
7bcb11d3
JS
718 {
719 // Have to add 1 to bottom-right corner of rectangle
720 // to make semi-circles look right (crooked line otherwise).
721 // Unfortunately this is not a reliable method, depends
722 // on the size of shape.
723 // TODO: figure out why this happens!
f6bcfd97 724 Pie(GetHdc(),xxx1,yyy1,xxx2+1,yyy2+1, xx1,yy1,xx2,yy2);
7bcb11d3
JS
725 }
726 else
2d8a5cb1 727 {
f6bcfd97 728 Arc(GetHdc(),xxx1,yyy1,xxx2,yyy2, xx1,yy1,xx2,yy2);
2d8a5cb1 729 }
f6bcfd97
BP
730
731 CalcBoundingBox(xc - r, yc - r);
732 CalcBoundingBox(xc + r, yc + r);
4676948b 733#endif
2bda0e17
KB
734}
735
cd9da200
VZ
736void wxDC::DoDrawCheckMark(wxCoord x1, wxCoord y1,
737 wxCoord width, wxCoord height)
738{
b76d9e76
VZ
739 // cases when we don't have DrawFrameControl()
740#if defined(__SYMANTEC__) || defined(__WXMICROWIN__)
741 return wxDCBase::DoDrawCheckMark(x1, y1, width, height);
742#else // normal case
cd9da200
VZ
743 wxCoord x2 = x1 + width,
744 y2 = y1 + height;
745
cd9da200
VZ
746 RECT rect;
747 rect.left = x1;
748 rect.top = y1;
749 rect.right = x2;
750 rect.bottom = y2;
751
4676948b
JS
752#ifdef __WXWINCE__
753 DrawFrameControl(GetHdc(), &rect, DFC_BUTTON, DFCS_BUTTONCHECK);
754#else
cd9da200 755 DrawFrameControl(GetHdc(), &rect, DFC_MENU, DFCS_MENUCHECK);
4676948b 756#endif
cd9da200
VZ
757
758 CalcBoundingBox(x1, y1);
759 CalcBoundingBox(x2, y2);
b76d9e76 760#endif // Microwin/Normal
cd9da200
VZ
761}
762
72cdf4c9 763void wxDC::DoDrawPoint(wxCoord x, wxCoord y)
2bda0e17 764{
82a306b7 765 WXMICROWIN_CHECK_HDC
d275c7eb 766
7bcb11d3
JS
767 COLORREF color = 0x00ffffff;
768 if (m_pen.Ok())
769 {
a23fd0e1 770 color = m_pen.GetColour().GetPixel();
7bcb11d3 771 }
a23fd0e1
VZ
772
773 SetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), color);
774
7bcb11d3 775 CalcBoundingBox(x, y);
2bda0e17
KB
776}
777
0c0d1521
WS
778void wxDC::DoDrawPolygon(int n,
779 wxPoint points[],
780 wxCoord xoffset,
781 wxCoord yoffset,
782 int WXUNUSED_IN_WINCE(fillStyle))
2bda0e17 783{
82a306b7 784 WXMICROWIN_CHECK_HDC
d275c7eb 785
f6bcfd97 786 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
de2d2cdc 787
7bcb11d3
JS
788 // Do things less efficiently if we have offsets
789 if (xoffset != 0 || yoffset != 0)
6a6c0a8b 790 {
7bcb11d3
JS
791 POINT *cpoints = new POINT[n];
792 int i;
793 for (i = 0; i < n; i++)
794 {
795 cpoints[i].x = (int)(points[i].x + xoffset);
796 cpoints[i].y = (int)(points[i].y + yoffset);
a23fd0e1 797
7bcb11d3
JS
798 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
799 }
4676948b 800#ifndef __WXWINCE__
a23fd0e1 801 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
4676948b 802#endif
a23fd0e1 803 (void)Polygon(GetHdc(), cpoints, n);
4676948b 804#ifndef __WXWINCE__
a23fd0e1 805 SetPolyFillMode(GetHdc(),prev);
4676948b 806#endif
7bcb11d3
JS
807 delete[] cpoints;
808 }
809 else
810 {
811 int i;
812 for (i = 0; i < n; i++)
813 CalcBoundingBox(points[i].x, points[i].y);
a23fd0e1 814
4676948b 815#ifndef __WXWINCE__
a23fd0e1 816 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
4676948b 817#endif
a23fd0e1 818 (void)Polygon(GetHdc(), (POINT*) points, n);
4676948b 819#ifndef __WXWINCE__
a23fd0e1 820 SetPolyFillMode(GetHdc(),prev);
4676948b 821#endif
6a6c0a8b 822 }
2bda0e17
KB
823}
824
6e76b35d
VZ
825void
826wxDC::DoDrawPolyPolygon(int n,
793db755 827 int count[],
6e76b35d
VZ
828 wxPoint points[],
829 wxCoord xoffset,
830 wxCoord yoffset,
831 int fillStyle)
832{
d61c1a6f 833#ifdef __WXWINCE__
95c1ea29 834 wxDCBase::DoDrawPolyPolygon(n, count, points, xoffset, yoffset, fillStyle);
35bbb0c6 835#else
82a306b7 836 WXMICROWIN_CHECK_HDC
6e76b35d
VZ
837
838 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
839 int i, cnt;
840 for (i = cnt = 0; i < n; i++)
793db755 841 cnt += count[i];
6e76b35d
VZ
842
843 // Do things less efficiently if we have offsets
844 if (xoffset != 0 || yoffset != 0)
845 {
846 POINT *cpoints = new POINT[cnt];
847 for (i = 0; i < cnt; i++)
848 {
849 cpoints[i].x = (int)(points[i].x + xoffset);
850 cpoints[i].y = (int)(points[i].y + yoffset);
851
852 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
853 }
d61c1a6f 854#ifndef __WXWINCE__
6e76b35d 855 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
35bbb0c6 856#endif
793db755 857 (void)PolyPolygon(GetHdc(), cpoints, count, n);
d61c1a6f 858#ifndef __WXWINCE__
6e76b35d 859 SetPolyFillMode(GetHdc(),prev);
35bbb0c6 860#endif
6e76b35d
VZ
861 delete[] cpoints;
862 }
863 else
864 {
865 for (i = 0; i < cnt; i++)
866 CalcBoundingBox(points[i].x, points[i].y);
867
d61c1a6f 868#ifndef __WXWINCE__
6e76b35d 869 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
35bbb0c6 870#endif
793db755 871 (void)PolyPolygon(GetHdc(), (POINT*) points, count, n);
d61c1a6f 872#ifndef __WXWINCE__
6e76b35d 873 SetPolyFillMode(GetHdc(),prev);
35bbb0c6 874#endif
6e76b35d 875 }
d61c1a6f
JS
876#endif
877 // __WXWINCE__
6e76b35d
VZ
878}
879
72cdf4c9 880void wxDC::DoDrawLines(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset)
2bda0e17 881{
82a306b7 882 WXMICROWIN_CHECK_HDC
d275c7eb 883
7bcb11d3
JS
884 // Do things less efficiently if we have offsets
885 if (xoffset != 0 || yoffset != 0)
6a6c0a8b 886 {
7bcb11d3
JS
887 POINT *cpoints = new POINT[n];
888 int i;
889 for (i = 0; i < n; i++)
890 {
891 cpoints[i].x = (int)(points[i].x + xoffset);
892 cpoints[i].y = (int)(points[i].y + yoffset);
a23fd0e1 893
7bcb11d3
JS
894 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
895 }
a23fd0e1 896 (void)Polyline(GetHdc(), cpoints, n);
7bcb11d3
JS
897 delete[] cpoints;
898 }
899 else
900 {
901 int i;
902 for (i = 0; i < n; i++)
903 CalcBoundingBox(points[i].x, points[i].y);
a23fd0e1
VZ
904
905 (void)Polyline(GetHdc(), (POINT*) points, n);
6a6c0a8b 906 }
2bda0e17
KB
907}
908
72cdf4c9 909void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
2bda0e17 910{
82a306b7 911 WXMICROWIN_CHECK_HDC
d275c7eb 912
f6bcfd97 913 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
de2d2cdc 914
72cdf4c9
VZ
915 wxCoord x2 = x + width;
916 wxCoord y2 = y + height;
a23fd0e1 917
5456b916 918 if ((m_logicalFunction == wxCOPY) && (m_pen.GetStyle() == wxTRANSPARENT))
0bafad0c 919 {
7299b1b2 920 RECT rect;
5456b916
RR
921 rect.left = XLOG2DEV(x);
922 rect.top = YLOG2DEV(y);
923 rect.right = XLOG2DEV(x2);
7299b1b2
RD
924 rect.bottom = YLOG2DEV(y2);
925 (void)FillRect(GetHdc(), &rect, (HBRUSH)m_brush.GetResourceHandle() );
5456b916
RR
926 }
927 else
928 {
929 // Windows draws the filled rectangles without outline (i.e. drawn with a
930 // transparent pen) one pixel smaller in both directions and we want them
f6bcfd97 931 // to have the same size regardless of which pen is used - adjust
5456b916
RR
932
933