]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/dc.cpp
fixing some redrawing bugs overpainting foreign window's area under OS9, reintroduced...
[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#ifdef wxHAVE_RAW_BITMAP
49#include "wx/rawbmp.h"
50#endif
51
52#include <string.h>
53#include <math.h>
54
55#include "wx/msw/private.h" // needs to be before #include <commdlg.h>
56
57#if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
58 #include <commdlg.h>
59#endif
60
61#ifndef __WIN32__
62 #include <print.h>
63#endif
64
65#ifndef AC_SRC_ALPHA
66#define AC_SRC_ALPHA 1
67#endif
68
69/* Quaternary raster codes */
70#ifndef MAKEROP4
71#define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
72#endif
73
74IMPLEMENT_ABSTRACT_CLASS(wxDC, wxDCBase)
75
76// ---------------------------------------------------------------------------
77// constants
78// ---------------------------------------------------------------------------
79
80static const int VIEWPORT_EXTENT = 1000;
81
82static const int MM_POINTS = 9;
83static const int MM_METRIC = 10;
84
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
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
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
113// ---------------------------------------------------------------------------
114// private functions
115// ---------------------------------------------------------------------------
116
117// convert degrees to radians
118static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
119
120
121#ifdef wxHAVE_RAW_BITMAP
122// our (limited) AlphaBlend() replacement
123static void
124wxAlphaBlend(wxDC& dc, int x, int y, int w, int h, const wxBitmap& bmp);
125#endif
126
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
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
175// ===========================================================================
176// implementation
177// ===========================================================================
178
179// ----------------------------------------------------------------------------
180// wxColourChanger
181// ----------------------------------------------------------------------------
182
183wxColourChanger::wxColourChanger(wxDC& dc) : m_dc(dc)
184{
185 const wxBrush& brush = dc.GetBrush();
186 if ( brush.Ok() && brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE )
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
233// ---------------------------------------------------------------------------
234// wxDC
235// ---------------------------------------------------------------------------
236
237// Default constructor
238wxDC::wxDC()
239{
240 m_canvas = NULL;
241
242 m_oldBitmap = 0;
243 m_oldPen = 0;
244 m_oldBrush = 0;
245 m_oldFont = 0;
246#if wxUSE_PALETTE
247 m_oldPalette = 0;
248#endif // wxUSE_PALETTE
249
250 m_bOwnsDC = FALSE;
251 m_hDC = 0;
252}
253
254wxDC::~wxDC()
255{
256 if ( m_hDC != 0 )
257 {
258 SelectOldObjects(m_hDC);
259
260 // if we own the HDC, we delete it, otherwise we just release it
261
262 if ( m_bOwnsDC )
263 {
264 ::DeleteDC(GetHdc());
265 }
266 else // we don't own our HDC
267 {
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 }
277 }
278 }
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{
286 if (dc)
287 {
288 if (m_oldBitmap)
289 {
290 ::SelectObject((HDC) dc, (HBITMAP) m_oldBitmap);
291#ifdef __WXDEBUG__
292 if (m_selectedBitmap.Ok())
293 {
294 m_selectedBitmap.SetSelectedInto(NULL);
295 }
296#endif
297 }
298 m_oldBitmap = 0;
299 if (m_oldPen)
300 {
301 ::SelectObject((HDC) dc, (HPEN) m_oldPen);
302 }
303 m_oldPen = 0;
304 if (m_oldBrush)
305 {
306 ::SelectObject((HDC) dc, (HBRUSH) m_oldBrush);
307 }
308 m_oldBrush = 0;
309 if (m_oldFont)
310 {
311 ::SelectObject((HDC) dc, (HFONT) m_oldFont);
312 }
313 m_oldFont = 0;
314
315#if wxUSE_PALETTE
316 if (m_oldPalette)
317 {
318 ::SelectPalette((HDC) dc, (HPALETTE) m_oldPalette, FALSE);
319 }
320 m_oldPalette = 0;
321#endif // wxUSE_PALETTE
322 }
323
324 m_brush = wxNullBrush;
325 m_pen = wxNullPen;
326#if wxUSE_PALETTE
327 m_palette = wxNullPalette;
328#endif // wxUSE_PALETTE
329 m_font = wxNullFont;
330 m_backgroundBrush = wxNullBrush;
331 m_selectedBitmap = wxNullBitmap;
332}
333
334// ---------------------------------------------------------------------------
335// clipping
336// ---------------------------------------------------------------------------
337
338void wxDC::UpdateClipBox()
339{
340#ifdef __WXMICROWIN__
341 if (!GetHDC()) return;
342#endif
343
344 RECT rect;
345 ::GetClipBox(GetHdc(), &rect);
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);
351}
352
353// common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
354void wxDC::SetClippingHrgn(WXHRGN hrgn)
355{
356 wxCHECK_RET( hrgn, wxT("invalid clipping region") );
357
358#ifdef __WXMICROWIN__
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
389
390 m_clipping = TRUE;
391
392 UpdateClipBox();
393}
394
395void wxDC::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
396{
397 // the region coords are always the device ones, so do the translation
398 // manually
399 //
400 // FIXME: possible +/-1 error here, to check!
401 HRGN hrgn = ::CreateRectRgn(LogicalToDeviceX(x),
402 LogicalToDeviceY(y),
403 LogicalToDeviceX(x + w),
404 LogicalToDeviceY(y + h));
405 if ( !hrgn )
406 {
407 wxLogLastError(_T("CreateRectRgn"));
408 }
409 else
410 {
411 SetClippingHrgn((WXHRGN)hrgn);
412
413 ::DeleteObject(hrgn);
414 }
415}
416
417void wxDC::DoSetClippingRegionAsRegion(const wxRegion& region)
418{
419 SetClippingHrgn(region.GetHRGN());
420}
421
422void wxDC::DestroyClippingRegion()
423{
424#ifdef __WXMICROWIN__
425 if (!GetHDC()) return;
426#endif
427
428 if (m_clipping && m_hDC)
429 {
430 // TODO: this should restore the previous clipping region,
431 // so that OnPaint processing works correctly, and the update
432 // clipping region doesn't get destroyed after the first
433 // DestroyClippingRegion.
434 HRGN rgn = CreateRectRgn(0, 0, 32000, 32000);
435 ::SelectClipRgn(GetHdc(), rgn);
436 ::DeleteObject(rgn);
437 }
438
439 m_clipping = FALSE;
440}
441
442// ---------------------------------------------------------------------------
443// query capabilities
444// ---------------------------------------------------------------------------
445
446bool wxDC::CanDrawBitmap() const
447{
448 return TRUE;
449}
450
451bool wxDC::CanGetTextExtent() const
452{
453#ifdef __WXMICROWIN__
454 // TODO Extend MicroWindows' GetDeviceCaps function
455 return TRUE;
456#else
457 // What sort of display is it?
458 int technology = ::GetDeviceCaps(GetHdc(), TECHNOLOGY);
459
460 return (technology == DT_RASDISPLAY) || (technology == DT_RASPRINTER);
461#endif
462}
463
464int wxDC::GetDepth() const
465{
466#ifdef __WXMICROWIN__
467 if (!GetHDC()) return 16;
468#endif
469
470 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL);
471}
472
473// ---------------------------------------------------------------------------
474// drawing
475// ---------------------------------------------------------------------------
476
477void wxDC::Clear()
478{
479#ifdef __WXMICROWIN__
480 if (!GetHDC()) return;
481#endif
482
483 RECT rect;
484 if ( m_canvas )
485 {
486 GetClientRect((HWND) m_canvas->GetHWND(), &rect);
487 }
488 else
489 {
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;
495
496 rect.left = 0; rect.top = 0;
497 rect.right = m_selectedBitmap.GetWidth();
498 rect.bottom = m_selectedBitmap.GetHeight();
499 }
500
501 (void) ::SetMapMode(GetHdc(), MM_TEXT);
502
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;
510
511 ::SetMapMode(GetHdc(), MM_ANISOTROPIC);
512 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT, VIEWPORT_EXTENT, NULL);
513 ::SetWindowExtEx(GetHdc(), width, height, NULL);
514 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL);
515 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX, (int)m_logicalOriginY, NULL);
516}
517
518bool wxDC::DoFloodFill(wxCoord x, wxCoord y, const wxColour& col, int style)
519{
520#ifdef __WXMICROWIN__
521 if (!GetHDC()) return FALSE;
522#endif
523
524 bool success = (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x), YLOG2DEV(y),
525 col.GetPixel(),
526 style == wxFLOOD_SURFACE ? FLOODFILLSURFACE
527 : FLOODFILLBORDER) ) ;
528 if (!success)
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 //
542 wxLogLastError(wxT("ExtFloodFill"));
543 }
544
545 CalcBoundingBox(x, y);
546
547 return success;
548}
549
550bool wxDC::DoGetPixel(wxCoord x, wxCoord y, wxColour *col) const
551{
552#ifdef __WXMICROWIN__
553 if (!GetHDC()) return FALSE;
554#endif
555
556 wxCHECK_MSG( col, FALSE, _T("NULL colour parameter in wxDC::GetPixel") );
557
558 // get the color of the pixel
559 COLORREF pixelcolor = ::GetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y));
560
561 wxRGBToColour(*col, pixelcolor);
562
563 return TRUE;
564}
565
566void wxDC::DoCrossHair(wxCoord x, wxCoord y)
567{
568#ifdef __WXMICROWIN__
569 if (!GetHDC()) return;
570#endif
571
572 wxCoord x1 = x-VIEWPORT_EXTENT;
573 wxCoord y1 = y-VIEWPORT_EXTENT;
574 wxCoord x2 = x+VIEWPORT_EXTENT;
575 wxCoord y2 = y+VIEWPORT_EXTENT;
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
583 CalcBoundingBox(x1, y1);
584 CalcBoundingBox(x2, y2);
585}
586
587void wxDC::DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
588{
589#ifdef __WXMICROWIN__
590 if (!GetHDC()) return;
591#endif
592
593 (void)MoveToEx(GetHdc(), XLOG2DEV(x1), YLOG2DEV(y1), NULL);
594 (void)LineTo(GetHdc(), XLOG2DEV(x2), YLOG2DEV(y2));
595
596 CalcBoundingBox(x1, y1);
597 CalcBoundingBox(x2, y2);
598}
599
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)
605{
606#ifdef __WXMICROWIN__
607 if (!GetHDC()) return;
608#endif
609
610 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
611
612 double dx = xc - x1;
613 double dy = yc - y1;
614 double radius = (double)sqrt(dx*dx+dy*dy);
615 wxCoord r = (wxCoord)radius;
616
617 // treat the special case of full circle separately
618 if ( x1 == x2 && y1 == y2 )
619 {
620 DrawEllipse(xc - r, yc - r, 2*r, 2*r);
621 return;
622 }
623
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)));
631
632 wxCoord xxx1 = (wxCoord) (xxc-ray);
633 wxCoord yyy1 = (wxCoord) (yyc-ray);
634 wxCoord xxx2 = (wxCoord) (xxc+ray);
635 wxCoord yyy2 = (wxCoord) (yyc+ray);
636
637 if ( m_brush.Ok() && m_brush.GetStyle() != wxTRANSPARENT )
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!
644 Pie(GetHdc(),xxx1,yyy1,xxx2+1,yyy2+1, xx1,yy1,xx2,yy2);
645 }
646 else
647 {
648 Arc(GetHdc(),xxx1,yyy1,xxx2,yyy2, xx1,yy1,xx2,yy2);
649 }
650
651 CalcBoundingBox(xc - r, yc - r);
652 CalcBoundingBox(xc + r, yc + r);
653}
654
655void wxDC::DoDrawCheckMark(wxCoord x1, wxCoord y1,
656 wxCoord width, wxCoord height)
657{
658#ifdef __WXMICROWIN__
659 if (!GetHDC()) return;
660#endif
661
662 wxCoord x2 = x1 + width,
663 y2 = y1 + height;
664
665#if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__)
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);
677 HPEN hPenOld = (HPEN)::SelectObject(GetHdc(), blackPen);
678 HPEN hBrushOld = (HPEN)::SelectObject(GetHdc(), whiteBrush);
679 ::SetROP2(GetHdc(), R2_COPYPEN);
680 Rectangle(GetHdc(), x1, y1, x2, y2);
681 MoveToEx(GetHdc(), x1, y1, NULL);
682 LineTo(GetHdc(), x2, y2);
683 MoveToEx(GetHdc(), x2, y1, NULL);
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
694void wxDC::DoDrawPoint(wxCoord x, wxCoord y)
695{
696#ifdef __WXMICROWIN__
697 if (!GetHDC()) return;
698#endif
699
700 COLORREF color = 0x00ffffff;
701 if (m_pen.Ok())
702 {
703 color = m_pen.GetColour().GetPixel();
704 }
705
706 SetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), color);
707
708 CalcBoundingBox(x, y);
709}
710
711void wxDC::DoDrawPolygon(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset,int fillStyle)
712{
713#ifdef __WXMICROWIN__
714 if (!GetHDC()) return;
715#endif
716
717 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
718
719 // Do things less efficiently if we have offsets
720 if (xoffset != 0 || yoffset != 0)
721 {
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);
728
729 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
730 }
731 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
732 (void)Polygon(GetHdc(), cpoints, n);
733 SetPolyFillMode(GetHdc(),prev);
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);
741
742 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
743 (void)Polygon(GetHdc(), (POINT*) points, n);
744 SetPolyFillMode(GetHdc(),prev);
745 }
746}
747
748void wxDC::DoDrawLines(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset)
749{
750#ifdef __WXMICROWIN__
751 if (!GetHDC()) return;
752#endif
753
754 // Do things less efficiently if we have offsets
755 if (xoffset != 0 || yoffset != 0)
756 {
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);
763
764 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
765 }
766 (void)Polyline(GetHdc(), cpoints, n);
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);
774
775 (void)Polyline(GetHdc(), (POINT*) points, n);
776 }
777}
778
779void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
780{
781#ifdef __WXMICROWIN__
782 if (!GetHDC()) return;
783#endif
784
785 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
786
787 wxCoord x2 = x + width;
788 wxCoord y2 = y + height;
789
790 if ((m_logicalFunction == wxCOPY) && (m_pen.GetStyle() == wxTRANSPARENT))
791 {
792 RECT rect;
793 rect.left = XLOG2DEV(x);
794 rect.top = YLOG2DEV(y);
795 rect.right = XLOG2DEV(x2);
796 rect.bottom = YLOG2DEV(y2);
797 (void)FillRect(GetHdc(), &rect, (HBRUSH)m_brush.GetResourceHandle() );
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
803 // to have the same size regardless of which pen is used - adjust
804
805