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