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