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