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