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