]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/dc.cpp
fixed pasting of Unicode strings
[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/msw/private.h" // needs to be before #include <commdlg.h>
45#include "wx/msw/missing.h" // needs to be before #include <commdlg.h>
46
47#include "wx/sysopt.h"
48#include "wx/dcprint.h"
49#include "wx/module.h"
50#include "wx/dynload.h"
51
52#ifdef wxHAVE_RAW_BITMAP
53#include "wx/rawbmp.h"
54#endif
55
56#include <string.h>
57#include <math.h>
58
59#if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
60 #include <commdlg.h>
61#endif
62
63#ifndef __WIN32__
64 #include <print.h>
65#endif
66
67#ifndef AC_SRC_ALPHA
68#define AC_SRC_ALPHA 1
69#endif
70
71/* Quaternary raster codes */
72#ifndef MAKEROP4
73#define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
74#endif
75
76// apparently with MicroWindows it is possible that HDC is 0 so we have to
77// check for this ourselves
78#ifdef __WXMICROWIN__
79 #define WXMICROWIN_CHECK_HDC if ( !GetHDC() ) return;
80 #define WXMICROWIN_CHECK_HDC_RET(x) if ( !GetHDC() ) return x;
81#else
82 #define WXMICROWIN_CHECK_HDC
83 #define WXMICROWIN_CHECK_HDC_RET(x)
84#endif
85
86IMPLEMENT_ABSTRACT_CLASS(wxDC, wxDCBase)
87
88// ---------------------------------------------------------------------------
89// constants
90// ---------------------------------------------------------------------------
91
92static const int VIEWPORT_EXTENT = 1000;
93
94static const int MM_POINTS = 9;
95static const int MM_METRIC = 10;
96
97// usually this is defined in math.h
98#ifndef M_PI
99 static const double M_PI = 3.14159265358979323846;
100#endif // M_PI
101
102// ROPs which don't have standard names (see "Ternary Raster Operations" in the
103// MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
104#define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
105
106// ----------------------------------------------------------------------------
107// macros for logical <-> device coords conversion
108// ----------------------------------------------------------------------------
109
110/*
111 We currently let Windows do all the translations itself so these macros are
112 not really needed (any more) but keep them to enhance readability of the
113 code by allowing to see where are the logical and where are the device
114 coordinates used.
115 */
116
117#ifdef __WXWINCE__
118 #define XLOG2DEV(x) ((x-m_logicalOriginX)*m_signX+m_deviceOriginX)
119 #define YLOG2DEV(y) ((y-m_logicalOriginY)*m_signY+m_deviceOriginY)
120 #define XDEV2LOG(x) ((x-m_deviceOriginX)*m_signX+m_logicalOriginX)
121 #define YDEV2LOG(y) ((y-m_deviceOriginY)*m_signY+m_logicalOriginY)
122#else
123 #define XLOG2DEV(x) (x)
124 #define YLOG2DEV(y) (y)
125 #define XDEV2LOG(x) (x)
126 #define YDEV2LOG(y) (y)
127#endif
128
129// ---------------------------------------------------------------------------
130// private functions
131// ---------------------------------------------------------------------------
132
133// convert degrees to radians
134static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
135
136// call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
137//
138// NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed
139// to pass it to this function but as we already have it at the point
140// of call anyhow we do
141//
142// return true if we could draw the bitmap in one way or the other, false
143// otherwise
144static bool AlphaBlt(HDC hdcDst,
145 int x, int y, int w, int h,
146 HDC hdcSrc,
147 const wxBitmap& bmpSrc);
148
149#ifdef wxHAVE_RAW_BITMAP
150// our (limited) AlphaBlend() replacement
151static void
152wxAlphaBlend(HDC hdcDst, int x, int y, int w, int h, const wxBitmap& bmp);
153#endif
154
155// ----------------------------------------------------------------------------
156// private classes
157// ----------------------------------------------------------------------------
158
159// instead of duplicating the same code which sets and then restores text
160// colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
161// encapsulate this in a small helper class
162
163// wxColourChanger: changes the text colours in the ctor if required and
164// restores them in the dtor
165class wxColourChanger
166{
167public:
168 wxColourChanger(wxDC& dc);
169 ~wxColourChanger();
170
171private:
172 wxDC& m_dc;
173
174 COLORREF m_colFgOld, m_colBgOld;
175
176 bool m_changed;
177
178 DECLARE_NO_COPY_CLASS(wxColourChanger)
179};
180
181// this class saves the old stretch blit mode during its life time
182class StretchBltModeChanger
183{
184public:
185 StretchBltModeChanger(HDC hdc, int mode)
186 : m_hdc(hdc)
187 {
188#ifndef __WXWINCE__
189 m_modeOld = ::SetStretchBltMode(m_hdc, mode);
190 if ( !m_modeOld )
191 wxLogLastError(_T("SetStretchBltMode"));
192#endif
193 }
194
195 ~StretchBltModeChanger()
196 {
197#ifndef __WXWINCE__
198 if ( !::SetStretchBltMode(m_hdc, m_modeOld) )
199 wxLogLastError(_T("SetStretchBltMode"));
200#endif
201 }
202
203private:
204 const HDC m_hdc;
205
206 int m_modeOld;
207
208 DECLARE_NO_COPY_CLASS(StretchBltModeChanger)
209};
210
211// ===========================================================================
212// implementation
213// ===========================================================================
214
215// ----------------------------------------------------------------------------
216// wxColourChanger
217// ----------------------------------------------------------------------------
218
219wxColourChanger::wxColourChanger(wxDC& dc) : m_dc(dc)
220{
221 const wxBrush& brush = dc.GetBrush();
222 if ( brush.Ok() && brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE )
223 {
224 HDC hdc = GetHdcOf(dc);
225 m_colFgOld = ::GetTextColor(hdc);
226 m_colBgOld = ::GetBkColor(hdc);
227
228 // note that Windows convention is opposite to wxWidgets one, this is
229 // why text colour becomes the background one and vice versa
230 const wxColour& colFg = dc.GetTextForeground();
231 if ( colFg.Ok() )
232 {
233 ::SetBkColor(hdc, colFg.GetPixel());
234 }
235
236 const wxColour& colBg = dc.GetTextBackground();
237 if ( colBg.Ok() )
238 {
239 ::SetTextColor(hdc, colBg.GetPixel());
240 }
241
242 SetBkMode(hdc,
243 dc.GetBackgroundMode() == wxTRANSPARENT ? TRANSPARENT
244 : OPAQUE);
245
246 // flag which telsl us to undo changes in the dtor
247 m_changed = true;
248 }
249 else
250 {
251 // nothing done, nothing to undo
252 m_changed = false;
253 }
254}
255
256wxColourChanger::~wxColourChanger()
257{
258 if ( m_changed )
259 {
260 // restore the colours we changed
261 HDC hdc = GetHdcOf(m_dc);
262
263 ::SetBkMode(hdc, TRANSPARENT);
264 ::SetTextColor(hdc, m_colFgOld);
265 ::SetBkColor(hdc, m_colBgOld);
266 }
267}
268
269// ---------------------------------------------------------------------------
270// wxDC
271// ---------------------------------------------------------------------------
272
273// Default constructor
274wxDC::wxDC()
275{
276 m_canvas = NULL;
277
278 m_oldBitmap = 0;
279 m_oldPen = 0;
280 m_oldBrush = 0;
281 m_oldFont = 0;
282#if wxUSE_PALETTE
283 m_oldPalette = 0;
284#endif // wxUSE_PALETTE
285
286 m_bOwnsDC = false;
287 m_hDC = 0;
288}
289
290wxDC::~wxDC()
291{
292 if ( m_hDC != 0 )
293 {
294 SelectOldObjects(m_hDC);
295
296 // if we own the HDC, we delete it, otherwise we just release it
297
298 if ( m_bOwnsDC )
299 {
300 ::DeleteDC(GetHdc());
301 }
302 else // we don't own our HDC
303 {
304 if (m_canvas)
305 {
306 ::ReleaseDC(GetHwndOf(m_canvas), GetHdc());
307 }
308 else
309 {
310 // Must have been a wxScreenDC
311 ::ReleaseDC((HWND) NULL, GetHdc());
312 }
313 }
314 }
315}
316
317// This will select current objects out of the DC,
318// which is what you have to do before deleting the
319// DC.
320void wxDC::SelectOldObjects(WXHDC dc)
321{
322 if (dc)
323 {
324 if (m_oldBitmap)
325 {
326 ::SelectObject((HDC) dc, (HBITMAP) m_oldBitmap);
327#ifdef __WXDEBUG__
328 if (m_selectedBitmap.Ok())
329 {
330 m_selectedBitmap.SetSelectedInto(NULL);
331 }
332#endif
333 }
334 m_oldBitmap = 0;
335 if (m_oldPen)
336 {
337 ::SelectObject((HDC) dc, (HPEN) m_oldPen);
338 }
339 m_oldPen = 0;
340 if (m_oldBrush)
341 {
342 ::SelectObject((HDC) dc, (HBRUSH) m_oldBrush);
343 }
344 m_oldBrush = 0;
345 if (m_oldFont)
346 {
347 ::SelectObject((HDC) dc, (HFONT) m_oldFont);
348 }
349 m_oldFont = 0;
350
351#if wxUSE_PALETTE
352 if (m_oldPalette)
353 {
354 ::SelectPalette((HDC) dc, (HPALETTE) m_oldPalette, FALSE);
355 }
356 m_oldPalette = 0;
357#endif // wxUSE_PALETTE
358 }
359
360 m_brush = wxNullBrush;
361 m_pen = wxNullPen;
362#if wxUSE_PALETTE
363 m_palette = wxNullPalette;
364#endif // wxUSE_PALETTE
365 m_font = wxNullFont;
366 m_backgroundBrush = wxNullBrush;
367 m_selectedBitmap = wxNullBitmap;
368}
369
370// ---------------------------------------------------------------------------
371// clipping
372// ---------------------------------------------------------------------------
373
374void wxDC::UpdateClipBox()
375{
376 WXMICROWIN_CHECK_HDC
377
378 RECT rect;
379 ::GetClipBox(GetHdc(), &rect);
380
381 m_clipX1 = (wxCoord) XDEV2LOG(rect.left);
382 m_clipY1 = (wxCoord) YDEV2LOG(rect.top);
383 m_clipX2 = (wxCoord) XDEV2LOG(rect.right);
384 m_clipY2 = (wxCoord) YDEV2LOG(rect.bottom);
385}
386
387void
388wxDC::DoGetClippingBox(wxCoord *x, wxCoord *y, wxCoord *w, wxCoord *h) const
389{
390 // check if we should try to retrieve the clipping region possibly not set
391 // by our SetClippingRegion() but preset by Windows:this can only happen
392 // when we're associated with an existing HDC usign SetHDC(), see there
393 if ( m_clipping && !m_clipX1 && !m_clipX2 )
394 {
395 wxDC *self = wxConstCast(this, wxDC);
396 self->UpdateClipBox();
397
398 if ( !m_clipX1 && !m_clipX2 )
399 self->m_clipping = false;
400 }
401
402 wxDCBase::DoGetClippingBox(x, y, w, h);
403}
404
405// common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
406void wxDC::SetClippingHrgn(WXHRGN hrgn)
407{
408 wxCHECK_RET( hrgn, wxT("invalid clipping region") );
409
410 WXMICROWIN_CHECK_HDC
411
412 // note that we combine the new clipping region with the existing one: this
413 // is compatible with what the other ports do and is the documented
414 // behaviour now (starting with 2.3.3)
415#if defined(__WXWINCE__)
416 RECT rectClip;
417 if ( !::GetClipBox(GetHdc(), &rectClip) )
418 return;
419
420 HRGN hrgnDest = ::CreateRectRgn(0, 0, 0, 0);
421 HRGN hrgnClipOld = ::CreateRectRgn(rectClip.left, rectClip.top,
422 rectClip.right, rectClip.bottom);
423
424 if ( ::CombineRgn(hrgnDest, hrgnClipOld, (HRGN)hrgn, RGN_AND) != ERROR )
425 {
426 ::SelectClipRgn(GetHdc(), hrgnDest);
427 }
428
429 ::DeleteObject(hrgnClipOld);
430 ::DeleteObject(hrgnDest);
431#else // !WinCE
432 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN)hrgn, RGN_AND) == ERROR )
433 {
434 wxLogLastError(_T("ExtSelectClipRgn"));
435
436 return;
437 }
438#endif // WinCE/!WinCE
439
440 m_clipping = true;
441
442 UpdateClipBox();
443}
444
445void wxDC::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
446{
447 // the region coords are always the device ones, so do the translation
448 // manually
449 //
450 // FIXME: possible +/-1 error here, to check!
451 HRGN hrgn = ::CreateRectRgn(LogicalToDeviceX(x),
452 LogicalToDeviceY(y),
453 LogicalToDeviceX(x + w),
454 LogicalToDeviceY(y + h));
455 if ( !hrgn )
456 {
457 wxLogLastError(_T("CreateRectRgn"));
458 }
459 else
460 {
461 SetClippingHrgn((WXHRGN)hrgn);
462
463 ::DeleteObject(hrgn);
464 }
465}
466
467void wxDC::DoSetClippingRegionAsRegion(const wxRegion& region)
468{
469 SetClippingHrgn(region.GetHRGN());
470}
471
472void wxDC::DestroyClippingRegion()
473{
474 WXMICROWIN_CHECK_HDC
475
476 if (m_clipping && m_hDC)
477 {
478 // TODO: this should restore the previous clipping region,
479 // so that OnPaint processing works correctly, and the update
480 // clipping region doesn't get destroyed after the first
481 // DestroyClippingRegion.
482 HRGN rgn = CreateRectRgn(0, 0, 32000, 32000);
483 ::SelectClipRgn(GetHdc(), rgn);
484 ::DeleteObject(rgn);
485 }
486
487 wxDCBase::DestroyClippingRegion();
488}
489
490// ---------------------------------------------------------------------------
491// query capabilities
492// ---------------------------------------------------------------------------
493
494bool wxDC::CanDrawBitmap() const
495{
496 return true;
497}
498
499bool wxDC::CanGetTextExtent() const
500{
501#ifdef __WXMICROWIN__
502 // TODO Extend MicroWindows' GetDeviceCaps function
503 return true;
504#else
505 // What sort of display is it?
506 int technology = ::GetDeviceCaps(GetHdc(), TECHNOLOGY);
507
508 return (technology == DT_RASDISPLAY) || (technology == DT_RASPRINTER);
509#endif
510}
511
512int wxDC::GetDepth() const
513{
514 WXMICROWIN_CHECK_HDC_RET(16)
515
516 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL);
517}
518
519// ---------------------------------------------------------------------------
520// drawing
521// ---------------------------------------------------------------------------
522
523void wxDC::Clear()
524{
525 WXMICROWIN_CHECK_HDC
526
527 RECT rect;
528 if ( m_canvas )
529 {
530 GetClientRect((HWND) m_canvas->GetHWND(), &rect);
531 }
532 else
533 {
534 // No, I think we should simply ignore this if printing on e.g.
535 // a printer DC.
536 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
537 if (!m_selectedBitmap.Ok())
538 return;
539
540 rect.left = 0; rect.top = 0;
541 rect.right = m_selectedBitmap.GetWidth();
542 rect.bottom = m_selectedBitmap.GetHeight();
543 }
544
545#ifndef __WXWINCE__
546 (void) ::SetMapMode(GetHdc(), MM_TEXT);
547#endif
548
549 DWORD colour = ::GetBkColor(GetHdc());
550 HBRUSH brush = ::CreateSolidBrush(colour);
551 ::FillRect(GetHdc(), &rect, brush);
552 ::DeleteObject(brush);
553
554 int width = DeviceToLogicalXRel(VIEWPORT_EXTENT)*m_signX,
555 height = DeviceToLogicalYRel(VIEWPORT_EXTENT)*m_signY;
556
557#ifndef __WXWINCE__
558 ::SetMapMode(GetHdc(), MM_ANISOTROPIC);
559
560 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT, VIEWPORT_EXTENT, NULL);
561 ::SetWindowExtEx(GetHdc(), width, height, NULL);
562 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL);
563 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX, (int)m_logicalOriginY, NULL);
564#endif
565}
566
567bool wxDC::DoFloodFill(wxCoord x, wxCoord y, const wxColour& col, int style)
568{
569#ifdef __WXWINCE__
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#endif
782 (void)Polygon(GetHdc(), cpoints, n);
783#ifndef __WXWINCE__
784 SetPolyFillMode(GetHdc(),prev);
785#endif
786 delete[] cpoints;
787 }
788 else
789 {
790 int i;
791 for (i = 0; i < n; i++)
792 CalcBoundingBox(points[i].x, points[i].y);
793
794#ifndef __WXWINCE__
795 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
796#endif
797 (void)Polygon(GetHdc(), (POINT*) points, n);
798#ifndef __WXWINCE__
799 SetPolyFillMode(GetHdc(),prev);
800#endif
801 }
802}
803
804void
805wxDC::DoDrawPolyPolygon(int n,
806 int count[],
807 wxPoint points[],
808 wxCoord xoffset,
809 wxCoord yoffset,
810 int fillStyle)
811{
812#ifdef __WXWINCE__
813 wxDCBase::DoDrawPolyPolygon(n, count, points, xoffset, yoffset, fillStyle);
814#else
815 WXMICROWIN_CHECK_HDC
816
817 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
818 int i, cnt;
819 for (i = cnt = 0; i < n; i++)
820 cnt += count[i];
821
822 // Do things less efficiently if we have offsets
823 if (xoffset != 0 || yoffset != 0)
824 {
825 POINT *cpoints = new POINT[cnt];
826 for (i = 0; i < cnt; i++)
827 {
828 cpoints[i].x = (int)(points[i].x + xoffset);
829 cpoints[i].y = (int)(points[i].y + yoffset);
830
831 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
832 }
833#ifndef __WXWINCE__
834 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
835#endif
836 (void)PolyPolygon(GetHdc(), cpoints, count, n);
837#ifndef __WXWINCE__
838 SetPolyFillMode(GetHdc(),prev);
839#endif
840 delete[] cpoints;
841 }
842 else
843 {
844 for (i = 0; i < cnt; i++)
845 CalcBoundingBox(points[i].x, points[i].y);
846
847#ifndef __WXWINCE__
848 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
849#endif
850 (void)PolyPolygon(GetHdc(), (POINT*) points, count, n);
851#ifndef __WXWINCE__
852 SetPolyFillMode(GetHdc(),prev);
853#endif
854 }
855#endif
856 // __WXWINCE__
857}
858
859void wxDC::DoDrawLines(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset)
860{
861 WXMICROWIN_CHECK_HDC
862
863 // Do things less efficiently if we have offsets
864 if (xoffset != 0 || yoffset != 0)
865 {
866 POINT *cpoints = new POINT[n];
867 int i;
868 for (i = 0; i < n; i++)
869 {
870 cpoints[i].x = (int)(points[i].x + xoffset);
871 cpoints[i].y = (int)(points[i].y + yoffset);
872
873 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
874 }
875 (void)Polyline(GetHdc(), cpoints, n);
876 delete[] cpoints;
877 }
878 else
879 {
880 int i;
881 for (i = 0; i < n; i++)
882 CalcBoundingBox(points[i].x, points[i].y);
883
884 (void)Polyline(GetHdc(), (POINT*) points, n);
885 }
886}
887
888void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
889{
890 WXMICROWIN_CHECK_HDC
891
892 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
893
894 wxCoord x2 = x + width;
895 wxCoord y2 = y + height;
896
897 if ((m_logicalFunction == wxCOPY) && (m_pen.GetStyle() == wxTRANSPARENT))
898 {
899 RECT rect;
900 rect.left = XLOG2DEV(x);
901 rect.top = YLOG2DEV(y);
902 rect.right = XLOG2DEV(x2);
903 rect.bottom = YLOG2DEV(y2);
904 (void)FillRect(GetHdc(), &rect, (HBRUSH)m_brush.GetResourceHandle() );
905 }
906 else
907 {
908 // Windows draws the filled rectangles without outline (i.e. drawn with a
909 // transparent pen) one pixel smaller in both directions and we want them
910 // to have the same size regardless of which pen is used - adjust
911
912