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