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