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