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