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