]> git.saurik.com Git - wxWidgets.git/blame - src/msw/dc.cpp
keeping classnames in synch for xti
[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
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);
387ebd3e
JS
575
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
JS
632#ifdef __WXWINCE__
633 // FIXME: emulate Arc
634#else
635
5adad466
JS
636#ifdef __WXMICROWIN__
637 if (!GetHDC()) return;
638#endif
d275c7eb 639
f6bcfd97 640 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
2d8a5cb1 641
f6bcfd97
BP
642 double dx = xc - x1;
643 double dy = yc - y1;
644 double radius = (double)sqrt(dx*dx+dy*dy);
645 wxCoord r = (wxCoord)radius;
2d8a5cb1 646
f6bcfd97
BP
647 // treat the special case of full circle separately
648 if ( x1 == x2 && y1 == y2 )
7bcb11d3 649 {
f6bcfd97 650 DrawEllipse(xc - r, yc - r, 2*r, 2*r);
a23fd0e1 651 return;
7bcb11d3 652 }
a23fd0e1 653
72cdf4c9
VZ
654 wxCoord xx1 = XLOG2DEV(x1);
655 wxCoord yy1 = YLOG2DEV(y1);
656 wxCoord xx2 = XLOG2DEV(x2);
657 wxCoord yy2 = YLOG2DEV(y2);
658 wxCoord xxc = XLOG2DEV(xc);
659 wxCoord yyc = YLOG2DEV(yc);
660 wxCoord ray = (wxCoord) sqrt(double((xxc-xx1)*(xxc-xx1)+(yyc-yy1)*(yyc-yy1)));
a23fd0e1 661
72cdf4c9
VZ
662 wxCoord xxx1 = (wxCoord) (xxc-ray);
663 wxCoord yyy1 = (wxCoord) (yyc-ray);
664 wxCoord xxx2 = (wxCoord) (xxc+ray);
665 wxCoord yyy2 = (wxCoord) (yyc+ray);
f6bcfd97
BP
666
667 if ( m_brush.Ok() && m_brush.GetStyle() != wxTRANSPARENT )
7bcb11d3
JS
668 {
669 // Have to add 1 to bottom-right corner of rectangle
670 // to make semi-circles look right (crooked line otherwise).
671 // Unfortunately this is not a reliable method, depends
672 // on the size of shape.
673 // TODO: figure out why this happens!
f6bcfd97 674 Pie(GetHdc(),xxx1,yyy1,xxx2+1,yyy2+1, xx1,yy1,xx2,yy2);
7bcb11d3
JS
675 }
676 else
2d8a5cb1 677 {
f6bcfd97 678 Arc(GetHdc(),xxx1,yyy1,xxx2,yyy2, xx1,yy1,xx2,yy2);
2d8a5cb1 679 }
f6bcfd97
BP
680
681 CalcBoundingBox(xc - r, yc - r);
682 CalcBoundingBox(xc + r, yc + r);
4676948b 683#endif
2bda0e17
KB
684}
685
cd9da200
VZ
686void wxDC::DoDrawCheckMark(wxCoord x1, wxCoord y1,
687 wxCoord width, wxCoord height)
688{
5adad466
JS
689#ifdef __WXMICROWIN__
690 if (!GetHDC()) return;
691#endif
d275c7eb 692
cd9da200
VZ
693 wxCoord x2 = x1 + width,
694 y2 = y1 + height;
695
1e3c12d7 696#if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__)
cd9da200
VZ
697 RECT rect;
698 rect.left = x1;
699 rect.top = y1;
700 rect.right = x2;
701 rect.bottom = y2;
702
4676948b
JS
703#ifdef __WXWINCE__
704 DrawFrameControl(GetHdc(), &rect, DFC_BUTTON, DFCS_BUTTONCHECK);
705#else
cd9da200 706 DrawFrameControl(GetHdc(), &rect, DFC_MENU, DFCS_MENUCHECK);
4676948b 707#endif
cd9da200
VZ
708#else // Win16
709 // In WIN16, draw a cross
710 HPEN blackPen = ::CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
711 HPEN whiteBrush = (HPEN)::GetStockObject(WHITE_BRUSH);
e06b9569
JS
712 HPEN hPenOld = (HPEN)::SelectObject(GetHdc(), blackPen);
713 HPEN hBrushOld = (HPEN)::SelectObject(GetHdc(), whiteBrush);
cd9da200
VZ
714 ::SetROP2(GetHdc(), R2_COPYPEN);
715 Rectangle(GetHdc(), x1, y1, x2, y2);
8cb172b4 716 MoveToEx(GetHdc(), x1, y1, NULL);
cd9da200 717 LineTo(GetHdc(), x2, y2);
8cb172b4 718 MoveToEx(GetHdc(), x2, y1, NULL);
cd9da200
VZ
719 LineTo(GetHdc(), x1, y2);
720 ::SelectObject(GetHdc(), hPenOld);
721 ::SelectObject(GetHdc(), hBrushOld);
722 ::DeleteObject(blackPen);
723#endif // Win32/16
724
725 CalcBoundingBox(x1, y1);
726 CalcBoundingBox(x2, y2);
727}
728
72cdf4c9 729void wxDC::DoDrawPoint(wxCoord x, wxCoord y)
2bda0e17 730{
5adad466
JS
731#ifdef __WXMICROWIN__
732 if (!GetHDC()) return;
733#endif
d275c7eb 734
7bcb11d3
JS
735 COLORREF color = 0x00ffffff;
736 if (m_pen.Ok())
737 {
a23fd0e1 738 color = m_pen.GetColour().GetPixel();
7bcb11d3 739 }
a23fd0e1
VZ
740
741 SetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), color);
742
7bcb11d3 743 CalcBoundingBox(x, y);
2bda0e17
KB
744}
745
72cdf4c9 746void wxDC::DoDrawPolygon(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset,int fillStyle)
2bda0e17 747{
5adad466
JS
748#ifdef __WXMICROWIN__
749 if (!GetHDC()) return;
750#endif
d275c7eb 751
f6bcfd97 752 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
de2d2cdc 753
7bcb11d3
JS
754 // Do things less efficiently if we have offsets
755 if (xoffset != 0 || yoffset != 0)
6a6c0a8b 756 {
7bcb11d3
JS
757 POINT *cpoints = new POINT[n];
758 int i;
759 for (i = 0; i < n; i++)
760 {
761 cpoints[i].x = (int)(points[i].x + xoffset);
762 cpoints[i].y = (int)(points[i].y + yoffset);
a23fd0e1 763
7bcb11d3
JS
764 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
765 }
4676948b 766#ifndef __WXWINCE__
a23fd0e1 767 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
4676948b 768#endif
a23fd0e1 769 (void)Polygon(GetHdc(), cpoints, n);
4676948b 770#ifndef __WXWINCE__
a23fd0e1 771 SetPolyFillMode(GetHdc(),prev);
4676948b 772#endif
7bcb11d3
JS
773 delete[] cpoints;
774 }
775 else
776 {
777 int i;
778 for (i = 0; i < n; i++)
779 CalcBoundingBox(points[i].x, points[i].y);
a23fd0e1 780
4676948b 781#ifndef __WXWINCE__
a23fd0e1 782 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
4676948b 783#endif
a23fd0e1 784 (void)Polygon(GetHdc(), (POINT*) points, n);
4676948b 785#ifndef __WXWINCE__
a23fd0e1 786 SetPolyFillMode(GetHdc(),prev);
4676948b 787#endif
6a6c0a8b 788 }
2bda0e17
KB
789}
790
72cdf4c9 791void wxDC::DoDrawLines(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset)
2bda0e17 792{
5adad466
JS
793#ifdef __WXMICROWIN__
794 if (!GetHDC()) return;
795#endif
d275c7eb 796
7bcb11d3
JS
797 // Do things less efficiently if we have offsets
798 if (xoffset != 0 || yoffset != 0)
6a6c0a8b 799 {
7bcb11d3
JS
800 POINT *cpoints = new POINT[n];
801 int i;
802 for (i = 0; i < n; i++)
803 {
804 cpoints[i].x = (int)(points[i].x + xoffset);
805 cpoints[i].y = (int)(points[i].y + yoffset);
a23fd0e1 806
7bcb11d3
JS
807 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
808 }
a23fd0e1 809 (void)Polyline(GetHdc(), cpoints, n);
7bcb11d3
JS
810 delete[] cpoints;
811 }
812 else
813 {
814 int i;
815 for (i = 0; i < n; i++)
816 CalcBoundingBox(points[i].x, points[i].y);
a23fd0e1
VZ
817
818 (void)Polyline(GetHdc(), (POINT*) points, n);
6a6c0a8b 819 }
2bda0e17
KB
820}
821
72cdf4c9 822void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
2bda0e17 823{
5adad466
JS
824#ifdef __WXMICROWIN__
825 if (!GetHDC()) return;
826#endif
d275c7eb 827
f6bcfd97 828 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
de2d2cdc 829
72cdf4c9
VZ
830 wxCoord x2 = x + width;
831 wxCoord y2 = y + height;
a23fd0e1 832
5456b916 833 if ((m_logicalFunction == wxCOPY) && (m_pen.GetStyle() == wxTRANSPARENT))
0bafad0c 834 {
7299b1b2 835 RECT rect;
5456b916
RR
836 rect.left = XLOG2DEV(x);
837 rect.top = YLOG2DEV(y);
838 rect.right = XLOG2DEV(x2);
7299b1b2
RD
839 rect.bottom = YLOG2DEV(y2);
840 (void)FillRect(GetHdc(), &rect, (HBRUSH)m_brush.GetResourceHandle() );
5456b916
RR
841 }
842 else
843 {
844 // Windows draws the filled rectangles without outline (i.e. drawn with a
845 // transparent pen) one pixel smaller in both directions and we want them
f6bcfd97 846 // to have the same size regardless of which pen is used - adjust
5456b916
RR
847
848