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