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