]> git.saurik.com Git - wxWidgets.git/blob - src/msw/dc.cpp
applied patch 428783 (fix B32 makefiles)
[wxWidgets.git] / src / msw / dc.cpp
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 and Markus Holzem
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ===========================================================================
13 // declarations
14 // ===========================================================================
15
16 // ---------------------------------------------------------------------------
17 // headers
18 // ---------------------------------------------------------------------------
19
20 #ifdef __GNUG__
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/dcprint.h"
44
45 #include <string.h>
46 #include <math.h>
47
48 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
49
50 #if wxUSE_COMMON_DIALOGS
51 #include <commdlg.h>
52 #endif
53
54 #ifndef __WIN32__
55 #include <print.h>
56 #endif
57
58 IMPLEMENT_ABSTRACT_CLASS(wxDC, wxDCBase)
59
60 // ---------------------------------------------------------------------------
61 // constants
62 // ---------------------------------------------------------------------------
63
64 static const int VIEWPORT_EXTENT = 1000;
65
66 static const int MM_POINTS = 9;
67 static const int MM_METRIC = 10;
68
69 // usually this is defined in math.h
70 #ifndef M_PI
71 static const double M_PI = 3.14159265358979323846;
72 #endif // M_PI
73
74 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
75 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
76 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
77
78 // ---------------------------------------------------------------------------
79 // private functions
80 // ---------------------------------------------------------------------------
81
82 // convert degrees to radians
83 static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
84
85 // ----------------------------------------------------------------------------
86 // private classes
87 // ----------------------------------------------------------------------------
88
89 // instead of duplicating the same code which sets and then restores text
90 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
91 // encapsulate this in a small helper class
92
93 // wxColourChanger: changes the text colours in the ctor if required and
94 // restores them in the dtor
95 class wxColourChanger
96 {
97 public:
98 wxColourChanger(wxDC& dc);
99 ~wxColourChanger();
100
101 private:
102 wxDC& m_dc;
103
104 COLORREF m_colFgOld, m_colBgOld;
105
106 bool m_changed;
107 };
108
109 // ===========================================================================
110 // implementation
111 // ===========================================================================
112
113 // ----------------------------------------------------------------------------
114 // wxColourChanger
115 // ----------------------------------------------------------------------------
116
117 wxColourChanger::wxColourChanger(wxDC& dc) : m_dc(dc)
118 {
119 if ( dc.GetBrush().GetStyle() == wxSTIPPLE_MASK_OPAQUE )
120 {
121 HDC hdc = GetHdcOf(dc);
122 m_colFgOld = ::GetTextColor(hdc);
123 m_colBgOld = ::GetBkColor(hdc);
124
125 // note that Windows convention is opposite to wxWindows one, this is
126 // why text colour becomes the background one and vice versa
127 const wxColour& colFg = dc.GetTextForeground();
128 if ( colFg.Ok() )
129 {
130 ::SetBkColor(hdc, colFg.GetPixel());
131 }
132
133 const wxColour& colBg = dc.GetTextBackground();
134 if ( colBg.Ok() )
135 {
136 ::SetTextColor(hdc, colBg.GetPixel());
137 }
138
139 SetBkMode(hdc,
140 dc.GetBackgroundMode() == wxTRANSPARENT ? TRANSPARENT
141 : OPAQUE);
142
143 // flag which telsl us to undo changes in the dtor
144 m_changed = TRUE;
145 }
146 else
147 {
148 // nothing done, nothing to undo
149 m_changed = FALSE;
150 }
151 }
152
153 wxColourChanger::~wxColourChanger()
154 {
155 if ( m_changed )
156 {
157 // restore the colours we changed
158 HDC hdc = GetHdcOf(m_dc);
159
160 ::SetBkMode(hdc, TRANSPARENT);
161 ::SetTextColor(hdc, m_colFgOld);
162 ::SetBkColor(hdc, m_colBgOld);
163 }
164 }
165
166 // ---------------------------------------------------------------------------
167 // wxDC
168 // ---------------------------------------------------------------------------
169
170 // Default constructor
171 wxDC::wxDC()
172 {
173 m_canvas = NULL;
174
175 m_oldBitmap = 0;
176 m_oldPen = 0;
177 m_oldBrush = 0;
178 m_oldFont = 0;
179 m_oldPalette = 0;
180
181 m_bOwnsDC = FALSE;
182 m_hDC = 0;
183
184 m_windowExtX = VIEWPORT_EXTENT;
185 m_windowExtY = VIEWPORT_EXTENT;
186 }
187
188
189 wxDC::~wxDC()
190 {
191 if ( m_hDC != 0 )
192 {
193 SelectOldObjects(m_hDC);
194
195 // if we own the HDC, we delete it, otherwise we just release it
196
197 if ( m_bOwnsDC )
198 {
199 ::DeleteDC(GetHdc());
200 }
201 else // we don't own our HDC
202 {
203 if (m_canvas)
204 {
205 ::ReleaseDC(GetHwndOf(m_canvas), GetHdc());
206 }
207 else
208 {
209 // Must have been a wxScreenDC
210 ::ReleaseDC((HWND) NULL, GetHdc());
211 }
212 }
213 }
214 }
215
216 // This will select current objects out of the DC,
217 // which is what you have to do before deleting the
218 // DC.
219 void wxDC::SelectOldObjects(WXHDC dc)
220 {
221 if (dc)
222 {
223 if (m_oldBitmap)
224 {
225 ::SelectObject((HDC) dc, (HBITMAP) m_oldBitmap);
226 if (m_selectedBitmap.Ok())
227 {
228 m_selectedBitmap.SetSelectedInto(NULL);
229 }
230 }
231 m_oldBitmap = 0;
232 if (m_oldPen)
233 {
234 ::SelectObject((HDC) dc, (HPEN) m_oldPen);
235 }
236 m_oldPen = 0;
237 if (m_oldBrush)
238 {
239 ::SelectObject((HDC) dc, (HBRUSH) m_oldBrush);
240 }
241 m_oldBrush = 0;
242 if (m_oldFont)
243 {
244 ::SelectObject((HDC) dc, (HFONT) m_oldFont);
245 }
246 m_oldFont = 0;
247 if (m_oldPalette)
248 {
249 ::SelectPalette((HDC) dc, (HPALETTE) m_oldPalette, TRUE);
250 }
251 m_oldPalette = 0;
252 }
253
254 m_brush = wxNullBrush;
255 m_pen = wxNullPen;
256 m_palette = wxNullPalette;
257 m_font = wxNullFont;
258 m_backgroundBrush = wxNullBrush;
259 m_selectedBitmap = wxNullBitmap;
260 }
261
262 // ---------------------------------------------------------------------------
263 // clipping
264 // ---------------------------------------------------------------------------
265
266 #define DO_SET_CLIPPING_BOX() \
267 { \
268 RECT rect; \
269 \
270 GetClipBox(GetHdc(), &rect); \
271 \
272 m_clipX1 = (wxCoord) XDEV2LOG(rect.left); \
273 m_clipY1 = (wxCoord) YDEV2LOG(rect.top); \
274 m_clipX2 = (wxCoord) XDEV2LOG(rect.right); \
275 m_clipY2 = (wxCoord) YDEV2LOG(rect.bottom); \
276 }
277
278 void wxDC::DoSetClippingRegion(wxCoord cx, wxCoord cy, wxCoord cw, wxCoord ch)
279 {
280 m_clipping = TRUE;
281
282 HRGN hrgn = ::CreateRectRgn(XLOG2DEV(cx), YLOG2DEV(cy),
283 XLOG2DEV(cx + cw), YLOG2DEV(cy + ch));
284 if ( !hrgn )
285 {
286 wxLogLastError(_T("CreateRectRgn"));
287 }
288 else
289 {
290 if ( ::SelectClipRgn(GetHdc(), hrgn) == ERROR )
291 {
292 wxLogLastError(_T("SelectClipRgn"));
293 }
294
295 DO_SET_CLIPPING_BOX()
296 }
297 }
298
299 void wxDC::DoSetClippingRegionAsRegion(const wxRegion& region)
300 {
301 wxCHECK_RET( region.GetHRGN(), wxT("invalid clipping region") );
302
303 m_clipping = TRUE;
304
305 #ifdef __WIN16__
306 SelectClipRgn(GetHdc(), (HRGN) region.GetHRGN());
307 #else
308 ExtSelectClipRgn(GetHdc(), (HRGN) region.GetHRGN(), RGN_AND);
309 #endif
310
311 DO_SET_CLIPPING_BOX()
312 }
313
314 void wxDC::DestroyClippingRegion()
315 {
316 if (m_clipping && m_hDC)
317 {
318 // TODO: this should restore the previous clipping region,
319 // so that OnPaint processing works correctly, and the update clipping region
320 // doesn't get destroyed after the first DestroyClippingRegion.
321 HRGN rgn = CreateRectRgn(0, 0, 32000, 32000);
322 SelectClipRgn(GetHdc(), rgn);
323 DeleteObject(rgn);
324 }
325 m_clipping = FALSE;
326 }
327
328 // ---------------------------------------------------------------------------
329 // query capabilities
330 // ---------------------------------------------------------------------------
331
332 bool wxDC::CanDrawBitmap() const
333 {
334 return TRUE;
335 }
336
337 bool wxDC::CanGetTextExtent() const
338 {
339 // What sort of display is it?
340 int technology = ::GetDeviceCaps(GetHdc(), TECHNOLOGY);
341
342 return (technology == DT_RASDISPLAY) || (technology == DT_RASPRINTER);
343 }
344
345 int wxDC::GetDepth() const
346 {
347 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL);
348 }
349
350 // ---------------------------------------------------------------------------
351 // drawing
352 // ---------------------------------------------------------------------------
353
354 void wxDC::Clear()
355 {
356 RECT rect;
357 if ( m_canvas )
358 {
359 GetClientRect((HWND) m_canvas->GetHWND(), &rect);
360 }
361 else
362 {
363 // No, I think we should simply ignore this if printing on e.g.
364 // a printer DC.
365 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
366 if (!m_selectedBitmap.Ok())
367 return;
368
369 rect.left = 0; rect.top = 0;
370 rect.right = m_selectedBitmap.GetWidth();
371 rect.bottom = m_selectedBitmap.GetHeight();
372 }
373
374 (void) ::SetMapMode(GetHdc(), MM_TEXT);
375
376 DWORD colour = GetBkColor(GetHdc());
377 HBRUSH brush = CreateSolidBrush(colour);
378 FillRect(GetHdc(), &rect, brush);
379 DeleteObject(brush);
380
381 ::SetMapMode(GetHdc(), MM_ANISOTROPIC);
382 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT, VIEWPORT_EXTENT, NULL);
383 ::SetWindowExtEx(GetHdc(), m_windowExtX, m_windowExtY, NULL);
384 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL);
385 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX, (int)m_logicalOriginY, NULL);
386 }
387
388 void wxDC::DoFloodFill(wxCoord x, wxCoord y, const wxColour& col, int style)
389 {
390 if ( !::ExtFloodFill(GetHdc(), XLOG2DEV(x), YLOG2DEV(y),
391 col.GetPixel(),
392 style == wxFLOOD_SURFACE ? FLOODFILLSURFACE
393 : FLOODFILLBORDER) )
394 {
395 // quoting from the MSDN docs:
396 //
397 // Following are some of the reasons this function might fail:
398 //
399 // * The filling could not be completed.
400 // * The specified point has the boundary color specified by the
401 // crColor parameter (if FLOODFILLBORDER was requested).
402 // * The specified point does not have the color specified by
403 // crColor (if FLOODFILLSURFACE was requested)
404 // * The point is outside the clipping region that is, it is not
405 // visible on the device.
406 //
407 wxLogLastError(wxT("ExtFloodFill"));
408 }
409
410 CalcBoundingBox(x, y);
411 }
412
413 bool wxDC::DoGetPixel(wxCoord x, wxCoord y, wxColour *col) const
414 {
415 wxCHECK_MSG( col, FALSE, _T("NULL colour parameter in wxDC::GetPixel") );
416
417 // get the color of the pixel
418 COLORREF pixelcolor = ::GetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y));
419
420 wxRGBToColour(*col, pixelcolor);
421
422 return TRUE;
423 }
424
425 void wxDC::DoCrossHair(wxCoord x, wxCoord y)
426 {
427 wxCoord x1 = x-VIEWPORT_EXTENT;
428 wxCoord y1 = y-VIEWPORT_EXTENT;
429 wxCoord x2 = x+VIEWPORT_EXTENT;
430 wxCoord y2 = y+VIEWPORT_EXTENT;
431
432 (void)MoveToEx(GetHdc(), XLOG2DEV(x1), YLOG2DEV(y), NULL);
433 (void)LineTo(GetHdc(), XLOG2DEV(x2), YLOG2DEV(y));
434
435 (void)MoveToEx(GetHdc(), XLOG2DEV(x), YLOG2DEV(y1), NULL);
436 (void)LineTo(GetHdc(), XLOG2DEV(x), YLOG2DEV(y2));
437
438 CalcBoundingBox(x1, y1);
439 CalcBoundingBox(x2, y2);
440 }
441
442 void wxDC::DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
443 {
444 (void)MoveToEx(GetHdc(), XLOG2DEV(x1), YLOG2DEV(y1), NULL);
445 (void)LineTo(GetHdc(), XLOG2DEV(x2), YLOG2DEV(y2));
446
447 // Normalization: Windows doesn't draw the last point of the line.
448 // But apparently neither does GTK+, so we take it out again.
449 // (void)LineTo(GetHdc(), XLOG2DEV(x2) + 1, YLOG2DEV(y2));
450
451 CalcBoundingBox(x1, y1);
452 CalcBoundingBox(x2, y2);
453 }
454
455 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
456 // and ending at (x2, y2)
457 void wxDC::DoDrawArc(wxCoord x1, wxCoord y1,
458 wxCoord x2, wxCoord y2,
459 wxCoord xc, wxCoord yc)
460 {
461 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
462
463 double dx = xc - x1;
464 double dy = yc - y1;
465 double radius = (double)sqrt(dx*dx+dy*dy);
466 wxCoord r = (wxCoord)radius;
467
468 // treat the special case of full circle separately
469 if ( x1 == x2 && y1 == y2 )
470 {
471 DrawEllipse(xc - r, yc - r, 2*r, 2*r);
472 return;
473 }
474
475 wxCoord xx1 = XLOG2DEV(x1);
476 wxCoord yy1 = YLOG2DEV(y1);
477 wxCoord xx2 = XLOG2DEV(x2);
478 wxCoord yy2 = YLOG2DEV(y2);
479 wxCoord xxc = XLOG2DEV(xc);
480 wxCoord yyc = YLOG2DEV(yc);
481 wxCoord ray = (wxCoord) sqrt(double((xxc-xx1)*(xxc-xx1)+(yyc-yy1)*(yyc-yy1)));
482
483 wxCoord xxx1 = (wxCoord) (xxc-ray);
484 wxCoord yyy1 = (wxCoord) (yyc-ray);
485 wxCoord xxx2 = (wxCoord) (xxc+ray);
486 wxCoord yyy2 = (wxCoord) (yyc+ray);
487
488 if ( m_brush.Ok() && m_brush.GetStyle() != wxTRANSPARENT )
489 {
490 // Have to add 1 to bottom-right corner of rectangle
491 // to make semi-circles look right (crooked line otherwise).
492 // Unfortunately this is not a reliable method, depends
493 // on the size of shape.
494 // TODO: figure out why this happens!
495 Pie(GetHdc(),xxx1,yyy1,xxx2+1,yyy2+1, xx1,yy1,xx2,yy2);
496 }
497 else
498 {
499 Arc(GetHdc(),xxx1,yyy1,xxx2,yyy2, xx1,yy1,xx2,yy2);
500 }
501
502 CalcBoundingBox(xc - r, yc - r);
503 CalcBoundingBox(xc + r, yc + r);
504 }
505
506 void wxDC::DoDrawCheckMark(wxCoord x1, wxCoord y1,
507 wxCoord width, wxCoord height)
508 {
509 wxCoord x2 = x1 + width,
510 y2 = y1 + height;
511
512 #if defined(__WIN32__) && !defined(__SC__)
513 RECT rect;
514 rect.left = x1;
515 rect.top = y1;
516 rect.right = x2;
517 rect.bottom = y2;
518
519 DrawFrameControl(GetHdc(), &rect, DFC_MENU, DFCS_MENUCHECK);
520 #else // Win16
521 // In WIN16, draw a cross
522 HPEN blackPen = ::CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
523 HPEN whiteBrush = (HPEN)::GetStockObject(WHITE_BRUSH);
524 HPEN hPenOld = (HPEN)::SelectObject(GetHdc(), blackPen);
525 HPEN hBrushOld = (HPEN)::SelectObject(GetHdc(), whiteBrush);
526 ::SetROP2(GetHdc(), R2_COPYPEN);
527 Rectangle(GetHdc(), x1, y1, x2, y2);
528 MoveTo(GetHdc(), x1, y1);
529 LineTo(GetHdc(), x2, y2);
530 MoveTo(GetHdc(), x2, y1);
531 LineTo(GetHdc(), x1, y2);
532 ::SelectObject(GetHdc(), hPenOld);
533 ::SelectObject(GetHdc(), hBrushOld);
534 ::DeleteObject(blackPen);
535 #endif // Win32/16
536
537 CalcBoundingBox(x1, y1);
538 CalcBoundingBox(x2, y2);
539 }
540
541 void wxDC::DoDrawPoint(wxCoord x, wxCoord y)
542 {
543 COLORREF color = 0x00ffffff;
544 if (m_pen.Ok())
545 {
546 color = m_pen.GetColour().GetPixel();
547 }
548
549 SetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), color);
550
551 CalcBoundingBox(x, y);
552 }
553
554 void wxDC::DoDrawPolygon(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset,int fillStyle)
555 {
556 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
557
558 // Do things less efficiently if we have offsets
559 if (xoffset != 0 || yoffset != 0)
560 {
561 POINT *cpoints = new POINT[n];
562 int i;
563 for (i = 0; i < n; i++)
564 {
565 cpoints[i].x = (int)(points[i].x + xoffset);
566 cpoints[i].y = (int)(points[i].y + yoffset);
567
568 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
569 }
570 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
571 (void)Polygon(GetHdc(), cpoints, n);
572 SetPolyFillMode(GetHdc(),prev);
573 delete[] cpoints;
574 }
575 else
576 {
577 int i;
578 for (i = 0; i < n; i++)
579 CalcBoundingBox(points[i].x, points[i].y);
580
581 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
582 (void)Polygon(GetHdc(), (POINT*) points, n);
583 SetPolyFillMode(GetHdc(),prev);
584 }
585 }
586
587 void wxDC::DoDrawLines(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset)
588 {
589 // Do things less efficiently if we have offsets
590 if (xoffset != 0 || yoffset != 0)
591 {
592 POINT *cpoints = new POINT[n];
593 int i;
594 for (i = 0; i < n; i++)
595 {
596 cpoints[i].x = (int)(points[i].x + xoffset);
597 cpoints[i].y = (int)(points[i].y + yoffset);
598
599 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
600 }
601 (void)Polyline(GetHdc(), cpoints, n);
602 delete[] cpoints;
603 }
604 else
605 {
606 int i;
607 for (i = 0; i < n; i++)
608 CalcBoundingBox(points[i].x, points[i].y);
609
610 (void)Polyline(GetHdc(), (POINT*) points, n);
611 }
612 }
613
614 void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
615 {
616 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
617
618 wxCoord x2 = x + width;
619 wxCoord y2 = y + height;
620
621 if ((m_logicalFunction == wxCOPY) && (m_pen.GetStyle() == wxTRANSPARENT))
622 {
623 RECT rect;
624 rect.left = XLOG2DEV(x);
625 rect.top = YLOG2DEV(y);
626 rect.right = XLOG2DEV(x2);
627 rect.bottom = YLOG2DEV(y2);
628 (void)FillRect(GetHdc(), &rect, (HBRUSH)m_brush.GetResourceHandle() );
629 }
630 else
631 {
632 // Windows draws the filled rectangles without outline (i.e. drawn with a
633 // transparent pen) one pixel smaller in both directions and we want them
634 // to have the same size regardless of which pen is used - adjust
635
636 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
637 if ( m_pen.GetStyle() == wxTRANSPARENT )
638 {
639 x2++;
640 y2++;
641 }
642
643 (void)Rectangle(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2));
644 }
645
646
647 CalcBoundingBox(x, y);
648 CalcBoundingBox(x2, y2);
649 }
650
651 void wxDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius)
652 {
653 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
654
655 // Now, a negative radius value is interpreted to mean
656 // 'the proportion of the smallest X or Y dimension'
657
658 if (radius < 0.0)
659 {
660 double smallest = 0.0;
661 if (width < height)
662 smallest = width;
663 else
664 smallest = height;
665 radius = (- radius * smallest);
666 }
667
668 wxCoord x2 = (x+width);
669 wxCoord y2 = (y+height);
670
671 // Windows draws the filled rectangles without outline (i.e. drawn with a
672 // transparent pen) one pixel smaller in both directions and we want them
673 // to have the same size regardless of which pen is used - adjust
674 if ( m_pen.GetStyle() == wxTRANSPARENT )
675 {
676 x2++;
677 y2++;
678 }
679
680 (void)RoundRect(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2),
681 YLOG2DEV(y2), (int) (2*XLOG2DEV(radius)), (int)( 2*YLOG2DEV(radius)));
682
683 CalcBoundingBox(x, y);
684 CalcBoundingBox(x2, y2);
685 }
686
687 void wxDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
688 {
689 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
690
691 wxCoord x2 = (x+width);
692 wxCoord y2 = (y+height);
693
694 (void)Ellipse(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2));
695
696 CalcBoundingBox(x, y);
697 CalcBoundingBox(x2, y2);
698 }
699
700 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
701 void wxDC::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea)
702 {
703 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
704
705 wxCoord x2 = x + w;
706 wxCoord y2 = y + h;
707
708 int rx1 = XLOG2DEV(x+w/2);
709 int ry1 = YLOG2DEV(y+h/2);
710 int rx2 = rx1;
711 int ry2 = ry1;
712
713 sa = DegToRad(sa);
714 ea = DegToRad(ea);
715
716 rx1 += (int)(100.0 * abs(w) * cos(sa));
717 ry1 -= (int)(100.0 * abs(h) * m_signY * sin(sa));
718 rx2 += (int)(100.0 * abs(w) * cos(ea));
719 ry2 -= (int)(100.0 * abs(h) * m_signY * sin(ea));
720
721 // draw pie with NULL_PEN first and then outline otherwise a line is
722 // drawn from the start and end points to the centre
723 HPEN hpenOld = (HPEN) ::SelectObject(GetHdc(), (HPEN) ::GetStockObject(NULL_PEN));
724 if (m_signY > 0)
725 {
726 (void)Pie(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2)+1, YLOG2DEV(y2)+1,
727 rx1, ry1, rx2, ry2);
728 }
729 else
730 {
731 (void)Pie(GetHdc(), XLOG2DEV(x), YLOG2DEV(y)-1, XLOG2DEV(x2)+1, YLOG2DEV(y2),
732 rx1, ry1-1, rx2, ry2-1);
733 }
734
735 ::SelectObject(GetHdc(), hpenOld);
736
737 (void)Arc(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2),
738 rx1, ry1, rx2, ry2);
739
740 CalcBoundingBox(x, y);
741 CalcBoundingBox(x2, y2);
742 }
743
744 void wxDC::DoDrawIcon(const wxIcon& icon, wxCoord x, wxCoord y)
745 {
746 wxCHECK_RET( icon.Ok(), wxT("invalid icon in DrawIcon") );
747
748 #ifdef __WIN32__
749 ::DrawIconEx(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), GetHiconOf(icon), icon.GetWidth(), icon.GetHeight(), 0, NULL, DI_NORMAL);
750 #else
751 ::DrawIcon(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), GetHiconOf(icon));
752 #endif
753
754 CalcBoundingBox(x, y);
755 CalcBoundingBox(x + icon.GetWidth(), y + icon.GetHeight());
756 }
757
758 void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask )
759 {
760 wxCHECK_RET( bmp.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
761
762 int width = bmp.GetWidth(),
763 height = bmp.GetHeight();
764
765 HBITMAP hbmpMask = 0;
766
767 if ( useMask )
768 {
769 wxMask *mask = bmp.GetMask();
770 if ( mask )
771 hbmpMask = (HBITMAP)mask->GetMaskBitmap();
772
773 if ( !hbmpMask )
774 {
775 // don't give assert here because this would break existing
776 // programs - just silently ignore useMask parameter
777 useMask = FALSE;
778 }
779 }
780
781 if ( useMask )
782 {
783 #ifdef __WIN32__
784 HDC hdcMem = ::CreateCompatibleDC(GetHdc());
785 ::SelectObject(hdcMem, GetHbitmapOf(bmp));
786
787 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
788 // points
789 bool ok = ::MaskBlt(GetHdc(), x, y, width, height,
790 hdcMem, 0, 0,
791 hbmpMask, 0, 0,
792 MAKEROP4(SRCCOPY, DSTCOPY)) != 0;
793 ::DeleteDC(hdcMem);
794
795 if ( !ok )
796 #endif // Win32
797 {
798 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
799 // level
800 wxMemoryDC memDC;
801 memDC.SelectObject(bmp);
802
803 Blit(x, y, width, height, &memDC, 0, 0, wxCOPY, useMask);
804
805 memDC.SelectObject(wxNullBitmap);
806 }
807 }
808 else // no mask, just use BitBlt()
809 {
810 HDC cdc = GetHdc();
811 HDC memdc = ::CreateCompatibleDC( cdc );
812 HBITMAP hbitmap = (HBITMAP) bmp.GetHBITMAP( );
813
814 wxASSERT_MSG( hbitmap, wxT("bitmap is ok but HBITMAP is NULL?") );
815
816 COLORREF old_textground = ::GetTextColor(GetHdc());
817 COLORREF old_background = ::GetBkColor(GetHdc());
818 if (m_textForegroundColour.Ok())
819 {
820 ::SetTextColor(GetHdc(), m_textForegroundColour.GetPixel() );
821 }
822 if (m_textBackgroundColour.Ok())
823 {
824 ::SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() );
825 }
826
827 ::SelectObject( memdc, hbitmap );
828 ::BitBlt( cdc, x, y, width, height, memdc, 0, 0, SRCCOPY);
829 ::DeleteDC( memdc );
830
831 ::SetTextColor(GetHdc(), old_textground);
832 ::SetBkColor(GetHdc(), old_background);
833 }
834 }
835
836 void wxDC::DoDrawText(const wxString& text, wxCoord x, wxCoord y)
837 {
838 DrawAnyText(text, x, y);
839
840 // update the bounding box
841 CalcBoundingBox(x, y);
842
843 wxCoord w, h;
844 GetTextExtent(text, &w, &h);
845 CalcBoundingBox(x + w, y + h);
846 }
847
848 void wxDC::DrawAnyText(const wxString& text, wxCoord x, wxCoord y)
849 {
850 // prepare for drawing the text
851 if ( m_textForegroundColour.Ok() )
852 SetTextColor(GetHdc(), m_textForegroundColour.GetPixel());
853
854 DWORD old_background = 0;
855 if ( m_textBackgroundColour.Ok() )
856 {
857 old_background = SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() );
858 }
859
860 SetBkMode(GetHdc(), m_backgroundMode == wxTRANSPARENT ? TRANSPARENT
861 : OPAQUE);
862
863 if ( ::TextOut(GetHdc(), XLOG2DEV(x), YLOG2DEV(y),
864 text.c_str(), text.length()) == 0 )
865 {
866 wxLogLastError(wxT("TextOut"));
867 }
868
869 // restore the old parameters (text foreground colour may be left because
870 // it never is set to anything else, but background should remain
871 // transparent even if we just drew an opaque string)
872 if ( m_textBackgroundColour.Ok() )
873 (void)SetBkColor(GetHdc(), old_background);
874
875 SetBkMode(GetHdc(), TRANSPARENT);
876 }
877
878 void wxDC::DoDrawRotatedText(const wxString& text,
879 wxCoord x, wxCoord y,
880 double angle)
881 {
882 // we test that we have some font because otherwise we should still use the
883 // "else" part below to avoid that DrawRotatedText(angle = 180) and
884 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
885 // font for drawing rotated fonts unfortunately)
886 if ( (angle == 0.0) && m_font.Ok() )
887 {
888 DoDrawText(text, x, y);
889 }
890 else
891 {
892 // NB: don't take DEFAULT_GUI_FONT because it's not TrueType and so
893 // can't have non zero orientation/escapement
894 wxFont font = m_font.Ok() ? m_font : *wxNORMAL_FONT;
895 HFONT hfont = (HFONT)font.GetResourceHandle();
896 LOGFONT lf;
897 if ( ::GetObject(hfont, sizeof(lf), &lf) == 0 )
898 {
899 wxLogLastError(wxT("GetObject(hfont)"));
900 }
901
902 // GDI wants the angle in tenth of degree
903 long angle10 = (long)(angle * 10);
904 lf.lfEscapement = angle10;
905 lf. lfOrientation = angle10;
906
907 hfont = ::CreateFontIndirect(&lf);
908 if ( !hfont )
909 {
910 wxLogLastError(wxT("CreateFont"));
911 }
912 else
913 {
914 HFONT hfontOld = (HFONT)::SelectObject(GetHdc(), hfont);
915
916 DrawAnyText(text, x, y);
917
918 (void)::SelectObject(GetHdc(), hfontOld);
919 (void)::DeleteObject(hfont);
920 }
921
922 // call the bounding box by adding all four vertices of the rectangle
923 // containing the text to it (simpler and probably not slower than
924 // determining which of them is really topmost/leftmost/...)
925 wxCoord w, h;
926 GetTextExtent(text, &w, &h);
927
928 double rad = DegToRad(angle);
929
930 // "upper left" and "upper right"
931 CalcBoundingBox(x, y);
932 CalcBoundingBox(x + w*cos(rad), y - h*sin(rad));
933
934 // "bottom left" and "bottom right"
935 x += (wxCoord)(h*sin(rad));
936 y += (wxCoord)(h*cos(rad));
937 CalcBoundingBox(x, y);
938 CalcBoundingBox(x + h*sin(rad), y + h*cos(rad));
939 }
940 }
941
942 // ---------------------------------------------------------------------------
943 // set GDI objects
944 // ---------------------------------------------------------------------------
945
946 void wxDC::SetPalette(const wxPalette& palette)
947 {
948 // Set the old object temporarily, in case the assignment deletes an object
949 // that's not yet selected out.
950 if (m_oldPalette)
951 {
952 ::SelectPalette(GetHdc(), (HPALETTE) m_oldPalette, TRUE);
953 m_oldPalette = 0;
954 }
955
956 m_palette = palette;
957
958 if (!m_palette.Ok())
959 {
960 // Setting a NULL colourmap is a way of restoring
961 // the original colourmap
962 if (m_oldPalette)
963 {
964 ::SelectPalette(GetHdc(), (HPALETTE) m_oldPalette, TRUE);
965 m_oldPalette = 0;
966 }
967
968 return;
969 }
970
971 if (m_palette.Ok() && m_palette.GetHPALETTE())
972 {
973 HPALETTE oldPal = ::SelectPalette(GetHdc(), (HPALETTE) m_palette.GetHPALETTE(), TRUE);
974 if (!m_oldPalette)
975 m_oldPalette = (WXHPALETTE) oldPal;
976
977 ::RealizePalette(GetHdc());
978 }
979 }
980
981 void wxDC::SetFont(const wxFont& the_font)
982 {
983 // Set the old object temporarily, in case the assignment deletes an object
984 // that's not yet selected out.
985 if (m_oldFont)
986 {
987 ::SelectObject(GetHdc(), (HFONT) m_oldFont);
988 m_oldFont = 0;
989 }
990
991 m_font = the_font;
992
993 if (!the_font.Ok())
994 {
995 if (m_oldFont)
996 ::SelectObject(GetHdc(), (HFONT) m_oldFont);
997 m_oldFont = 0;
998 }
999
1000 if (m_font.Ok() && m_font.GetResourceHandle())
1001 {
1002 HFONT f = (HFONT) ::SelectObject(GetHdc(), (HFONT) m_font.GetResourceHandle());
1003 if (f == (HFONT) NULL)
1004 {
1005 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
1006 }
1007 if (!m_oldFont)
1008 m_oldFont = (WXHFONT) f;
1009 }
1010 }
1011
1012 void wxDC::SetPen(const wxPen& pen)
1013 {
1014 // Set the old object temporarily, in case the assignment deletes an object
1015 // that's not yet selected out.
1016 if (m_oldPen)
1017 {
1018 ::SelectObject(GetHdc(), (HPEN) m_oldPen);
1019 m_oldPen = 0;
1020 }
1021
1022 m_pen = pen;
1023
1024 if (!m_pen.Ok())
1025 {
1026 if (m_oldPen)
1027 ::SelectObject(GetHdc(), (HPEN) m_oldPen);
1028 m_oldPen = 0;
1029 }
1030
1031 if (m_pen.Ok())
1032 {
1033 if (m_pen.GetResourceHandle())
1034 {
1035 HPEN p = (HPEN) ::SelectObject(GetHdc(), (HPEN)m_pen.GetResourceHandle());
1036 if (!m_oldPen)
1037 m_oldPen = (WXHPEN) p;
1038 }
1039 }
1040 }
1041
1042 void wxDC::SetBrush(const wxBrush& brush)
1043 {
1044 // Set the old object temporarily, in case the assignment deletes an object
1045 // that's not yet selected out.
1046 if (m_oldBrush)
1047 {
1048 ::SelectObject(GetHdc(), (HBRUSH) m_oldBrush);
1049 m_oldBrush = 0;
1050 }
1051
1052 m_brush = brush;
1053
1054 if (!m_brush.Ok())
1055 {
1056 if (m_oldBrush)
1057 ::SelectObject(GetHdc(), (HBRUSH) m_oldBrush);
1058 m_oldBrush = 0;
1059 }
1060
1061 if (m_brush.Ok())
1062 {
1063 // to make sure the brush is alligned with the logical coordinates
1064 wxBitmap *stipple = m_brush.GetStipple();
1065 if ( stipple && stipple->Ok() )
1066 {
1067 #ifdef __WIN32__
1068 ::SetBrushOrgEx(GetHdc(),
1069 m_deviceOriginX % stipple->GetWidth(),
1070 m_deviceOriginY % stipple->GetHeight(),
1071 NULL); // don't need previous brush origin
1072 #else
1073 ::SetBrushOrg(GetHdc(),
1074 m_deviceOriginX % stipple->GetWidth(),
1075 m_deviceOriginY % stipple->GetHeight());
1076 #endif
1077 }
1078
1079 if ( m_brush.GetResourceHandle() )
1080 {
1081 HBRUSH b = 0;
1082 b = (HBRUSH) ::SelectObject(GetHdc(), (HBRUSH)m_brush.GetResourceHandle());
1083 if (!m_oldBrush)
1084 m_oldBrush = (WXHBRUSH) b;
1085 }
1086 }
1087 }
1088
1089 void wxDC::SetBackground(const wxBrush& brush)
1090 {
1091 m_backgroundBrush = brush;
1092
1093 if (!m_backgroundBrush.Ok())
1094 return;
1095
1096 if (m_canvas)
1097 {
1098 bool customColours = TRUE;
1099 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
1100 // change background colours from the control-panel specified colours.
1101 if (m_canvas->IsKindOf(CLASSINFO(wxWindow)) && ((m_canvas->GetWindowStyleFlag() & wxUSER_COLOURS) != wxUSER_COLOURS))
1102 customColours = FALSE;
1103
1104 if (customColours)
1105 {
1106 if (m_backgroundBrush.GetStyle()==wxTRANSPARENT)
1107 {
1108 m_canvas->SetTransparent(TRUE);
1109 }
1110 else
1111 {
1112 // New behaviour, 10/2/99: setting the background brush of a DC
1113 // doesn't affect the window background colour. However,
1114 // I'm leaving in the transparency setting because it's needed by
1115 // various controls (e.g. wxStaticText) to determine whether to draw
1116 // transparently or not. TODO: maybe this should be a new function
1117 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
1118 // parent?
1119 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
1120 m_canvas->SetTransparent(FALSE);
1121 }
1122 }
1123 }
1124 COLORREF new_color = m_backgroundBrush.GetColour().GetPixel();
1125 {
1126 (void)SetBkColor(GetHdc(), new_color);
1127 }
1128 }
1129
1130 void wxDC::SetBackgroundMode(int mode)
1131 {
1132 m_backgroundMode = mode;
1133
1134 // SetBackgroundColour now only refers to text background
1135 // and m_backgroundMode is used there
1136
1137 /*
1138 if (m_backgroundMode == wxTRANSPARENT)
1139 ::SetBkMode(GetHdc(), TRANSPARENT);
1140 else
1141 ::SetBkMode(GetHdc(), OPAQUE);
1142 Last change: AC 29 Jan 101 8:54 pm
1143 */
1144 }
1145
1146 void wxDC::SetLogicalFunction(int function)
1147 {
1148 m_logicalFunction = function;
1149
1150 SetRop(m_hDC);
1151 }
1152
1153 void wxDC::SetRop(WXHDC dc)
1154 {
1155 if ( !dc || m_logicalFunction < 0 )
1156 return;
1157
1158 int rop;
1159
1160 switch (m_logicalFunction)
1161 {
1162 case wxCLEAR: rop = R2_BLACK; break;
1163 case wxXOR: rop = R2_XORPEN; break;
1164 case wxINVERT: rop = R2_NOT; break;
1165 case wxOR_REVERSE: rop = R2_MERGEPENNOT; break;
1166 case wxAND_REVERSE: rop = R2_MASKPENNOT; break;
1167 case wxCOPY: rop = R2_COPYPEN; break;
1168 case wxAND: rop = R2_MASKPEN; break;
1169 case wxAND_INVERT: rop = R2_MASKNOTPEN; break;
1170 case wxNO_OP: rop = R2_NOP; break;
1171 case wxNOR: rop = R2_NOTMERGEPEN; break;
1172 case wxEQUIV: rop = R2_NOTXORPEN; break;
1173 case wxSRC_INVERT: rop = R2_NOTCOPYPEN; break;
1174 case wxOR_INVERT: rop = R2_MERGENOTPEN; break;
1175 case wxNAND: rop = R2_NOTMASKPEN; break;
1176 case wxOR: rop = R2_MERGEPEN; break;
1177 case wxSET: rop = R2_WHITE; break;
1178
1179 default:
1180 wxFAIL_MSG( wxT("unsupported logical function") );
1181 return;
1182 }
1183
1184 SetROP2(GetHdc(), rop);
1185 }
1186
1187 bool wxDC::StartDoc(const wxString& WXUNUSED(message))
1188 {
1189 // We might be previewing, so return TRUE to let it continue.
1190 return TRUE;
1191 }
1192
1193 void wxDC::EndDoc()
1194 {
1195 }
1196
1197 void wxDC::StartPage()
1198 {
1199 }
1200
1201 void wxDC::EndPage()
1202 {
1203 }
1204
1205 // ---------------------------------------------------------------------------
1206 // text metrics
1207 // ---------------------------------------------------------------------------
1208
1209 wxCoord wxDC::GetCharHeight() const
1210 {
1211 TEXTMETRIC lpTextMetric;
1212
1213 GetTextMetrics(GetHdc(), &lpTextMetric);
1214
1215 return YDEV2LOGREL(lpTextMetric.tmHeight);
1216 }
1217
1218 wxCoord wxDC::GetCharWidth() const
1219 {
1220 TEXTMETRIC lpTextMetric;
1221
1222 GetTextMetrics(GetHdc(), &lpTextMetric);
1223
1224 return XDEV2LOGREL(lpTextMetric.tmAveCharWidth);
1225 }
1226
1227 void wxDC::DoGetTextExtent(const wxString& string, wxCoord *x, wxCoord *y,
1228 wxCoord *descent, wxCoord *externalLeading,
1229 wxFont *font) const
1230 {
1231 HFONT hfontOld;
1232 if ( font )
1233 {
1234 wxASSERT_MSG( font->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1235
1236 hfontOld = (HFONT)::SelectObject(GetHdc(), GetHfontOf(*font));
1237 }
1238 else // don't change the font
1239 {
1240 hfontOld = 0;
1241 }
1242
1243 SIZE sizeRect;
1244 TEXTMETRIC tm;
1245
1246 GetTextExtentPoint(GetHdc(), string, string.length(), &sizeRect);
1247 GetTextMetrics(GetHdc(), &tm);
1248
1249 if (x) *x = XDEV2LOGREL(sizeRect.cx);
1250 if (y) *y = YDEV2LOGREL(sizeRect.cy);
1251 if (descent) *descent = tm.tmDescent;
1252 if (externalLeading) *externalLeading = tm.tmExternalLeading;
1253
1254 if ( hfontOld )
1255 {
1256 ::SelectObject(GetHdc(), hfontOld);
1257 }
1258 }
1259
1260 void wxDC::SetMapMode(int mode)
1261 {
1262 m_mappingMode = mode;
1263
1264 int pixel_width = 0;
1265 int pixel_height = 0;
1266 int mm_width = 0;
1267 int mm_height = 0;
1268
1269 pixel_width = GetDeviceCaps(GetHdc(), HORZRES);
1270 pixel_height = GetDeviceCaps(GetHdc(), VERTRES);
1271 mm_width = GetDeviceCaps(GetHdc(), HORZSIZE);
1272 mm_height = GetDeviceCaps(GetHdc(), VERTSIZE);
1273
1274 if ((pixel_width == 0) || (pixel_height == 0) || (mm_width == 0) || (mm_height == 0))
1275 {
1276 return;
1277 }
1278
1279 double mm2pixelsX = pixel_width/mm_width;
1280 double mm2pixelsY = pixel_height/mm_height;
1281
1282 switch (mode)
1283 {
1284 case wxMM_TWIPS:
1285 {
1286 m_logicalScaleX = (twips2mm * mm2pixelsX);
1287 m_logicalScaleY = (twips2mm * mm2pixelsY);
1288 break;
1289 }
1290 case wxMM_POINTS:
1291 {
1292 m_logicalScaleX = (pt2mm * mm2pixelsX);
1293 m_logicalScaleY = (pt2mm * mm2pixelsY);
1294 break;
1295 }
1296 case wxMM_METRIC:
1297 {
1298 m_logicalScaleX = mm2pixelsX;
1299 m_logicalScaleY = mm2pixelsY;
1300 break;
1301 }
1302 case wxMM_LOMETRIC:
1303 {
1304 m_logicalScaleX = (mm2pixelsX/10.0);
1305 m_logicalScaleY = (mm2pixelsY/10.0);
1306 break;
1307 }
1308 default:
1309 case wxMM_TEXT:
1310 {
1311 m_logicalScaleX = 1.0;
1312 m_logicalScaleY = 1.0;
1313 break;
1314 }
1315 }
1316
1317 if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC)
1318 ::SetMapMode(GetHdc(), MM_ANISOTROPIC);
1319
1320 SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT, VIEWPORT_EXTENT, NULL);
1321 m_windowExtX = (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT);
1322 m_windowExtY = (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT);
1323 ::SetWindowExtEx(GetHdc(), m_windowExtX, m_windowExtY, NULL);
1324 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL);
1325 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX, (int)m_logicalOriginY, NULL);
1326 }
1327
1328 void wxDC::SetUserScale(double x, double y)
1329 {
1330 m_userScaleX = x;
1331 m_userScaleY = y;
1332
1333 SetMapMode(m_mappingMode);
1334 }
1335
1336 void wxDC::SetAxisOrientation(bool xLeftRight, bool yBottomUp)
1337 {
1338 m_signX = xLeftRight ? 1 : -1;
1339 m_signY = yBottomUp ? -1 : 1;
1340
1341 SetMapMode(m_mappingMode);
1342 }
1343
1344 void wxDC::SetSystemScale(double x, double y)
1345 {
1346 m_scaleX = x;
1347 m_scaleY = y;
1348
1349 SetMapMode(m_mappingMode);
1350 }
1351
1352 void wxDC::SetLogicalOrigin(wxCoord x, wxCoord y)
1353 {
1354 m_logicalOriginX = x;
1355 m_logicalOriginY = y;
1356
1357 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX, (int)m_logicalOriginY, NULL);
1358 }
1359
1360 void wxDC::SetDeviceOrigin(wxCoord x, wxCoord y)
1361 {
1362 m_deviceOriginX = x;
1363 m_deviceOriginY = y;
1364
1365 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL);
1366 }
1367
1368 // ---------------------------------------------------------------------------
1369 // coordinates transformations
1370 // ---------------------------------------------------------------------------
1371
1372 wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
1373 {
1374 double xRel = x - m_deviceOriginX;
1375 xRel /= m_logicalScaleX*m_userScaleX*m_signX*m_scaleX;
1376 return (wxCoord)(xRel + m_logicalOriginX);
1377 }
1378
1379 wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
1380 {
1381 return (wxCoord) ((x)/(m_logicalScaleX*m_userScaleX*m_signX*m_scaleX));
1382 }
1383
1384 wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
1385 {
1386 double yRel = y - m_deviceOriginY;
1387 yRel /= m_logicalScaleY*m_userScaleY*m_signY*m_scaleY;
1388 return (wxCoord)(yRel + m_logicalOriginY);
1389 }
1390
1391 wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
1392 {
1393 return (wxCoord) ((y)/(m_logicalScaleY*m_userScaleY*m_signY*m_scaleY));
1394 }
1395
1396 wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
1397 {
1398 return (wxCoord) ((x - m_logicalOriginX)*m_logicalScaleX*m_userScaleX*m_signX*m_scaleX + m_deviceOriginX);
1399 }
1400
1401 wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
1402 {
1403 return (wxCoord) (x*m_logicalScaleX*m_userScaleX*m_signX*m_scaleX);
1404 }
1405
1406 wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
1407 {
1408 return (wxCoord) ((y - m_logicalOriginY)*m_logicalScaleY*m_userScaleY*m_signY*m_scaleY + m_deviceOriginY);
1409 }
1410
1411 wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
1412 {
1413 return (wxCoord) (y*m_logicalScaleY*m_userScaleY*m_signY*m_scaleY);
1414 }
1415
1416 // ---------------------------------------------------------------------------
1417 // bit blit
1418 // ---------------------------------------------------------------------------
1419
1420 bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest,
1421 wxCoord width, wxCoord height,
1422 wxDC *source, wxCoord xsrc, wxCoord ysrc,
1423 int rop, bool useMask)
1424 {
1425 wxMask *mask = NULL;
1426 if ( useMask )
1427 {
1428 const wxBitmap& bmp = source->m_selectedBitmap;
1429 mask = bmp.GetMask();
1430
1431 if ( !(bmp.Ok() && mask && mask->GetMaskBitmap()) )
1432 {
1433 // don't give assert here because this would break existing
1434 // programs - just silently ignore useMask parameter
1435 useMask = FALSE;
1436 }
1437 }
1438
1439 COLORREF old_textground = ::GetTextColor(GetHdc());
1440 COLORREF old_background = ::GetBkColor(GetHdc());
1441 if (m_textForegroundColour.Ok())
1442 {
1443 ::SetTextColor(GetHdc(), m_textForegroundColour.GetPixel() );
1444 }
1445 if (m_textBackgroundColour.Ok())
1446 {
1447 ::SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() );
1448 }
1449
1450 DWORD dwRop = SRCCOPY;
1451 switch (rop)
1452 {
1453 case wxXOR: dwRop = SRCINVERT; break;
1454 case wxINVERT: dwRop = DSTINVERT; break;
1455 case wxOR_REVERSE: dwRop = 0x00DD0228; break;
1456 case wxAND_REVERSE: dwRop = SRCERASE; break;
1457 case wxCLEAR: dwRop = BLACKNESS; break;
1458 case wxSET: dwRop = WHITENESS; break;
1459 case wxOR_INVERT: dwRop = MERGEPAINT; break;
1460 case wxAND: dwRop = SRCAND; break;
1461 case wxOR: dwRop = SRCPAINT; break;
1462 case wxEQUIV: dwRop = 0x00990066; break;
1463 case wxNAND: dwRop = 0x007700E6; break;
1464 case wxAND_INVERT: dwRop = 0x00220326; break;
1465 case wxCOPY: dwRop = SRCCOPY; break;
1466 case wxNO_OP: dwRop = DSTCOPY; break;
1467 case wxSRC_INVERT: dwRop = NOTSRCCOPY; break;
1468 case wxNOR: dwRop = NOTSRCCOPY; break;
1469 default:
1470 wxFAIL_MSG( wxT("unsupported logical function") );
1471 return FALSE;
1472 }
1473
1474 bool success;
1475
1476 if (useMask)
1477 {
1478 #ifdef __WIN32__
1479 // we want the part of the image corresponding to the mask to be
1480 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1481 // meaning of fg and bg is inverted which corresponds to wxWin notion
1482 // of the mask which is also contrary to the Windows one)
1483 success = ::MaskBlt(GetHdc(), xdest, ydest, width, height,
1484 GetHdcOf(*source), xsrc, ysrc,
1485 (HBITMAP)mask->GetMaskBitmap(), xsrc, ysrc,
1486 MAKEROP4(dwRop, DSTCOPY)) != 0;
1487
1488 if ( !success )
1489 #endif // Win32
1490 {
1491 // Blit bitmap with mask
1492
1493 // create a temp buffer bitmap and DCs to access it and the mask
1494 HDC dc_mask = ::CreateCompatibleDC(GetHdcOf(*source));
1495 HDC dc_buffer = ::CreateCompatibleDC(GetHdc());
1496 HBITMAP buffer_bmap = ::CreateCompatibleBitmap(GetHdc(), width, height);
1497 ::SelectObject(dc_mask, (HBITMAP) mask->GetMaskBitmap());
1498 ::SelectObject(dc_buffer, buffer_bmap);
1499
1500 // copy dest to buffer
1501 if ( !::BitBlt(dc_buffer, 0, 0, (int)width, (int)height,
1502 GetHdc(), xdest, ydest, SRCCOPY) )
1503 {
1504 wxLogLastError(wxT("BitBlt"));
1505 }
1506
1507 // copy src to buffer using selected raster op
1508 if ( !::BitBlt(dc_buffer, 0, 0, (int)width, (int)height,
1509 GetHdcOf(*source), xsrc, ysrc, dwRop) )
1510 {
1511 wxLogLastError(wxT("BitBlt"));
1512 }
1513
1514 // set masked area in buffer to BLACK (pixel value 0)
1515 COLORREF prevBkCol = ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1516 COLORREF prevCol = ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1517 if ( !::BitBlt(dc_buffer, 0, 0, (int)width, (int)height,
1518 dc_mask, xsrc, ysrc, SRCAND) )
1519 {
1520 wxLogLastError(wxT("BitBlt"));
1521 }
1522
1523 // set unmasked area in dest to BLACK
1524 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1525 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1526 if ( !::BitBlt(GetHdc(), xdest, ydest, (int)width, (int)height,
1527 dc_mask, xsrc, ysrc, SRCAND) )
1528 {
1529 wxLogLastError(wxT("BitBlt"));
1530 }
1531 ::SetBkColor(GetHdc(), prevBkCol); // restore colours to original values
1532 ::SetTextColor(GetHdc(), prevCol);
1533
1534 // OR buffer to dest
1535 success = ::BitBlt(GetHdc(), xdest, ydest,
1536 (int)width, (int)height,
1537 dc_buffer, 0, 0, SRCPAINT) != 0;
1538 if ( !success )
1539 {
1540 wxLogLastError(wxT("BitBlt"));
1541 }
1542
1543 // tidy up temporary DCs and bitmap
1544 ::SelectObject(dc_mask, 0);
1545 ::DeleteDC(dc_mask);
1546 ::SelectObject(dc_buffer, 0);
1547 ::DeleteDC(dc_buffer);
1548 ::DeleteObject(buffer_bmap);
1549 }
1550 }
1551 else // no mask, just BitBlt() it
1552 {
1553 success = ::BitBlt(GetHdc(), xdest, ydest,
1554 (int)width, (int)height,
1555 GetHdcOf(*source), xsrc, ysrc, dwRop) != 0;
1556 if ( !success )
1557 {
1558 wxLogLastError(wxT("BitBlt"));
1559 }
1560 }
1561 ::SetTextColor(GetHdc(), old_textground);
1562 ::SetBkColor(GetHdc(), old_background);
1563
1564 return success;
1565 }
1566
1567 void wxDC::DoGetSize(int *w, int *h) const
1568 {
1569 if ( w ) *w = ::GetDeviceCaps(GetHdc(), HORZRES);
1570 if ( h ) *h = ::GetDeviceCaps(GetHdc(), VERTRES);
1571 }
1572
1573 void wxDC::DoGetSizeMM(int *w, int *h) const
1574 {
1575 if ( w ) *w = ::GetDeviceCaps(GetHdc(), HORZSIZE);
1576 if ( h ) *h = ::GetDeviceCaps(GetHdc(), VERTSIZE);
1577 }
1578
1579 wxSize wxDC::GetPPI() const
1580 {
1581 int x = ::GetDeviceCaps(GetHdc(), LOGPIXELSX);
1582 int y = ::GetDeviceCaps(GetHdc(), LOGPIXELSY);
1583
1584 return wxSize(x, y);
1585 }
1586
1587 // For use by wxWindows only, unless custom units are required.
1588 void wxDC::SetLogicalScale(double x, double y)
1589 {
1590 m_logicalScaleX = x;
1591 m_logicalScaleY = y;
1592 }
1593
1594 #if WXWIN_COMPATIBILITY
1595 void wxDC::DoGetTextExtent(const wxString& string, float *x, float *y,
1596 float *descent, float *externalLeading,
1597 wxFont *theFont, bool use16bit) const
1598 {
1599 wxCoord x1, y1, descent1, externalLeading1;
1600 GetTextExtent(string, & x1, & y1, & descent1, & externalLeading1, theFont, use16bit);
1601 *x = x1; *y = y1;
1602 if (descent)
1603 *descent = descent1;
1604 if (externalLeading)
1605 *externalLeading = externalLeading1;
1606 }
1607 #endif
1608
1609