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