]> git.saurik.com Git - wxWidgets.git/blame - src/msw/dc.cpp
reset m_selectionOld when the selection is programatically changed
[wxWidgets.git] / src / msw / dc.cpp
CommitLineData
2bda0e17
KB
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$
6c9a19aa 8// Copyright: (c) Julian Smart
65571936 9// Licence: wxWindows licence
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
a23fd0e1
VZ
12// ===========================================================================
13// declarations
14// ===========================================================================
15
16// ---------------------------------------------------------------------------
17// headers
18// ---------------------------------------------------------------------------
19
14f355c2 20#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
a23fd0e1 21 #pragma implementation "dc.h"
2bda0e17
KB
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
a23fd0e1 28 #pragma hdrstop
2bda0e17
KB
29#endif
30
31#ifndef WX_PRECOMP
fb6724f1 32 #include "wx/image.h"
4286a5b5 33 #include "wx/window.h"
a23fd0e1
VZ
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"
0c589ad0 40 #include "wx/log.h"
4286a5b5 41 #include "wx/icon.h"
2bda0e17
KB
42#endif
43
42d11c8e 44#include "wx/msw/private.h" // needs to be before #include <commdlg.h>
d61c1a6f 45#include "wx/msw/missing.h" // needs to be before #include <commdlg.h>
42d11c8e 46
0cbff120 47#include "wx/sysopt.h"
2bda0e17 48#include "wx/dcprint.h"
aef94d68 49#include "wx/module.h"
acf8e3d2 50#include "wx/dynload.h"
1e3c12d7
CE
51
52#ifdef wxHAVE_RAW_BITMAP
878711c0 53#include "wx/rawbmp.h"
1e3c12d7 54#endif
2bda0e17
KB
55
56#include <string.h>
2bda0e17 57
c67d6888 58#if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
a23fd0e1 59 #include <commdlg.h>
2bda0e17
KB
60#endif
61
62#ifndef __WIN32__
a23fd0e1 63 #include <print.h>
2bda0e17
KB
64#endif
65
878711c0
VZ
66#ifndef AC_SRC_ALPHA
67#define AC_SRC_ALPHA 1
68#endif
69
3bce6687
JS
70/* Quaternary raster codes */
71#ifndef MAKEROP4
72#define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
73#endif
74
82a306b7
VZ
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
5acb7b3e 85IMPLEMENT_ABSTRACT_CLASS(wxDC, wxDCBase)
2bda0e17 86
a23fd0e1
VZ
87// ---------------------------------------------------------------------------
88// constants
89// ---------------------------------------------------------------------------
90
42e69d6b
VZ
91static const int VIEWPORT_EXTENT = 1000;
92
93static const int MM_POINTS = 9;
94static const int MM_METRIC = 10;
a23fd0e1 95
4aff28fc
VZ
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
1e2081a1
VZ
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
1a4b50d2
RR
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
1e2081a1 122
4314ec48
VZ
123// ---------------------------------------------------------------------------
124// private functions
125// ---------------------------------------------------------------------------
126
127// convert degrees to radians
128static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
129
275a63e3
VZ
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);
1e3c12d7
CE
142
143#ifdef wxHAVE_RAW_BITMAP
878711c0
VZ
144// our (limited) AlphaBlend() replacement
145static void
275a63e3 146wxAlphaBlend(HDC hdcDst, int x, int y, int w, int h, const wxBitmap& bmp);
1e3c12d7 147#endif
878711c0 148
f6bcfd97
BP
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;
2eb10e2a
VZ
171
172 DECLARE_NO_COPY_CLASS(wxColourChanger)
f6bcfd97
BP
173};
174
f178ab7e
VZ
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 {
4676948b 182#ifndef __WXWINCE__
f178ab7e
VZ
183 m_modeOld = ::SetStretchBltMode(m_hdc, mode);
184 if ( !m_modeOld )
185 wxLogLastError(_T("SetStretchBltMode"));
17a6a2e0
WS
186#else
187 wxUnusedVar(mode);
4676948b 188#endif
f178ab7e
VZ
189 }
190
191 ~StretchBltModeChanger()
192 {
4676948b 193#ifndef __WXWINCE__
f178ab7e
VZ
194 if ( !::SetStretchBltMode(m_hdc, m_modeOld) )
195 wxLogLastError(_T("SetStretchBltMode"));
4676948b 196#endif
f178ab7e
VZ
197 }
198
199private:
200 const HDC m_hdc;
201
202 int m_modeOld;
2eb10e2a
VZ
203
204 DECLARE_NO_COPY_CLASS(StretchBltModeChanger)
f178ab7e
VZ
205};
206
a23fd0e1
VZ
207// ===========================================================================
208// implementation
209// ===========================================================================
210
f6bcfd97
BP
211// ----------------------------------------------------------------------------
212// wxColourChanger
213// ----------------------------------------------------------------------------
214
215wxColourChanger::wxColourChanger(wxDC& dc) : m_dc(dc)
216{
cafbad8f
VZ
217 const wxBrush& brush = dc.GetBrush();
218 if ( brush.Ok() && brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE )
f6bcfd97
BP
219 {
220 HDC hdc = GetHdcOf(dc);
221 m_colFgOld = ::GetTextColor(hdc);
222 m_colBgOld = ::GetBkColor(hdc);
223
77ffb593 224 // note that Windows convention is opposite to wxWidgets one, this is
f6bcfd97
BP
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
beb966c5 243 m_changed = true;
f6bcfd97
BP
244 }
245 else
246 {
247 // nothing done, nothing to undo
beb966c5 248 m_changed = false;
f6bcfd97
BP
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
a23fd0e1
VZ
265// ---------------------------------------------------------------------------
266// wxDC
267// ---------------------------------------------------------------------------
2bda0e17
KB
268
269// Default constructor
a23fd0e1 270wxDC::wxDC()
2bda0e17 271{
7bcb11d3 272 m_canvas = NULL;
a23fd0e1 273
7bcb11d3
JS
274 m_oldBitmap = 0;
275 m_oldPen = 0;
276 m_oldBrush = 0;
277 m_oldFont = 0;
d275c7eb 278#if wxUSE_PALETTE
7bcb11d3 279 m_oldPalette = 0;
d275c7eb 280#endif // wxUSE_PALETTE
a23fd0e1 281
beb966c5 282 m_bOwnsDC = false;
7bcb11d3 283 m_hDC = 0;
2bda0e17
KB
284}
285
a23fd0e1 286wxDC::~wxDC()
2bda0e17 287{
7ba4fbeb
VZ
288 if ( m_hDC != 0 )
289 {
7bcb11d3 290 SelectOldObjects(m_hDC);
7ba4fbeb
VZ
291
292 // if we own the HDC, we delete it, otherwise we just release it
293
294 if ( m_bOwnsDC )
295 {
296 ::DeleteDC(GetHdc());
7bcb11d3 297 }
7ba4fbeb
VZ
298 else // we don't own our HDC
299 {
db400410
JS
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 }
7ba4fbeb
VZ
309 }
310 }
2bda0e17
KB
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{
7bcb11d3 318 if (dc)
2bda0e17 319 {
7bcb11d3
JS
320 if (m_oldBitmap)
321 {
322 ::SelectObject((HDC) dc, (HBITMAP) m_oldBitmap);
3ca22d5e 323#ifdef __WXDEBUG__
7bcb11d3
JS
324 if (m_selectedBitmap.Ok())
325 {
326 m_selectedBitmap.SetSelectedInto(NULL);
327 }
3ca22d5e 328#endif
7bcb11d3 329 }
a23fd0e1 330 m_oldBitmap = 0;
7bcb11d3
JS
331 if (m_oldPen)
332 {
333 ::SelectObject((HDC) dc, (HPEN) m_oldPen);
334 }
a23fd0e1 335 m_oldPen = 0;
7bcb11d3
JS
336 if (m_oldBrush)
337 {
338 ::SelectObject((HDC) dc, (HBRUSH) m_oldBrush);
339 }
a23fd0e1 340 m_oldBrush = 0;
7bcb11d3
JS
341 if (m_oldFont)
342 {
343 ::SelectObject((HDC) dc, (HFONT) m_oldFont);
344 }
a23fd0e1 345 m_oldFont = 0;
d275c7eb
VZ
346
347#if wxUSE_PALETTE
7bcb11d3
JS
348 if (m_oldPalette)
349 {
19193a2c 350 ::SelectPalette((HDC) dc, (HPALETTE) m_oldPalette, FALSE);
7bcb11d3 351 }
a23fd0e1 352 m_oldPalette = 0;
d275c7eb 353#endif // wxUSE_PALETTE
2bda0e17 354 }
a23fd0e1
VZ
355
356 m_brush = wxNullBrush;
7bcb11d3 357 m_pen = wxNullPen;
d275c7eb 358#if wxUSE_PALETTE
7bcb11d3 359 m_palette = wxNullPalette;
d275c7eb 360#endif // wxUSE_PALETTE
7bcb11d3
JS
361 m_font = wxNullFont;
362 m_backgroundBrush = wxNullBrush;
363 m_selectedBitmap = wxNullBitmap;
2bda0e17
KB
364}
365
a23fd0e1
VZ
366// ---------------------------------------------------------------------------
367// clipping
368// ---------------------------------------------------------------------------
369
1e6feb95
VZ
370void wxDC::UpdateClipBox()
371{
82a306b7 372 WXMICROWIN_CHECK_HDC
d275c7eb 373
1e6feb95 374 RECT rect;
5230934a 375 ::GetClipBox(GetHdc(), &rect);
1e6feb95
VZ
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);
f547e9bb
RL
381}
382
2e76da54
VZ
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 {
395b914e
VZ
391 wxDC *self = wxConstCast(this, wxDC);
392 self->UpdateClipBox();
2e76da54
VZ
393
394 if ( !m_clipX1 && !m_clipX2 )
395b914e 395 self->m_clipping = false;
2e76da54
VZ
396 }
397
f67fe9a4 398 wxDCBase::DoGetClippingBox(x, y, w, h);
2e76da54
VZ
399}
400
5230934a
VZ
401// common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
402void wxDC::SetClippingHrgn(WXHRGN hrgn)
2bda0e17 403{
5230934a
VZ
404 wxCHECK_RET( hrgn, wxT("invalid clipping region") );
405
82a306b7 406 WXMICROWIN_CHECK_HDC
5230934a
VZ
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)
3a5bcc4d 411#if defined(__WXWINCE__)
5230934a
VZ
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);
3a5bcc4d 427#else // !WinCE
5230934a
VZ
428 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN)hrgn, RGN_AND) == ERROR )
429 {
430 wxLogLastError(_T("ExtSelectClipRgn"));
431
432 return;
433 }
3a5bcc4d 434#endif // WinCE/!WinCE
d275c7eb 435
beb966c5 436 m_clipping = true;
40a89076 437
5230934a
VZ
438 UpdateClipBox();
439}
440
441void wxDC::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
442{
c4218a74
VZ
443 // the region coords are always the device ones, so do the translation
444 // manually
1e6feb95
VZ
445 //
446 // FIXME: possible +/-1 error here, to check!
c4218a74
VZ
447 HRGN hrgn = ::CreateRectRgn(LogicalToDeviceX(x),
448 LogicalToDeviceY(y),
449 LogicalToDeviceX(x + w),
450 LogicalToDeviceY(y + h));
40a89076
VZ
451 if ( !hrgn )
452 {
453 wxLogLastError(_T("CreateRectRgn"));
454 }
455 else
456 {
5230934a 457 SetClippingHrgn((WXHRGN)hrgn);
40a89076 458
5230934a 459 ::DeleteObject(hrgn);
40a89076 460 }
2bda0e17
KB
461}
462
a23fd0e1 463void wxDC::DoSetClippingRegionAsRegion(const wxRegion& region)
a724d789 464{
5230934a 465 SetClippingHrgn(region.GetHRGN());
2bda0e17
KB
466}
467
a23fd0e1 468void wxDC::DestroyClippingRegion()
2bda0e17 469{
82a306b7 470 WXMICROWIN_CHECK_HDC
d275c7eb 471
7bcb11d3
JS
472 if (m_clipping && m_hDC)
473 {
474 // TODO: this should restore the previous clipping region,
5230934a
VZ
475 // so that OnPaint processing works correctly, and the update
476 // clipping region doesn't get destroyed after the first
477 // DestroyClippingRegion.
7bcb11d3 478 HRGN rgn = CreateRectRgn(0, 0, 32000, 32000);
5230934a
VZ
479 ::SelectClipRgn(GetHdc(), rgn);
480 ::DeleteObject(rgn);
7bcb11d3 481 }
1e6feb95 482
2e76da54 483 wxDCBase::DestroyClippingRegion();
2bda0e17
KB
484}
485
a23fd0e1
VZ
486// ---------------------------------------------------------------------------
487// query capabilities
488// ---------------------------------------------------------------------------
489
490bool wxDC::CanDrawBitmap() const
2bda0e17 491{
beb966c5 492 return true;
2bda0e17
KB
493}
494
a23fd0e1 495bool wxDC::CanGetTextExtent() const
2bda0e17 496{
04ef50df
JS
497#ifdef __WXMICROWIN__
498 // TODO Extend MicroWindows' GetDeviceCaps function
beb966c5 499 return true;
04ef50df 500#else
7bcb11d3 501 // What sort of display is it?
a23fd0e1
VZ
502 int technology = ::GetDeviceCaps(GetHdc(), TECHNOLOGY);
503
504 return (technology == DT_RASDISPLAY) || (technology == DT_RASPRINTER);
04ef50df 505#endif
2bda0e17
KB
506}
507
a23fd0e1 508int wxDC::GetDepth() const
2bda0e17 509{
82a306b7 510 WXMICROWIN_CHECK_HDC_RET(16)
d275c7eb 511
a23fd0e1 512 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL);
2bda0e17
KB
513}
514
a23fd0e1
VZ
515// ---------------------------------------------------------------------------
516// drawing
517// ---------------------------------------------------------------------------
518
519void wxDC::Clear()
2bda0e17 520{
82a306b7 521 WXMICROWIN_CHECK_HDC
d275c7eb 522
7bcb11d3 523 RECT rect;
2506aab6
VZ
524 if ( m_canvas )
525 {
7bcb11d3 526 GetClientRect((HWND) m_canvas->GetHWND(), &rect);
2506aab6
VZ
527 }
528 else
7bcb11d3 529 {
eaeb6a3c
JS
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;
2506aab6 535
7bcb11d3
JS
536 rect.left = 0; rect.top = 0;
537 rect.right = m_selectedBitmap.GetWidth();
538 rect.bottom = m_selectedBitmap.GetHeight();
539 }
2506aab6 540
4676948b 541#ifndef __WXWINCE__
a23fd0e1 542 (void) ::SetMapMode(GetHdc(), MM_TEXT);
4676948b 543#endif
a23fd0e1 544
1e2081a1
VZ
545 DWORD colour = ::GetBkColor(GetHdc());
546 HBRUSH brush = ::CreateSolidBrush(colour);
547 ::FillRect(GetHdc(), &rect, brush);
548 ::DeleteObject(brush);
549
35bbb0c6 550#ifndef __WXWINCE__
1e2081a1
VZ
551 int width = DeviceToLogicalXRel(VIEWPORT_EXTENT)*m_signX,
552 height = DeviceToLogicalYRel(VIEWPORT_EXTENT)*m_signY;
a23fd0e1
VZ
553
554 ::SetMapMode(GetHdc(), MM_ANISOTROPIC);
4676948b 555
a23fd0e1 556 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT, VIEWPORT_EXTENT, NULL);
1e2081a1 557 ::SetWindowExtEx(GetHdc(), width, height, NULL);
a23fd0e1
VZ
558 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL);
559 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX, (int)m_logicalOriginY, NULL);
4676948b 560#endif
a23fd0e1
VZ
561}
562
387ebd3e 563bool wxDC::DoFloodFill(wxCoord x, wxCoord y, const wxColour& col, int style)
a23fd0e1 564{
4676948b 565#ifdef __WXWINCE__
17a6a2e0
WS
566 wxUnusedVar(x);
567 wxUnusedVar(y);
568 wxUnusedVar(col);
569 wxUnusedVar(style);
beb966c5 570 return false;
4676948b
JS
571#else
572
beb966c5 573 WXMICROWIN_CHECK_HDC_RET(false)
d275c7eb 574
387ebd3e 575 bool success = (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x), YLOG2DEV(y),
0bafad0c
VZ
576 col.GetPixel(),
577 style == wxFLOOD_SURFACE ? FLOODFILLSURFACE
387ebd3e
JS
578 : FLOODFILLBORDER) ) ;
579 if (!success)
0bafad0c
VZ
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 //
f6bcfd97 593 wxLogLastError(wxT("ExtFloodFill"));
0bafad0c 594 }
a23fd0e1 595
7bcb11d3 596 CalcBoundingBox(x, y);
419430a0 597
387ebd3e 598 return success;
4676948b 599#endif
2bda0e17
KB
600}
601
72cdf4c9 602bool wxDC::DoGetPixel(wxCoord x, wxCoord y, wxColour *col) const
2bda0e17 603{
beb966c5 604 WXMICROWIN_CHECK_HDC_RET(false)
d275c7eb 605
beb966c5 606 wxCHECK_MSG( col, false, _T("NULL colour parameter in wxDC::GetPixel") );
f6bcfd97 607
7bcb11d3 608 // get the color of the pixel
a23fd0e1 609 COLORREF pixelcolor = ::GetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y));
0bafad0c 610
f6bcfd97 611 wxRGBToColour(*col, pixelcolor);
dc1efb1d 612
beb966c5 613 return true;
2bda0e17
KB
614}
615
72cdf4c9 616void wxDC::DoCrossHair(wxCoord x, wxCoord y)
a23fd0e1 617{
82a306b7 618 WXMICROWIN_CHECK_HDC
d275c7eb 619
72cdf4c9
VZ
620 wxCoord x1 = x-VIEWPORT_EXTENT;
621 wxCoord y1 = y-VIEWPORT_EXTENT;
622 wxCoord x2 = x+VIEWPORT_EXTENT;
623 wxCoord y2 = y+VIEWPORT_EXTENT;
a23fd0e1 624
4676948b
JS
625 wxDrawLine(GetHdc(), XLOG2DEV(x1), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y));
626 wxDrawLine(GetHdc(), XLOG2DEV(x), YLOG2DEV(y1), XLOG2DEV(x), YLOG2DEV(y2));
a23fd0e1 627
7bcb11d3
JS
628 CalcBoundingBox(x1, y1);
629 CalcBoundingBox(x2, y2);
2bda0e17
KB
630}
631
72cdf4c9 632void wxDC::DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
2bda0e17 633{
82a306b7 634 WXMICROWIN_CHECK_HDC
d275c7eb 635
4676948b 636 wxDrawLine(GetHdc(), XLOG2DEV(x1), YLOG2DEV(y1), XLOG2DEV(x2), YLOG2DEV(y2));
a23fd0e1 637
7bcb11d3
JS
638 CalcBoundingBox(x1, y1);
639 CalcBoundingBox(x2, y2);
2bda0e17
KB
640}
641
f6bcfd97
BP
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)
2bda0e17 647{
4676948b 648#ifdef __WXWINCE__
4f10962b
JS
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 );
4676948b
JS
655#else
656
82a306b7 657 WXMICROWIN_CHECK_HDC
d275c7eb 658
f6bcfd97 659 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
2d8a5cb1 660
f6bcfd97
BP
661 double dx = xc - x1;
662 double dy = yc - y1;
663 double radius = (double)sqrt(dx*dx+dy*dy);
664 wxCoord r = (wxCoord)radius;
2d8a5cb1 665
f6bcfd97
BP
666 // treat the special case of full circle separately
667 if ( x1 == x2 && y1 == y2 )
7bcb11d3 668 {
f6bcfd97 669 DrawEllipse(xc - r, yc - r, 2*r, 2*r);
a23fd0e1 670 return;
7bcb11d3 671 }
a23fd0e1 672
72cdf4c9
VZ
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)));
a23fd0e1 680
72cdf4c9
VZ
681 wxCoord xxx1 = (wxCoord) (xxc-ray);
682 wxCoord yyy1 = (wxCoord) (yyc-ray);
683 wxCoord xxx2 = (wxCoord) (xxc+ray);
684 wxCoord yyy2 = (wxCoord) (yyc+ray);
f6bcfd97
BP
685
686 if ( m_brush.Ok() && m_brush.GetStyle() != wxTRANSPARENT )
7bcb11d3
JS
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!
f6bcfd97 693 Pie(GetHdc(),xxx1,yyy1,xxx2+1,yyy2+1, xx1,yy1,xx2,yy2);
7bcb11d3
JS
694 }
695 else
2d8a5cb1 696 {
f6bcfd97 697 Arc(GetHdc(),xxx1,yyy1,xxx2,yyy2, xx1,yy1,xx2,yy2);
2d8a5cb1 698 }
f6bcfd97
BP
699
700 CalcBoundingBox(xc - r, yc - r);
701 CalcBoundingBox(xc + r, yc + r);
4676948b 702#endif
2bda0e17
KB
703}
704
cd9da200
VZ
705void wxDC::DoDrawCheckMark(wxCoord x1, wxCoord y1,
706 wxCoord width, wxCoord height)
707{
82a306b7 708 WXMICROWIN_CHECK_HDC
d275c7eb 709
cd9da200
VZ
710 wxCoord x2 = x1 + width,
711 y2 = y1 + height;
712
1e3c12d7 713#if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__)
cd9da200
VZ
714 RECT rect;
715 rect.left = x1;
716 rect.top = y1;
717 rect.right = x2;
718 rect.bottom = y2;
719
4676948b
JS
720#ifdef __WXWINCE__
721 DrawFrameControl(GetHdc(), &rect, DFC_BUTTON, DFCS_BUTTONCHECK);
722#else
cd9da200 723 DrawFrameControl(GetHdc(), &rect, DFC_MENU, DFCS_MENUCHECK);
4676948b 724#endif
3a5bcc4d
VZ
725#else // Symantec-MicroWin
726 // draw a cross
cd9da200
VZ
727 HPEN blackPen = ::CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
728 HPEN whiteBrush = (HPEN)::GetStockObject(WHITE_BRUSH);
e06b9569
JS
729 HPEN hPenOld = (HPEN)::SelectObject(GetHdc(), blackPen);
730 HPEN hBrushOld = (HPEN)::SelectObject(GetHdc(), whiteBrush);
cd9da200
VZ
731 ::SetROP2(GetHdc(), R2_COPYPEN);
732 Rectangle(GetHdc(), x1, y1, x2, y2);
8cb172b4 733 MoveToEx(GetHdc(), x1, y1, NULL);
cd9da200 734 LineTo(GetHdc(), x2, y2);
8cb172b4 735 MoveToEx(GetHdc(), x2, y1, NULL);
cd9da200
VZ
736 LineTo(GetHdc(), x1, y2);
737 ::SelectObject(GetHdc(), hPenOld);
738 ::SelectObject(GetHdc(), hBrushOld);
739 ::DeleteObject(blackPen);
3a5bcc4d 740#endif // Win32/Symantec-MicroWin
cd9da200
VZ
741
742 CalcBoundingBox(x1, y1);
743 CalcBoundingBox(x2, y2);
744}
745
72cdf4c9 746void wxDC::DoDrawPoint(wxCoord x, wxCoord y)
2bda0e17 747{
82a306b7 748 WXMICROWIN_CHECK_HDC
d275c7eb 749
7bcb11d3
JS
750 COLORREF color = 0x00ffffff;
751 if (m_pen.Ok())
752 {
a23fd0e1 753 color = m_pen.GetColour().GetPixel();
7bcb11d3 754 }
a23fd0e1
VZ
755
756 SetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), color);
757
7bcb11d3 758 CalcBoundingBox(x, y);
2bda0e17
KB
759}
760
72cdf4c9 761void wxDC::DoDrawPolygon(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset,int fillStyle)
2bda0e17 762{
82a306b7 763 WXMICROWIN_CHECK_HDC
d275c7eb 764
f6bcfd97 765 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
de2d2cdc 766
7bcb11d3
JS
767 // Do things less efficiently if we have offsets
768 if (xoffset != 0 || yoffset != 0)
6a6c0a8b 769 {
7bcb11d3
JS
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);
a23fd0e1 776
7bcb11d3
JS
777 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
778 }
4676948b 779#ifndef __WXWINCE__
a23fd0e1 780 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
17a6a2e0
WS
781#else
782 wxUnusedVar(fillStyle);
4676948b 783#endif
a23fd0e1 784 (void)Polygon(GetHdc(), cpoints, n);
4676948b 785#ifndef __WXWINCE__
a23fd0e1 786 SetPolyFillMode(GetHdc(),prev);
4676948b 787#endif
7bcb11d3
JS
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);
a23fd0e1 795
4676948b 796#ifndef __WXWINCE__
a23fd0e1 797 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
4676948b 798#endif
a23fd0e1 799 (void)Polygon(GetHdc(), (POINT*) points, n);
4676948b 800#ifndef __WXWINCE__
a23fd0e1 801 SetPolyFillMode(GetHdc(),prev);
4676948b 802#endif
6a6c0a8b 803 }
2bda0e17
KB
804}
805
6e76b35d
VZ
806void
807wxDC::DoDrawPolyPolygon(int n,
793db755 808 int count[],
6e76b35d
VZ
809 wxPoint points[],
810 wxCoord xoffset,
811 wxCoord yoffset,
812 int fillStyle)
813{
d61c1a6f 814#ifdef __WXWINCE__
95c1ea29 815 wxDCBase::DoDrawPolyPolygon(n, count, points, xoffset, yoffset, fillStyle);
35bbb0c6 816#else
82a306b7 817 WXMICROWIN_CHECK_HDC
6e76b35d
VZ
818
819 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
820 int i, cnt;
821 for (i = cnt = 0; i < n; i++)
793db755 822 cnt += count[i];
6e76b35d
VZ
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 }
d61c1a6f 835#ifndef __WXWINCE__
6e76b35d 836 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
35bbb0c6 837#endif
793db755 838 (void)PolyPolygon(GetHdc(), cpoints, count, n);
d61c1a6f 839#ifndef __WXWINCE__
6e76b35d 840 SetPolyFillMode(GetHdc(),prev);
35bbb0c6 841#endif
6e76b35d
VZ
842 delete[] cpoints;
843 }
844 else
845 {
846 for (i = 0; i < cnt; i++)
847 CalcBoundingBox(points[i].x, points[i].y);
848
d61c1a6f 849#ifndef __WXWINCE__
6e76b35d 850 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
35bbb0c6 851#endif
793db755 852 (void)PolyPolygon(GetHdc(), (POINT*) points, count, n);
d61c1a6f 853#ifndef __WXWINCE__
6e76b35d 854 SetPolyFillMode(GetHdc(),prev);
35bbb0c6 855#endif
6e76b35d 856 }
d61c1a6f
JS
857#endif
858 // __WXWINCE__
6e76b35d
VZ
859}
860
72cdf4c9 861void wxDC::DoDrawLines(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset)
2bda0e17 862{
82a306b7 863 WXMICROWIN_CHECK_HDC
d275c7eb 864
7bcb11d3
JS
865 // Do things less efficiently if we have offsets
866 if (xoffset != 0 || yoffset != 0)
6a6c0a8b 867 {
7bcb11d3
JS
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);
a23fd0e1 874
7bcb11d3
JS
875 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
876 }
a23fd0e1 877 (void)Polyline(GetHdc(), cpoints, n);
7bcb11d3
JS
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);
a23fd0e1
VZ
885
886 (void)Polyline(GetHdc(), (POINT*) points, n);
6a6c0a8b 887 }
2bda0e17
KB
888}
889
72cdf4c9 890void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
2bda0e17 891{
82a306b7 892 WXMICROWIN_CHECK_HDC
d275c7eb 893
f6bcfd97 894 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
de2d2cdc 895
72cdf4c9
VZ
896 wxCoord x2 = x + width;
897 wxCoord y2 = y + height;
a23fd0e1 898
5456b916 899 if ((m_logicalFunction == wxCOPY) && (m_pen.GetStyle() == wxTRANSPARENT))
0bafad0c 900 {
7299b1b2 901 RECT rect;
5456b916
RR
902 rect.left = XLOG2DEV(x);
903 rect.top = YLOG2DEV(y);
904 rect.right = XLOG2DEV(x2);
7299b1b2
RD
905 rect.bottom = YLOG2DEV(y2);
906 (void)FillRect(GetHdc(), &rect, (HBRUSH)m_brush.GetResourceHandle() );
5456b916
RR
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
f6bcfd97 912 // to have the same size regardless of which pen is used - adjust
5456b916
RR
913
914