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