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