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