]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/dc.cpp
[ 1502016 ] wxImage::ConvertToGreyscale should retain alpha channel.
[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 #include "wx/dcprint.h"
39#endif
40
41#include "wx/sysopt.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 // cases when we don't have DrawFrameControl()
728#if defined(__SYMANTEC__) || defined(__WXMICROWIN__)
729 return wxDCBase::DoDrawCheckMark(x1, y1, width, height);
730#else // normal case
731 wxCoord x2 = x1 + width,
732 y2 = y1 + height;
733
734 RECT rect;
735 rect.left = x1;
736 rect.top = y1;
737 rect.right = x2;
738 rect.bottom = y2;
739
740#ifdef __WXWINCE__
741 DrawFrameControl(GetHdc(), &rect, DFC_BUTTON, DFCS_BUTTONCHECK);
742#else
743 DrawFrameControl(GetHdc(), &rect, DFC_MENU, DFCS_MENUCHECK);
744#endif
745
746 CalcBoundingBox(x1, y1);
747 CalcBoundingBox(x2, y2);
748#endif // Microwin/Normal
749}
750
751void wxDC::DoDrawPoint(wxCoord x, wxCoord y)
752{
753 WXMICROWIN_CHECK_HDC
754
755 COLORREF color = 0x00ffffff;
756 if (m_pen.Ok())
757 {
758 color = m_pen.GetColour().GetPixel();
759 }
760
761 SetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), color);
762
763 CalcBoundingBox(x, y);
764}
765
766void wxDC::DoDrawPolygon(int n,
767 wxPoint points[],
768 wxCoord xoffset,
769 wxCoord yoffset,
770 int WXUNUSED_IN_WINCE(fillStyle))
771{
772 WXMICROWIN_CHECK_HDC
773
774 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
775
776 // Do things less efficiently if we have offsets
777 if (xoffset != 0 || yoffset != 0)
778 {
779 POINT *cpoints = new POINT[n];
780 int i;
781 for (i = 0; i < n; i++)
782 {
783 cpoints[i].x = (int)(points[i].x + xoffset);
784 cpoints[i].y = (int)(points[i].y + yoffset);
785
786 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
787 }
788#ifndef __WXWINCE__
789 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
790#endif
791 (void)Polygon(GetHdc(), cpoints, n);
792#ifndef __WXWINCE__
793 SetPolyFillMode(GetHdc(),prev);
794#endif
795 delete[] cpoints;
796 }
797 else
798 {
799 int i;
800 for (i = 0; i < n; i++)
801 CalcBoundingBox(points[i].x, points[i].y);
802
803#ifndef __WXWINCE__
804 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
805#endif
806 (void)Polygon(GetHdc(), (POINT*) points, n);
807#ifndef __WXWINCE__
808 SetPolyFillMode(GetHdc(),prev);
809#endif
810 }
811}
812
813void
814wxDC::DoDrawPolyPolygon(int n,
815 int count[],
816 wxPoint points[],
817 wxCoord xoffset,
818 wxCoord yoffset,
819 int fillStyle)
820{
821#ifdef __WXWINCE__
822 wxDCBase::DoDrawPolyPolygon(n, count, points, xoffset, yoffset, fillStyle);
823#else
824 WXMICROWIN_CHECK_HDC
825
826 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
827 int i, cnt;
828 for (i = cnt = 0; i < n; i++)
829 cnt += count[i];
830
831 // Do things less efficiently if we have offsets
832 if (xoffset != 0 || yoffset != 0)
833 {
834 POINT *cpoints = new POINT[cnt];
835 for (i = 0; i < cnt; i++)
836 {
837 cpoints[i].x = (int)(points[i].x + xoffset);
838 cpoints[i].y = (int)(points[i].y + yoffset);
839
840 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
841 }
842#ifndef __WXWINCE__
843 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
844#endif
845 (void)PolyPolygon(GetHdc(), cpoints, count, n);
846#ifndef __WXWINCE__
847 SetPolyFillMode(GetHdc(),prev);
848#endif
849 delete[] cpoints;
850 }
851 else
852 {
853 for (i = 0; i < cnt; i++)
854 CalcBoundingBox(points[i].x, points[i].y);
855
856#ifndef __WXWINCE__
857 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
858#endif
859 (void)PolyPolygon(GetHdc(), (POINT*) points, count, n);
860#ifndef __WXWINCE__
861 SetPolyFillMode(GetHdc(),prev);
862#endif
863 }
864#endif
865 // __WXWINCE__
866}
867
868void wxDC::DoDrawLines(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset)
869{
870 WXMICROWIN_CHECK_HDC
871
872 // Do things less efficiently if we have offsets
873 if (xoffset != 0 || yoffset != 0)
874 {
875 POINT *cpoints = new POINT[n];
876 int i;
877 for (i = 0; i < n; i++)
878 {
879 cpoints[i].x = (int)(points[i].x + xoffset);
880 cpoints[i].y = (int)(points[i].y + yoffset);
881
882 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
883 }
884 (void)Polyline(GetHdc(), cpoints, n);
885 delete[] cpoints;
886 }
887 else
888 {
889 int i;
890 for (i = 0; i < n; i++)
891 CalcBoundingBox(points[i].x, points[i].y);
892
893 (void)Polyline(GetHdc(), (POINT*) points, n);
894 }
895}
896
897void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
898{
899 WXMICROWIN_CHECK_HDC
900
901 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
902
903 wxCoord x2 = x + width;
904 wxCoord y2 = y + height;
905
906 if ((m_logicalFunction == wxCOPY) && (m_pen.GetStyle() == wxTRANSPARENT))
907 {
908 RECT rect;
909 rect.left = XLOG2DEV(x);
910 rect.top = YLOG2DEV(y);
911 rect.right = XLOG2DEV(x2);
912 rect.bottom = YLOG2DEV(y2);
913 (void)FillRect(GetHdc(), &rect, (HBRUSH)m_brush.GetResourceHandle() );
914 }
915 else
916 {
917 // Windows draws the filled rectangles without outline (i.e. drawn with a
918 // transparent pen) one pixel smaller in both directions and we want them
919 // to have the same size regardless of which pen is used - adjust
920
921