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