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