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