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