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