]> git.saurik.com Git - wxWidgets.git/blame - src/msw/dc.cpp
Another RTL fix.
[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
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);
3cdcf4d4 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);
3cdcf4d4 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{
b76d9e76
VZ
727 // cases when we don't have DrawFrameControl()
728#if defined(__SYMANTEC__) || defined(__WXMICROWIN__)
729 return wxDCBase::DoDrawCheckMark(x1, y1, width, height);
730#else // normal case
cd9da200
VZ
731 wxCoord x2 = x1 + width,
732 y2 = y1 + height;
733
cd9da200
VZ
734 RECT rect;
735 rect.left = x1;
736 rect.top = y1;
737 rect.right = x2;
738 rect.bottom = y2;
739
4676948b
JS
740#ifdef __WXWINCE__
741 DrawFrameControl(GetHdc(), &rect, DFC_BUTTON, DFCS_BUTTONCHECK);
742#else
cd9da200 743 DrawFrameControl(GetHdc(), &rect, DFC_MENU, DFCS_MENUCHECK);
4676948b 744#endif
cd9da200
VZ
745
746 CalcBoundingBox(x1, y1);
747 CalcBoundingBox(x2, y2);
b76d9e76 748#endif // Microwin/Normal
cd9da200
VZ
749}
750
72cdf4c9 751void wxDC::DoDrawPoint(wxCoord x, wxCoord y)
2bda0e17 752{
82a306b7 753 WXMICROWIN_CHECK_HDC
d275c7eb 754
7bcb11d3
JS
755 COLORREF color = 0x00ffffff;
756 if (m_pen.Ok())
757 {
a23fd0e1 758 color = m_pen.GetColour().GetPixel();
7bcb11d3 759 }
a23fd0e1
VZ
760
761 SetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), color);
762
7bcb11d3 763 CalcBoundingBox(x, y);
2bda0e17
KB
764}
765
0c0d1521
WS
766void wxDC::DoDrawPolygon(int n,
767 wxPoint points[],
768 wxCoord xoffset,
769 wxCoord yoffset,
770 int WXUNUSED_IN_WINCE(fillStyle))
2bda0e17 771{
82a306b7 772 WXMICROWIN_CHECK_HDC
d275c7eb 773
f6bcfd97 774 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
de2d2cdc 775
7bcb11d3
JS
776 // Do things less efficiently if we have offsets
777 if (xoffset != 0 || yoffset != 0)
6a6c0a8b 778 {
7bcb11d3
JS
779 POINT *cpoints = new POINT[n];
780 int i;
781 for (i = 0; i < n; i++)
782 {
783 cpoints[i].x = (int)(points[i].x + xoffset);
784 cpoints[i].y = (int)(points[i].y + yoffset);
a23fd0e1 785
7bcb11d3
JS
786 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
787 }
4676948b 788#ifndef __WXWINCE__
a23fd0e1 789 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
4676948b 790#endif
a23fd0e1 791 (void)Polygon(GetHdc(), cpoints, n);
4676948b 792#ifndef __WXWINCE__
a23fd0e1 793 SetPolyFillMode(GetHdc(),prev);
4676948b 794#endif
7bcb11d3
JS
795 delete[] cpoints;
796 }
797 else
798 {
799 int i;
800 for (i = 0; i < n; i++)
801 CalcBoundingBox(points[i].x, points[i].y);
a23fd0e1 802
4676948b 803#ifndef __WXWINCE__
a23fd0e1 804 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
4676948b 805#endif
a23fd0e1 806 (void)Polygon(GetHdc(), (POINT*) points, n);
4676948b 807#ifndef __WXWINCE__
a23fd0e1 808 SetPolyFillMode(GetHdc(),prev);
4676948b 809#endif
6a6c0a8b 810 }
2bda0e17
KB
811}
812
6e76b35d
VZ
813void
814wxDC::DoDrawPolyPolygon(int n,
793db755 815 int count[],
6e76b35d
VZ
816 wxPoint points[],
817 wxCoord xoffset,
818 wxCoord yoffset,
819 int fillStyle)
820{
d61c1a6f 821#ifdef __WXWINCE__
95c1ea29 822 wxDCBase::DoDrawPolyPolygon(n, count, points, xoffset, yoffset, fillStyle);
35bbb0c6 823#else
82a306b7 824 WXMICROWIN_CHECK_HDC
6e76b35d
VZ
825
826 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
827 int i, cnt;
828 for (i = cnt = 0; i < n; i++)
793db755 829 cnt += count[i];
6e76b35d
VZ
830
831 // Do things less efficiently if we have offsets
832 if (xoffset != 0 || yoffset != 0)
833 {
834 POINT *cpoints = new POINT[cnt];
835 for (i = 0; i < cnt; i++)
836 {
837 cpoints[i].x = (int)(points[i].x + xoffset);
838 cpoints[i].y = (int)(points[i].y + yoffset);
839
840 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
841 }
d61c1a6f 842#ifndef __WXWINCE__
6e76b35d 843 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
35bbb0c6 844#endif
793db755 845 (void)PolyPolygon(GetHdc(), cpoints, count, n);
d61c1a6f 846#ifndef __WXWINCE__
6e76b35d 847 SetPolyFillMode(GetHdc(),prev);
35bbb0c6 848#endif
6e76b35d
VZ
849 delete[] cpoints;
850 }
851 else
852 {
853 for (i = 0; i < cnt; i++)
854 CalcBoundingBox(points[i].x, points[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(), (POINT*) points, count, n);
d61c1a6f 860#ifndef __WXWINCE__
6e76b35d 861 SetPolyFillMode(GetHdc(),prev);
35bbb0c6 862#endif
6e76b35d 863 }
d61c1a6f
JS
864#endif
865 // __WXWINCE__
6e76b35d
VZ
866}
867
72cdf4c9 868void wxDC::DoDrawLines(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset)
2bda0e17 869{
82a306b7 870 WXMICROWIN_CHECK_HDC
d275c7eb 871
7bcb11d3
JS
872 // Do things less efficiently if we have offsets
873 if (xoffset != 0 || yoffset != 0)
6a6c0a8b 874 {
7bcb11d3
JS
875 POINT *cpoints = new POINT[n];
876 int i;
877 for (i = 0; i < n; i++)
878 {
879 cpoints[i].x = (int)(points[i].x + xoffset);
880 cpoints[i].y = (int)(points[i].y + yoffset);
a23fd0e1 881
7bcb11d3
JS
882 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
883 }
a23fd0e1 884 (void)Polyline(GetHdc(), cpoints, n);
7bcb11d3
JS
885 delete[] cpoints;
886 }
887 else
888 {
889 int i;
890 for (i = 0; i < n; i++)
891 CalcBoundingBox(points[i].x, points[i].y);
a23fd0e1
VZ
892
893 (void)Polyline(GetHdc(), (POINT*) points, n);
6a6c0a8b 894 }
2bda0e17
KB
895}
896
72cdf4c9 897void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
2bda0e17 898{
82a306b7 899 WXMICROWIN_CHECK_HDC
d275c7eb 900
f6bcfd97 901 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
de2d2cdc 902
72cdf4c9
VZ
903 wxCoord x2 = x + width;
904 wxCoord y2 = y + height;
a23fd0e1 905
5456b916 906 if ((m_logicalFunction == wxCOPY) && (m_pen.GetStyle() == wxTRANSPARENT))
0bafad0c 907 {
7299b1b2 908 RECT rect;
5456b916
RR
909 rect.left = XLOG2DEV(x);
910 rect.top = YLOG2DEV(y);
911 rect.right = XLOG2DEV(x2);
7299b1b2
RD
912 rect.bottom = YLOG2DEV(y2);
913 (void)FillRect(GetHdc(), &rect, (HBRUSH)m_brush.GetResourceHandle() );
5456b916
RR
914 }
915 else
916 {
917 // Windows draws the filled rectangles without outline (i.e. drawn with a
918 // transparent pen) one pixel smaller in both directions and we want them
f6bcfd97 919 // to have the same size regardless of which pen is used - adjust
5456b916
RR
920
921