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