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