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