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