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