]> git.saurik.com Git - wxWidgets.git/blame - src/msw/dc.cpp
wxCocoa: Allow calendar control, spin button, spin control
[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
275a63e3
VZ
120// call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
121//
122// NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed
123// to pass it to this function but as we already have it at the point
124// of call anyhow we do
125//
126// return true if we could draw the bitmap in one way or the other, false
127// otherwise
128static bool AlphaBlt(HDC hdcDst,
129 int x, int y, int w, int h,
130 HDC hdcSrc,
131 const wxBitmap& bmpSrc);
1e3c12d7
CE
132
133#ifdef wxHAVE_RAW_BITMAP
878711c0
VZ
134// our (limited) AlphaBlend() replacement
135static void
275a63e3 136wxAlphaBlend(HDC hdcDst, int x, int y, int w, int h, const wxBitmap& bmp);
1e3c12d7 137#endif
878711c0 138
f6bcfd97
BP
139// ----------------------------------------------------------------------------
140// private classes
141// ----------------------------------------------------------------------------
142
143// instead of duplicating the same code which sets and then restores text
144// colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
145// encapsulate this in a small helper class
146
147// wxColourChanger: changes the text colours in the ctor if required and
148// restores them in the dtor
149class wxColourChanger
150{
151public:
152 wxColourChanger(wxDC& dc);
153 ~wxColourChanger();
154
155private:
156 wxDC& m_dc;
157
158 COLORREF m_colFgOld, m_colBgOld;
159
160 bool m_changed;
161};
162
f178ab7e
VZ
163// this class saves the old stretch blit mode during its life time
164class StretchBltModeChanger
165{
166public:
167 StretchBltModeChanger(HDC hdc, int mode)
168 : m_hdc(hdc)
169 {
4676948b 170#ifndef __WXWINCE__
f178ab7e
VZ
171 m_modeOld = ::SetStretchBltMode(m_hdc, mode);
172 if ( !m_modeOld )
173 wxLogLastError(_T("SetStretchBltMode"));
4676948b 174#endif
f178ab7e
VZ
175 }
176
177 ~StretchBltModeChanger()
178 {
4676948b 179#ifndef __WXWINCE__
f178ab7e
VZ
180 if ( !::SetStretchBltMode(m_hdc, m_modeOld) )
181 wxLogLastError(_T("SetStretchBltMode"));
4676948b 182#endif
f178ab7e
VZ
183 }
184
185private:
186 const HDC m_hdc;
187
188 int m_modeOld;
189};
190
a23fd0e1
VZ
191// ===========================================================================
192// implementation
193// ===========================================================================
194
f6bcfd97
BP
195// ----------------------------------------------------------------------------
196// wxColourChanger
197// ----------------------------------------------------------------------------
198
199wxColourChanger::wxColourChanger(wxDC& dc) : m_dc(dc)
200{
cafbad8f
VZ
201 const wxBrush& brush = dc.GetBrush();
202 if ( brush.Ok() && brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE )
f6bcfd97
BP
203 {
204 HDC hdc = GetHdcOf(dc);
205 m_colFgOld = ::GetTextColor(hdc);
206 m_colBgOld = ::GetBkColor(hdc);
207
208 // note that Windows convention is opposite to wxWindows one, this is
209 // why text colour becomes the background one and vice versa
210 const wxColour& colFg = dc.GetTextForeground();
211 if ( colFg.Ok() )
212 {
213 ::SetBkColor(hdc, colFg.GetPixel());
214 }
215
216 const wxColour& colBg = dc.GetTextBackground();
217 if ( colBg.Ok() )
218 {
219 ::SetTextColor(hdc, colBg.GetPixel());
220 }
221
222 SetBkMode(hdc,
223 dc.GetBackgroundMode() == wxTRANSPARENT ? TRANSPARENT
224 : OPAQUE);
225
226 // flag which telsl us to undo changes in the dtor
227 m_changed = TRUE;
228 }
229 else
230 {
231 // nothing done, nothing to undo
232 m_changed = FALSE;
233 }
234}
235
236wxColourChanger::~wxColourChanger()
237{
238 if ( m_changed )
239 {
240 // restore the colours we changed
241 HDC hdc = GetHdcOf(m_dc);
242
243 ::SetBkMode(hdc, TRANSPARENT);
244 ::SetTextColor(hdc, m_colFgOld);
245 ::SetBkColor(hdc, m_colBgOld);
246 }
247}
248
a23fd0e1
VZ
249// ---------------------------------------------------------------------------
250// wxDC
251// ---------------------------------------------------------------------------
2bda0e17
KB
252
253// Default constructor
a23fd0e1 254wxDC::wxDC()
2bda0e17 255{
7bcb11d3 256 m_canvas = NULL;
a23fd0e1 257
7bcb11d3
JS
258 m_oldBitmap = 0;
259 m_oldPen = 0;
260 m_oldBrush = 0;
261 m_oldFont = 0;
d275c7eb 262#if wxUSE_PALETTE
7bcb11d3 263 m_oldPalette = 0;
d275c7eb 264#endif // wxUSE_PALETTE
a23fd0e1 265
7bcb11d3
JS
266 m_bOwnsDC = FALSE;
267 m_hDC = 0;
2bda0e17
KB
268}
269
a23fd0e1 270wxDC::~wxDC()
2bda0e17 271{
7ba4fbeb
VZ
272 if ( m_hDC != 0 )
273 {
7bcb11d3 274 SelectOldObjects(m_hDC);
7ba4fbeb
VZ
275
276 // if we own the HDC, we delete it, otherwise we just release it
277
278 if ( m_bOwnsDC )
279 {
280 ::DeleteDC(GetHdc());
7bcb11d3 281 }
7ba4fbeb
VZ
282 else // we don't own our HDC
283 {
db400410
JS
284 if (m_canvas)
285 {
286 ::ReleaseDC(GetHwndOf(m_canvas), GetHdc());
287 }
288 else
289 {
290 // Must have been a wxScreenDC
291 ::ReleaseDC((HWND) NULL, GetHdc());
292 }
7ba4fbeb
VZ
293 }
294 }
2bda0e17
KB
295}
296
297// This will select current objects out of the DC,
298// which is what you have to do before deleting the
299// DC.
300void wxDC::SelectOldObjects(WXHDC dc)
301{
7bcb11d3 302 if (dc)
2bda0e17 303 {
7bcb11d3
JS
304 if (m_oldBitmap)
305 {
306 ::SelectObject((HDC) dc, (HBITMAP) m_oldBitmap);
3ca22d5e 307#ifdef __WXDEBUG__
7bcb11d3
JS
308 if (m_selectedBitmap.Ok())
309 {
310 m_selectedBitmap.SetSelectedInto(NULL);
311 }
3ca22d5e 312#endif
7bcb11d3 313 }
a23fd0e1 314 m_oldBitmap = 0;
7bcb11d3
JS
315 if (m_oldPen)
316 {
317 ::SelectObject((HDC) dc, (HPEN) m_oldPen);
318 }
a23fd0e1 319 m_oldPen = 0;
7bcb11d3
JS
320 if (m_oldBrush)
321 {
322 ::SelectObject((HDC) dc, (HBRUSH) m_oldBrush);
323 }
a23fd0e1 324 m_oldBrush = 0;
7bcb11d3
JS
325 if (m_oldFont)
326 {
327 ::SelectObject((HDC) dc, (HFONT) m_oldFont);
328 }
a23fd0e1 329 m_oldFont = 0;
d275c7eb
VZ
330
331#if wxUSE_PALETTE
7bcb11d3
JS
332 if (m_oldPalette)
333 {
19193a2c 334 ::SelectPalette((HDC) dc, (HPALETTE) m_oldPalette, FALSE);
7bcb11d3 335 }
a23fd0e1 336 m_oldPalette = 0;
d275c7eb 337#endif // wxUSE_PALETTE
2bda0e17 338 }
a23fd0e1
VZ
339
340 m_brush = wxNullBrush;
7bcb11d3 341 m_pen = wxNullPen;
d275c7eb 342#if wxUSE_PALETTE
7bcb11d3 343 m_palette = wxNullPalette;
d275c7eb 344#endif // wxUSE_PALETTE
7bcb11d3
JS
345 m_font = wxNullFont;
346 m_backgroundBrush = wxNullBrush;
347 m_selectedBitmap = wxNullBitmap;
2bda0e17
KB
348}
349
a23fd0e1
VZ
350// ---------------------------------------------------------------------------
351// clipping
352// ---------------------------------------------------------------------------
353
1e6feb95
VZ
354void wxDC::UpdateClipBox()
355{
5adad466
JS
356#ifdef __WXMICROWIN__
357 if (!GetHDC()) return;
358#endif
d275c7eb 359
1e6feb95 360 RECT rect;
5230934a 361 ::GetClipBox(GetHdc(), &rect);
1e6feb95
VZ
362
363 m_clipX1 = (wxCoord) XDEV2LOG(rect.left);
364 m_clipY1 = (wxCoord) YDEV2LOG(rect.top);
365 m_clipX2 = (wxCoord) XDEV2LOG(rect.right);
366 m_clipY2 = (wxCoord) YDEV2LOG(rect.bottom);
f547e9bb
RL
367}
368
5230934a
VZ
369// common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
370void wxDC::SetClippingHrgn(WXHRGN hrgn)
2bda0e17 371{
5230934a
VZ
372 wxCHECK_RET( hrgn, wxT("invalid clipping region") );
373
5adad466 374#ifdef __WXMICROWIN__
5230934a
VZ
375 if (!GetHdc()) return;
376#endif // __WXMICROWIN__
377
378 // note that we combine the new clipping region with the existing one: this
379 // is compatible with what the other ports do and is the documented
380 // behaviour now (starting with 2.3.3)
4676948b 381#if defined(__WIN16__) || defined(__WXWINCE__)
5230934a
VZ
382 RECT rectClip;
383 if ( !::GetClipBox(GetHdc(), &rectClip) )
384 return;
385
386 HRGN hrgnDest = ::CreateRectRgn(0, 0, 0, 0);
387 HRGN hrgnClipOld = ::CreateRectRgn(rectClip.left, rectClip.top,
388 rectClip.right, rectClip.bottom);
389
390 if ( ::CombineRgn(hrgnDest, hrgnClipOld, (HRGN)hrgn, RGN_AND) != ERROR )
391 {
392 ::SelectClipRgn(GetHdc(), hrgnDest);
393 }
394
395 ::DeleteObject(hrgnClipOld);
396 ::DeleteObject(hrgnDest);
397#else // Win32
398 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN)hrgn, RGN_AND) == ERROR )
399 {
400 wxLogLastError(_T("ExtSelectClipRgn"));
401
402 return;
403 }
404#endif // Win16/32
d275c7eb 405
7bcb11d3 406 m_clipping = TRUE;
40a89076 407
5230934a
VZ
408 UpdateClipBox();
409}
410
411void wxDC::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
412{
c4218a74
VZ
413 // the region coords are always the device ones, so do the translation
414 // manually
1e6feb95
VZ
415 //
416 // FIXME: possible +/-1 error here, to check!
c4218a74
VZ
417 HRGN hrgn = ::CreateRectRgn(LogicalToDeviceX(x),
418 LogicalToDeviceY(y),
419 LogicalToDeviceX(x + w),
420 LogicalToDeviceY(y + h));
40a89076
VZ
421 if ( !hrgn )
422 {
423 wxLogLastError(_T("CreateRectRgn"));
424 }
425 else
426 {
5230934a 427 SetClippingHrgn((WXHRGN)hrgn);
40a89076 428
5230934a 429 ::DeleteObject(hrgn);
40a89076 430 }
2bda0e17
KB
431}
432
a23fd0e1 433void wxDC::DoSetClippingRegionAsRegion(const wxRegion& region)
a724d789 434{
5230934a 435 SetClippingHrgn(region.GetHRGN());
2bda0e17
KB
436}
437
a23fd0e1 438void wxDC::DestroyClippingRegion()
2bda0e17 439{
5adad466
JS
440#ifdef __WXMICROWIN__
441 if (!GetHDC()) return;
442#endif
d275c7eb 443
7bcb11d3
JS
444 if (m_clipping && m_hDC)
445 {
446 // TODO: this should restore the previous clipping region,
5230934a
VZ
447 // so that OnPaint processing works correctly, and the update
448 // clipping region doesn't get destroyed after the first
449 // DestroyClippingRegion.
7bcb11d3 450 HRGN rgn = CreateRectRgn(0, 0, 32000, 32000);
5230934a
VZ
451 ::SelectClipRgn(GetHdc(), rgn);
452 ::DeleteObject(rgn);
7bcb11d3 453 }
1e6feb95 454
7bcb11d3 455 m_clipping = FALSE;
2bda0e17
KB
456}
457
a23fd0e1
VZ
458// ---------------------------------------------------------------------------
459// query capabilities
460// ---------------------------------------------------------------------------
461
462bool wxDC::CanDrawBitmap() const
2bda0e17 463{
7bcb11d3 464 return TRUE;
2bda0e17
KB
465}
466
a23fd0e1 467bool wxDC::CanGetTextExtent() const
2bda0e17 468{
04ef50df
JS
469#ifdef __WXMICROWIN__
470 // TODO Extend MicroWindows' GetDeviceCaps function
471 return TRUE;
472#else
7bcb11d3 473 // What sort of display is it?
a23fd0e1
VZ
474 int technology = ::GetDeviceCaps(GetHdc(), TECHNOLOGY);
475
476 return (technology == DT_RASDISPLAY) || (technology == DT_RASPRINTER);
04ef50df 477#endif
2bda0e17
KB
478}
479
a23fd0e1 480int wxDC::GetDepth() const
2bda0e17 481{
5adad466
JS
482#ifdef __WXMICROWIN__
483 if (!GetHDC()) return 16;
484#endif
d275c7eb 485
a23fd0e1 486 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL);
2bda0e17
KB
487}
488
a23fd0e1
VZ
489// ---------------------------------------------------------------------------
490// drawing
491// ---------------------------------------------------------------------------
492
493void wxDC::Clear()
2bda0e17 494{
5adad466
JS
495#ifdef __WXMICROWIN__
496 if (!GetHDC()) return;
497#endif
d275c7eb 498
7bcb11d3 499 RECT rect;
2506aab6
VZ
500 if ( m_canvas )
501 {
7bcb11d3 502 GetClientRect((HWND) m_canvas->GetHWND(), &rect);
2506aab6
VZ
503 }
504 else
7bcb11d3 505 {
eaeb6a3c
JS
506 // No, I think we should simply ignore this if printing on e.g.
507 // a printer DC.
508 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
509 if (!m_selectedBitmap.Ok())
510 return;
2506aab6 511
7bcb11d3
JS
512 rect.left = 0; rect.top = 0;
513 rect.right = m_selectedBitmap.GetWidth();
514 rect.bottom = m_selectedBitmap.GetHeight();
515 }
2506aab6 516
4676948b 517#ifndef __WXWINCE__
a23fd0e1 518 (void) ::SetMapMode(GetHdc(), MM_TEXT);
4676948b 519#endif
a23fd0e1 520
1e2081a1
VZ
521 DWORD colour = ::GetBkColor(GetHdc());
522 HBRUSH brush = ::CreateSolidBrush(colour);
523 ::FillRect(GetHdc(), &rect, brush);
524 ::DeleteObject(brush);
525
526 int width = DeviceToLogicalXRel(VIEWPORT_EXTENT)*m_signX,
527 height = DeviceToLogicalYRel(VIEWPORT_EXTENT)*m_signY;
a23fd0e1 528
4676948b 529#ifndef __WXWINCE__
a23fd0e1 530 ::SetMapMode(GetHdc(), MM_ANISOTROPIC);
4676948b 531
a23fd0e1 532 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT, VIEWPORT_EXTENT, NULL);
1e2081a1 533 ::SetWindowExtEx(GetHdc(), width, height, NULL);
a23fd0e1
VZ
534 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL);
535 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX, (int)m_logicalOriginY, NULL);
4676948b 536#endif
a23fd0e1
VZ
537}
538
387ebd3e 539bool wxDC::DoFloodFill(wxCoord x, wxCoord y, const wxColour& col, int style)
a23fd0e1 540{
4676948b
JS
541#ifdef __WXWINCE__
542 return FALSE;
543#else
544
5adad466 545#ifdef __WXMICROWIN__
387ebd3e 546 if (!GetHDC()) return FALSE;
5adad466 547#endif
d275c7eb 548
387ebd3e 549 bool success = (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x), YLOG2DEV(y),
0bafad0c
VZ
550 col.GetPixel(),
551 style == wxFLOOD_SURFACE ? FLOODFILLSURFACE
387ebd3e
JS
552 : FLOODFILLBORDER) ) ;
553 if (!success)
0bafad0c
VZ
554 {
555 // quoting from the MSDN docs:
556 //
557 // Following are some of the reasons this function might fail:
558 //
559 // * The filling could not be completed.
560 // * The specified point has the boundary color specified by the
561 // crColor parameter (if FLOODFILLBORDER was requested).
562 // * The specified point does not have the color specified by
563 // crColor (if FLOODFILLSURFACE was requested)
564 // * The point is outside the clipping region that is, it is not
565 // visible on the device.
566 //
f6bcfd97 567 wxLogLastError(wxT("ExtFloodFill"));
0bafad0c 568 }
a23fd0e1 569
7bcb11d3 570 CalcBoundingBox(x, y);
387ebd3e
JS
571
572 return success;
4676948b 573#endif
2bda0e17
KB
574}
575
72cdf4c9 576bool wxDC::DoGetPixel(wxCoord x, wxCoord y, wxColour *col) const
2bda0e17 577{
5adad466
JS
578#ifdef __WXMICROWIN__
579 if (!GetHDC()) return FALSE;
580#endif
d275c7eb 581
f6bcfd97
BP
582 wxCHECK_MSG( col, FALSE, _T("NULL colour parameter in wxDC::GetPixel") );
583
7bcb11d3 584 // get the color of the pixel
a23fd0e1 585 COLORREF pixelcolor = ::GetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y));
0bafad0c 586
f6bcfd97 587 wxRGBToColour(*col, pixelcolor);
dc1efb1d
JS
588
589 return TRUE;
2bda0e17
KB
590}
591
72cdf4c9 592void wxDC::DoCrossHair(wxCoord x, wxCoord y)
a23fd0e1 593{
5adad466
JS
594#ifdef __WXMICROWIN__
595 if (!GetHDC()) return;
596#endif
d275c7eb 597
72cdf4c9
VZ
598 wxCoord x1 = x-VIEWPORT_EXTENT;
599 wxCoord y1 = y-VIEWPORT_EXTENT;
600 wxCoord x2 = x+VIEWPORT_EXTENT;
601 wxCoord y2 = y+VIEWPORT_EXTENT;
a23fd0e1 602
4676948b
JS
603 wxDrawLine(GetHdc(), XLOG2DEV(x1), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y));
604 wxDrawLine(GetHdc(), XLOG2DEV(x), YLOG2DEV(y1), XLOG2DEV(x), YLOG2DEV(y2));
a23fd0e1 605
7bcb11d3
JS
606 CalcBoundingBox(x1, y1);
607 CalcBoundingBox(x2, y2);
2bda0e17
KB
608}
609
72cdf4c9 610void wxDC::DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
2bda0e17 611{
5adad466
JS
612#ifdef __WXMICROWIN__
613 if (!GetHDC()) return;
614#endif
d275c7eb 615
4676948b 616 wxDrawLine(GetHdc(), XLOG2DEV(x1), YLOG2DEV(y1), XLOG2DEV(x2), YLOG2DEV(y2));
a23fd0e1 617
7bcb11d3
JS
618 CalcBoundingBox(x1, y1);
619 CalcBoundingBox(x2, y2);
2bda0e17
KB
620}
621
f6bcfd97
BP
622// Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
623// and ending at (x2, y2)
624void wxDC::DoDrawArc(wxCoord x1, wxCoord y1,
625 wxCoord x2, wxCoord y2,
626 wxCoord xc, wxCoord yc)
2bda0e17 627{
4676948b
JS
628#ifdef __WXWINCE__
629 // FIXME: emulate Arc
630#else
631
5adad466
JS
632#ifdef __WXMICROWIN__
633 if (!GetHDC()) return;
634#endif
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{
5adad466
JS
685#ifdef __WXMICROWIN__
686 if (!GetHDC()) return;
687#endif
d275c7eb 688
cd9da200
VZ
689 wxCoord x2 = x1 + width,
690 y2 = y1 + height;
691
1e3c12d7 692#if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__)
cd9da200
VZ
693 RECT rect;
694 rect.left = x1;
695 rect.top = y1;
696 rect.right = x2;
697 rect.bottom = y2;
698
4676948b
JS
699#ifdef __WXWINCE__
700 DrawFrameControl(GetHdc(), &rect, DFC_BUTTON, DFCS_BUTTONCHECK);
701#else
cd9da200 702 DrawFrameControl(GetHdc(), &rect, DFC_MENU, DFCS_MENUCHECK);
4676948b 703#endif
cd9da200
VZ
704#else // Win16
705 // In WIN16, draw a cross
706 HPEN blackPen = ::CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
707 HPEN whiteBrush = (HPEN)::GetStockObject(WHITE_BRUSH);
e06b9569
JS
708 HPEN hPenOld = (HPEN)::SelectObject(GetHdc(), blackPen);
709 HPEN hBrushOld = (HPEN)::SelectObject(GetHdc(), whiteBrush);
cd9da200
VZ
710 ::SetROP2(GetHdc(), R2_COPYPEN);
711 Rectangle(GetHdc(), x1, y1, x2, y2);
8cb172b4 712 MoveToEx(GetHdc(), x1, y1, NULL);
cd9da200 713 LineTo(GetHdc(), x2, y2);
8cb172b4 714 MoveToEx(GetHdc(), x2, y1, NULL);
cd9da200
VZ
715 LineTo(GetHdc(), x1, y2);
716 ::SelectObject(GetHdc(), hPenOld);
717 ::SelectObject(GetHdc(), hBrushOld);
718 ::DeleteObject(blackPen);
719#endif // Win32/16
720
721 CalcBoundingBox(x1, y1);
722 CalcBoundingBox(x2, y2);
723}
724
72cdf4c9 725void wxDC::DoDrawPoint(wxCoord x, wxCoord y)
2bda0e17 726{
5adad466
JS
727#ifdef __WXMICROWIN__
728 if (!GetHDC()) return;
729#endif
d275c7eb 730
7bcb11d3
JS
731 COLORREF color = 0x00ffffff;
732 if (m_pen.Ok())
733 {
a23fd0e1 734 color = m_pen.GetColour().GetPixel();
7bcb11d3 735 }
a23fd0e1
VZ
736
737 SetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), color);
738
7bcb11d3 739 CalcBoundingBox(x, y);
2bda0e17
KB
740}
741
72cdf4c9 742void wxDC::DoDrawPolygon(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset,int fillStyle)
2bda0e17 743{
5adad466
JS
744#ifdef __WXMICROWIN__
745 if (!GetHDC()) return;
746#endif
d275c7eb 747
f6bcfd97 748 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
de2d2cdc 749
7bcb11d3
JS
750 // Do things less efficiently if we have offsets
751 if (xoffset != 0 || yoffset != 0)
6a6c0a8b 752 {
7bcb11d3
JS
753 POINT *cpoints = new POINT[n];
754 int i;
755 for (i = 0; i < n; i++)
756 {
757 cpoints[i].x = (int)(points[i].x + xoffset);
758 cpoints[i].y = (int)(points[i].y + yoffset);
a23fd0e1 759
7bcb11d3
JS
760 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
761 }
4676948b 762#ifndef __WXWINCE__
a23fd0e1 763 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
4676948b 764#endif
a23fd0e1 765 (void)Polygon(GetHdc(), cpoints, n);
4676948b 766#ifndef __WXWINCE__
a23fd0e1 767 SetPolyFillMode(GetHdc(),prev);
4676948b 768#endif
7bcb11d3
JS
769 delete[] cpoints;
770 }
771 else
772 {
773 int i;
774 for (i = 0; i < n; i++)
775 CalcBoundingBox(points[i].x, points[i].y);
a23fd0e1 776
4676948b 777#ifndef __WXWINCE__
a23fd0e1 778 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
4676948b 779#endif
a23fd0e1 780 (void)Polygon(GetHdc(), (POINT*) points, n);
4676948b 781#ifndef __WXWINCE__
a23fd0e1 782 SetPolyFillMode(GetHdc(),prev);
4676948b 783#endif
6a6c0a8b 784 }
2bda0e17
KB
785}
786
72cdf4c9 787void wxDC::DoDrawLines(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset)
2bda0e17 788{
5adad466
JS
789#ifdef __WXMICROWIN__
790 if (!GetHDC()) return;
791#endif
d275c7eb 792
7bcb11d3
JS
793 // Do things less efficiently if we have offsets
794 if (xoffset != 0 || yoffset != 0)
6a6c0a8b 795 {
7bcb11d3
JS
796 POINT *cpoints = new POINT[n];
797 int i;
798 for (i = 0; i < n; i++)
799 {
800 cpoints[i].x = (int)(points[i].x + xoffset);
801 cpoints[i].y = (int)(points[i].y + yoffset);
a23fd0e1 802
7bcb11d3
JS
803 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
804 }
a23fd0e1 805 (void)Polyline(GetHdc(), cpoints, n);
7bcb11d3
JS
806 delete[] cpoints;
807 }
808 else
809 {
810 int i;
811 for (i = 0; i < n; i++)
812 CalcBoundingBox(points[i].x, points[i].y);
a23fd0e1
VZ
813
814 (void)Polyline(GetHdc(), (POINT*) points, n);
6a6c0a8b 815 }
2bda0e17
KB
816}
817
72cdf4c9 818void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
2bda0e17 819{
5adad466
JS
820#ifdef __WXMICROWIN__
821 if (!GetHDC()) return;
822#endif
d275c7eb 823
f6bcfd97 824 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
de2d2cdc 825
72cdf4c9
VZ
826 wxCoord x2 = x + width;
827 wxCoord y2 = y + height;
a23fd0e1 828
5456b916 829 if ((m_logicalFunction == wxCOPY) && (m_pen.GetStyle() == wxTRANSPARENT))
0bafad0c 830 {
7299b1b2 831 RECT rect;
5456b916
RR
832 rect.left = XLOG2DEV(x);
833 rect.top = YLOG2DEV(y);
834 rect.right = XLOG2DEV(x2);
7299b1b2
RD
835 rect.bottom = YLOG2DEV(y2);
836 (void)FillRect(GetHdc(), &rect, (HBRUSH)m_brush.GetResourceHandle() );
5456b916
RR
837 }
838 else
839 {
840 // Windows draws the filled rectangles without outline (i.e. drawn with a
841 // transparent pen) one pixel smaller in both directions and we want them
f6bcfd97 842 // to have the same size regardless of which pen is used - adjust
5456b916
RR
843
844