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