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