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