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