]> git.saurik.com Git - wxWidgets.git/blob - src/msw/dc.cpp
added a comment about the default button handling
[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/sysopt.h"
44 #include "wx/dcprint.h"
45 #include "wx/module.h"
46
47 #include <string.h>
48 #include <math.h>
49
50 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
51
52 #if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
53 #include <commdlg.h>
54 #endif
55
56 #ifndef __WIN32__
57 #include <print.h>
58 #endif
59
60 IMPLEMENT_ABSTRACT_CLASS(wxDC, wxDCBase)
61
62 // ---------------------------------------------------------------------------
63 // constants
64 // ---------------------------------------------------------------------------
65
66 static const int VIEWPORT_EXTENT = 1000;
67
68 static const int MM_POINTS = 9;
69 static const int MM_METRIC = 10;
70
71 // usually this is defined in math.h
72 #ifndef M_PI
73 static const double M_PI = 3.14159265358979323846;
74 #endif // M_PI
75
76 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
77 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
78 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
79
80 // ----------------------------------------------------------------------------
81 // macros for logical <-> device coords conversion
82 // ----------------------------------------------------------------------------
83
84 /*
85 We currently let Windows do all the translations itself so these macros are
86 not really needed (any more) but keep them to enhance readability of the
87 code by allowing to see where are the logical and where are the device
88 coordinates used.
89 */
90
91 // logical to device
92 #define XLOG2DEV(x) (x)
93 #define YLOG2DEV(y) (y)
94
95 // device to logical
96 #define XDEV2LOG(x) (x)
97 #define YDEV2LOG(y) (y)
98
99 // ---------------------------------------------------------------------------
100 // private functions
101 // ---------------------------------------------------------------------------
102
103 // convert degrees to radians
104 static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
105
106 // ----------------------------------------------------------------------------
107 // private classes
108 // ----------------------------------------------------------------------------
109
110 // instead of duplicating the same code which sets and then restores text
111 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
112 // encapsulate this in a small helper class
113
114 // wxColourChanger: changes the text colours in the ctor if required and
115 // restores them in the dtor
116 class wxColourChanger
117 {
118 public:
119 wxColourChanger(wxDC& dc);
120 ~wxColourChanger();
121
122 private:
123 wxDC& m_dc;
124
125 COLORREF m_colFgOld, m_colBgOld;
126
127 bool m_changed;
128 };
129
130 // ===========================================================================
131 // implementation
132 // ===========================================================================
133
134 // ----------------------------------------------------------------------------
135 // wxColourChanger
136 // ----------------------------------------------------------------------------
137
138 wxColourChanger::wxColourChanger(wxDC& dc) : m_dc(dc)
139 {
140 const wxBrush& brush = dc.GetBrush();
141 if ( brush.Ok() && brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE )
142 {
143 HDC hdc = GetHdcOf(dc);
144 m_colFgOld = ::GetTextColor(hdc);
145 m_colBgOld = ::GetBkColor(hdc);
146
147 // note that Windows convention is opposite to wxWindows one, this is
148 // why text colour becomes the background one and vice versa
149 const wxColour& colFg = dc.GetTextForeground();
150 if ( colFg.Ok() )
151 {
152 ::SetBkColor(hdc, colFg.GetPixel());
153 }
154
155 const wxColour& colBg = dc.GetTextBackground();
156 if ( colBg.Ok() )
157 {
158 ::SetTextColor(hdc, colBg.GetPixel());
159 }
160
161 SetBkMode(hdc,
162 dc.GetBackgroundMode() == wxTRANSPARENT ? TRANSPARENT
163 : OPAQUE);
164
165 // flag which telsl us to undo changes in the dtor
166 m_changed = TRUE;
167 }
168 else
169 {
170 // nothing done, nothing to undo
171 m_changed = FALSE;
172 }
173 }
174
175 wxColourChanger::~wxColourChanger()
176 {
177 if ( m_changed )
178 {
179 // restore the colours we changed
180 HDC hdc = GetHdcOf(m_dc);
181
182 ::SetBkMode(hdc, TRANSPARENT);
183 ::SetTextColor(hdc, m_colFgOld);
184 ::SetBkColor(hdc, m_colBgOld);
185 }
186 }
187
188 // ---------------------------------------------------------------------------
189 // wxDC
190 // ---------------------------------------------------------------------------
191
192 // Default constructor
193 wxDC::wxDC()
194 {
195 m_canvas = NULL;
196
197 m_oldBitmap = 0;
198 m_oldPen = 0;
199 m_oldBrush = 0;
200 m_oldFont = 0;
201 #if wxUSE_PALETTE
202 m_oldPalette = 0;
203 #endif // wxUSE_PALETTE
204
205 m_bOwnsDC = FALSE;
206 m_hDC = 0;
207 }
208
209 wxDC::~wxDC()
210 {
211 if ( m_hDC != 0 )
212 {
213 SelectOldObjects(m_hDC);
214
215 // if we own the HDC, we delete it, otherwise we just release it
216
217 if ( m_bOwnsDC )
218 {
219 ::DeleteDC(GetHdc());
220 }
221 else // we don't own our HDC
222 {
223 if (m_canvas)
224 {
225 ::ReleaseDC(GetHwndOf(m_canvas), GetHdc());
226 }
227 else
228 {
229 // Must have been a wxScreenDC
230 ::ReleaseDC((HWND) NULL, GetHdc());
231 }
232 }
233 }
234 }
235
236 // This will select current objects out of the DC,
237 // which is what you have to do before deleting the
238 // DC.
239 void wxDC::SelectOldObjects(WXHDC dc)
240 {
241 if (dc)
242 {
243 if (m_oldBitmap)
244 {
245 ::SelectObject((HDC) dc, (HBITMAP) m_oldBitmap);
246 if (m_selectedBitmap.Ok())
247 {
248 m_selectedBitmap.SetSelectedInto(NULL);
249 }
250 }
251 m_oldBitmap = 0;
252 if (m_oldPen)
253 {
254 ::SelectObject((HDC) dc, (HPEN) m_oldPen);
255 }
256 m_oldPen = 0;
257 if (m_oldBrush)
258 {
259 ::SelectObject((HDC) dc, (HBRUSH) m_oldBrush);
260 }
261 m_oldBrush = 0;
262 if (m_oldFont)
263 {
264 ::SelectObject((HDC) dc, (HFONT) m_oldFont);
265 }
266 m_oldFont = 0;
267
268 #if wxUSE_PALETTE
269 if (m_oldPalette)
270 {
271 ::SelectPalette((HDC) dc, (HPALETTE) m_oldPalette, FALSE);
272 }
273 m_oldPalette = 0;
274 #endif // wxUSE_PALETTE
275 }
276
277 m_brush = wxNullBrush;
278 m_pen = wxNullPen;
279 #if wxUSE_PALETTE
280 m_palette = wxNullPalette;
281 #endif // wxUSE_PALETTE
282 m_font = wxNullFont;
283 m_backgroundBrush = wxNullBrush;
284 m_selectedBitmap = wxNullBitmap;
285 }
286
287 // ---------------------------------------------------------------------------
288 // clipping
289 // ---------------------------------------------------------------------------
290
291 void wxDC::UpdateClipBox()
292 {
293 #ifdef __WXMICROWIN__
294 if (!GetHDC()) return;
295 #endif
296
297 RECT rect;
298 ::GetClipBox(GetHdc(), &rect);
299
300 m_clipX1 = (wxCoord) XDEV2LOG(rect.left);
301 m_clipY1 = (wxCoord) YDEV2LOG(rect.top);
302 m_clipX2 = (wxCoord) XDEV2LOG(rect.right);
303 m_clipY2 = (wxCoord) YDEV2LOG(rect.bottom);
304 }
305
306 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
307 void wxDC::SetClippingHrgn(WXHRGN hrgn)
308 {
309 wxCHECK_RET( hrgn, wxT("invalid clipping region") );
310
311 #ifdef __WXMICROWIN__
312 if (!GetHdc()) return;
313 #endif // __WXMICROWIN__
314
315 // note that we combine the new clipping region with the existing one: this
316 // is compatible with what the other ports do and is the documented
317 // behaviour now (starting with 2.3.3)
318 #ifdef __WIN16__
319 RECT rectClip;
320 if ( !::GetClipBox(GetHdc(), &rectClip) )
321 return;
322
323 HRGN hrgnDest = ::CreateRectRgn(0, 0, 0, 0);
324 HRGN hrgnClipOld = ::CreateRectRgn(rectClip.left, rectClip.top,
325 rectClip.right, rectClip.bottom);
326
327 if ( ::CombineRgn(hrgnDest, hrgnClipOld, (HRGN)hrgn, RGN_AND) != ERROR )
328 {
329 ::SelectClipRgn(GetHdc(), hrgnDest);
330 }
331
332 ::DeleteObject(hrgnClipOld);
333 ::DeleteObject(hrgnDest);
334 #else // Win32
335 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN)hrgn, RGN_AND) == ERROR )
336 {
337 wxLogLastError(_T("ExtSelectClipRgn"));
338
339 return;
340 }
341 #endif // Win16/32
342
343 m_clipping = TRUE;
344
345 UpdateClipBox();
346 }
347
348 void wxDC::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
349 {
350 // the region coords are always the device ones, so do the translation
351 // manually
352 //
353 // FIXME: possible +/-1 error here, to check!
354 HRGN hrgn = ::CreateRectRgn(LogicalToDeviceX(x),
355 LogicalToDeviceY(y),
356 LogicalToDeviceX(x + w),
357 LogicalToDeviceY(y + h));
358 if ( !hrgn )
359 {
360 wxLogLastError(_T("CreateRectRgn"));
361 }
362 else
363 {
364 SetClippingHrgn((WXHRGN)hrgn);
365
366 ::DeleteObject(hrgn);
367 }
368 }
369
370 void wxDC::DoSetClippingRegionAsRegion(const wxRegion& region)
371 {
372 SetClippingHrgn(region.GetHRGN());
373 }
374
375 void wxDC::DestroyClippingRegion()
376 {
377 #ifdef __WXMICROWIN__
378 if (!GetHDC()) return;
379 #endif
380
381 if (m_clipping && m_hDC)
382 {
383 // TODO: this should restore the previous clipping region,
384 // so that OnPaint processing works correctly, and the update
385 // clipping region doesn't get destroyed after the first
386 // DestroyClippingRegion.
387 HRGN rgn = CreateRectRgn(0, 0, 32000, 32000);
388 ::SelectClipRgn(GetHdc(), rgn);
389 ::DeleteObject(rgn);
390 }
391
392 m_clipping = FALSE;
393 }
394
395 // ---------------------------------------------------------------------------
396 // query capabilities
397 // ---------------------------------------------------------------------------
398
399 bool wxDC::CanDrawBitmap() const
400 {
401 return TRUE;
402 }
403
404 bool wxDC::CanGetTextExtent() const
405 {
406 #ifdef __WXMICROWIN__
407 // TODO Extend MicroWindows' GetDeviceCaps function
408 return TRUE;
409 #else
410 // What sort of display is it?
411 int technology = ::GetDeviceCaps(GetHdc(), TECHNOLOGY);
412
413 return (technology == DT_RASDISPLAY) || (technology == DT_RASPRINTER);
414 #endif
415 }
416
417 int wxDC::GetDepth() const
418 {
419 #ifdef __WXMICROWIN__
420 if (!GetHDC()) return 16;
421 #endif
422
423 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL);
424 }
425
426 // ---------------------------------------------------------------------------
427 // drawing
428 // ---------------------------------------------------------------------------
429
430 void wxDC::Clear()
431 {
432 #ifdef __WXMICROWIN__
433 if (!GetHDC()) return;
434 #endif
435
436 RECT rect;
437 if ( m_canvas )
438 {
439 GetClientRect((HWND) m_canvas->GetHWND(), &rect);
440 }
441 else
442 {
443 // No, I think we should simply ignore this if printing on e.g.
444 // a printer DC.
445 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
446 if (!m_selectedBitmap.Ok())
447 return;
448
449 rect.left = 0; rect.top = 0;
450 rect.right = m_selectedBitmap.GetWidth();
451 rect.bottom = m_selectedBitmap.GetHeight();
452 }
453
454 (void) ::SetMapMode(GetHdc(), MM_TEXT);
455
456 DWORD colour = ::GetBkColor(GetHdc());
457 HBRUSH brush = ::CreateSolidBrush(colour);
458 ::FillRect(GetHdc(), &rect, brush);
459 ::DeleteObject(brush);
460
461 int width = DeviceToLogicalXRel(VIEWPORT_EXTENT)*m_signX,
462 height = DeviceToLogicalYRel(VIEWPORT_EXTENT)*m_signY;
463
464 ::SetMapMode(GetHdc(), MM_ANISOTROPIC);
465 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT, VIEWPORT_EXTENT, NULL);
466 ::SetWindowExtEx(GetHdc(), width, height, NULL);
467 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL);
468 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX, (int)m_logicalOriginY, NULL);
469 }
470
471 bool wxDC::DoFloodFill(wxCoord x, wxCoord y, const wxColour& col, int style)
472 {
473 #ifdef __WXMICROWIN__
474 if (!GetHDC()) return FALSE;
475 #endif
476
477 bool success = (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x), YLOG2DEV(y),
478 col.GetPixel(),
479 style == wxFLOOD_SURFACE ? FLOODFILLSURFACE
480 : FLOODFILLBORDER) ) ;
481 if (!success)
482 {
483 // quoting from the MSDN docs:
484 //
485 // Following are some of the reasons this function might fail:
486 //
487 // * The filling could not be completed.
488 // * The specified point has the boundary color specified by the
489 // crColor parameter (if FLOODFILLBORDER was requested).
490 // * The specified point does not have the color specified by
491 // crColor (if FLOODFILLSURFACE was requested)
492 // * The point is outside the clipping region that is, it is not
493 // visible on the device.
494 //
495 wxLogLastError(wxT("ExtFloodFill"));
496 }
497
498 CalcBoundingBox(x, y);
499
500 return success;
501 }
502
503 bool wxDC::DoGetPixel(wxCoord x, wxCoord y, wxColour *col) const
504 {
505 #ifdef __WXMICROWIN__
506 if (!GetHDC()) return FALSE;
507 #endif
508
509 wxCHECK_MSG( col, FALSE, _T("NULL colour parameter in wxDC::GetPixel") );
510
511 // get the color of the pixel
512 COLORREF pixelcolor = ::GetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y));
513
514 wxRGBToColour(*col, pixelcolor);
515
516 return TRUE;
517 }
518
519 void wxDC::DoCrossHair(wxCoord x, wxCoord y)
520 {
521 #ifdef __WXMICROWIN__
522 if (!GetHDC()) return;
523 #endif
524
525 wxCoord x1 = x-VIEWPORT_EXTENT;
526 wxCoord y1 = y-VIEWPORT_EXTENT;
527 wxCoord x2 = x+VIEWPORT_EXTENT;
528 wxCoord y2 = y+VIEWPORT_EXTENT;
529
530 (void)MoveToEx(GetHdc(), XLOG2DEV(x1), YLOG2DEV(y), NULL);
531 (void)LineTo(GetHdc(), XLOG2DEV(x2), YLOG2DEV(y));
532
533 (void)MoveToEx(GetHdc(), XLOG2DEV(x), YLOG2DEV(y1), NULL);
534 (void)LineTo(GetHdc(), XLOG2DEV(x), YLOG2DEV(y2));
535
536 CalcBoundingBox(x1, y1);
537 CalcBoundingBox(x2, y2);
538 }
539
540 void wxDC::DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
541 {
542 #ifdef __WXMICROWIN__
543 if (!GetHDC()) return;
544 #endif
545
546 (void)MoveToEx(GetHdc(), XLOG2DEV(x1), YLOG2DEV(y1), NULL);
547 (void)LineTo(GetHdc(), XLOG2DEV(x2), YLOG2DEV(y2));
548
549 CalcBoundingBox(x1, y1);
550 CalcBoundingBox(x2, y2);
551 }
552
553 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
554 // and ending at (x2, y2)
555 void wxDC::DoDrawArc(wxCoord x1, wxCoord y1,
556 wxCoord x2, wxCoord y2,
557 wxCoord xc, wxCoord yc)
558 {
559 #ifdef __WXMICROWIN__
560 if (!GetHDC()) return;
561 #endif
562
563 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
564
565 double dx = xc - x1;
566 double dy = yc - y1;
567 double radius = (double)sqrt(dx*dx+dy*dy);
568 wxCoord r = (wxCoord)radius;
569
570 // treat the special case of full circle separately
571 if ( x1 == x2 && y1 == y2 )
572 {
573 DrawEllipse(xc - r, yc - r, 2*r, 2*r);
574 return;
575 }
576
577 wxCoord xx1 = XLOG2DEV(x1);
578 wxCoord yy1 = YLOG2DEV(y1);
579 wxCoord xx2 = XLOG2DEV(x2);
580 wxCoord yy2 = YLOG2DEV(y2);
581 wxCoord xxc = XLOG2DEV(xc);
582 wxCoord yyc = YLOG2DEV(yc);
583 wxCoord ray = (wxCoord) sqrt(double((xxc-xx1)*(xxc-xx1)+(yyc-yy1)*(yyc-yy1)));
584
585 wxCoord xxx1 = (wxCoord) (xxc-ray);
586 wxCoord yyy1 = (wxCoord) (yyc-ray);
587 wxCoord xxx2 = (wxCoord) (xxc+ray);
588 wxCoord yyy2 = (wxCoord) (yyc+ray);
589
590 if ( m_brush.Ok() && m_brush.GetStyle() != wxTRANSPARENT )
591 {
592 // Have to add 1 to bottom-right corner of rectangle
593 // to make semi-circles look right (crooked line otherwise).
594 // Unfortunately this is not a reliable method, depends
595 // on the size of shape.
596 // TODO: figure out why this happens!
597 Pie(GetHdc(),xxx1,yyy1,xxx2+1,yyy2+1, xx1,yy1,xx2,yy2);
598 }
599 else
600 {
601 Arc(GetHdc(),xxx1,yyy1,xxx2,yyy2, xx1,yy1,xx2,yy2);
602 }
603
604 CalcBoundingBox(xc - r, yc - r);
605 CalcBoundingBox(xc + r, yc + r);
606 }
607
608 void wxDC::DoDrawCheckMark(wxCoord x1, wxCoord y1,
609 wxCoord width, wxCoord height)
610 {
611 #ifdef __WXMICROWIN__
612 if (!GetHDC()) return;
613 #endif
614
615 wxCoord x2 = x1 + width,
616 y2 = y1 + height;
617
618 #if defined(__WIN32__) && !defined(__SC__) && !defined(__WXMICROWIN__)
619 RECT rect;
620 rect.left = x1;
621 rect.top = y1;
622 rect.right = x2;
623 rect.bottom = y2;
624
625 DrawFrameControl(GetHdc(), &rect, DFC_MENU, DFCS_MENUCHECK);
626 #else // Win16
627 // In WIN16, draw a cross
628 HPEN blackPen = ::CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
629 HPEN whiteBrush = (HPEN)::GetStockObject(WHITE_BRUSH);
630 HPEN hPenOld = (HPEN)::SelectObject(GetHdc(), blackPen);
631 HPEN hBrushOld = (HPEN)::SelectObject(GetHdc(), whiteBrush);
632 ::SetROP2(GetHdc(), R2_COPYPEN);
633 Rectangle(GetHdc(), x1, y1, x2, y2);
634 MoveToEx(GetHdc(), x1, y1, NULL);
635 LineTo(GetHdc(), x2, y2);
636 MoveToEx(GetHdc(), x2, y1, NULL);
637 LineTo(GetHdc(), x1, y2);
638 ::SelectObject(GetHdc(), hPenOld);
639 ::SelectObject(GetHdc(), hBrushOld);
640 ::DeleteObject(blackPen);
641 #endif // Win32/16
642
643 CalcBoundingBox(x1, y1);
644 CalcBoundingBox(x2, y2);
645 }
646
647 void wxDC::DoDrawPoint(wxCoord x, wxCoord y)
648 {
649 #ifdef __WXMICROWIN__
650 if (!GetHDC()) return;
651 #endif
652
653 COLORREF color = 0x00ffffff;
654 if (m_pen.Ok())
655 {
656 color = m_pen.GetColour().GetPixel();
657 }
658
659 SetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), color);
660
661 CalcBoundingBox(x, y);
662 }
663
664 void wxDC::DoDrawPolygon(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset,int fillStyle)
665 {
666 #ifdef __WXMICROWIN__
667 if (!GetHDC()) return;
668 #endif
669
670 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
671
672 // Do things less efficiently if we have offsets
673 if (xoffset != 0 || yoffset != 0)
674 {
675 POINT *cpoints = new POINT[n];
676 int i;
677 for (i = 0; i < n; i++)
678 {
679 cpoints[i].x = (int)(points[i].x + xoffset);
680 cpoints[i].y = (int)(points[i].y + yoffset);
681
682 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
683 }
684 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
685 (void)Polygon(GetHdc(), cpoints, n);
686 SetPolyFillMode(GetHdc(),prev);
687 delete[] cpoints;
688 }
689 else
690 {
691 int i;
692 for (i = 0; i < n; i++)
693 CalcBoundingBox(points[i].x, points[i].y);
694
695 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
696 (void)Polygon(GetHdc(), (POINT*) points, n);
697 SetPolyFillMode(GetHdc(),prev);
698 }
699 }
700
701 void wxDC::DoDrawLines(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset)
702 {
703 #ifdef __WXMICROWIN__
704 if (!GetHDC()) return;
705 #endif
706
707 // Do things less efficiently if we have offsets
708 if (xoffset != 0 || yoffset != 0)
709 {
710 POINT *cpoints = new POINT[n];
711 int i;
712 for (i = 0; i < n; i++)
713 {
714 cpoints[i].x = (int)(points[i].x + xoffset);
715 cpoints[i].y = (int)(points[i].y + yoffset);
716
717 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
718 }
719 (void)Polyline(GetHdc(), cpoints, n);
720 delete[] cpoints;
721 }
722 else
723 {
724 int i;
725 for (i = 0; i < n; i++)
726 CalcBoundingBox(points[i].x, points[i].y);
727
728 (void)Polyline(GetHdc(), (POINT*) points, n);
729 }
730 }
731
732 void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
733 {
734 #ifdef __WXMICROWIN__
735 if (!GetHDC()) return;
736 #endif
737
738 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
739
740 wxCoord x2 = x + width;
741 wxCoord y2 = y + height;
742
743 if ((m_logicalFunction == wxCOPY) && (m_pen.GetStyle() == wxTRANSPARENT))
744 {
745 RECT rect;
746 rect.left = XLOG2DEV(x);
747 rect.top = YLOG2DEV(y);
748 rect.right = XLOG2DEV(x2);
749 rect.bottom = YLOG2DEV(y2);
750 (void)FillRect(GetHdc(), &rect, (HBRUSH)m_brush.GetResourceHandle() );
751 }
752 else
753 {
754 // Windows draws the filled rectangles without outline (i.e. drawn with a
755 // transparent pen) one pixel smaller in both directions and we want them
756 // to have the same size regardless of which pen is used - adjust
757
758 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
759 if ( m_pen.GetStyle() == wxTRANSPARENT )
760 {
761 x2++;
762 y2++;
763 }
764
765 (void)Rectangle(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2));
766 }
767
768
769 CalcBoundingBox(x, y);
770 CalcBoundingBox(x2, y2);
771 }
772
773 void wxDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius)
774 {
775 #ifdef __WXMICROWIN__
776 if (!GetHDC()) return;
777 #endif
778
779 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
780
781 // Now, a negative radius value is interpreted to mean
782 // 'the proportion of the smallest X or Y dimension'
783
784 if (radius < 0.0)
785 {
786 double smallest = 0.0;
787 if (width < height)
788 smallest = width;
789 else
790 smallest = height;
791 radius = (- radius * smallest);
792 }
793
794 wxCoord x2 = (x+width);
795 wxCoord y2 = (y+height);
796
797 // Windows draws the filled rectangles without outline (i.e. drawn with a
798 // transparent pen) one pixel smaller in both directions and we want them
799 // to have the same size regardless of which pen is used - adjust
800 if ( m_pen.GetStyle() == wxTRANSPARENT )
801 {
802 x2++;
803 y2++;
804 }
805
806 (void)RoundRect(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2),
807 YLOG2DEV(y2), (int) (2*XLOG2DEV(radius)), (int)( 2*YLOG2DEV(radius)));
808
809 CalcBoundingBox(x, y);
810 CalcBoundingBox(x2, y2);
811 }
812
813 void wxDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
814 {
815 #ifdef __WXMICROWIN__
816 if (!GetHDC()) return;
817 #endif
818
819 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
820
821 wxCoord x2 = (x+width);
822 wxCoord y2 = (y+height);
823
824 (void)Ellipse(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2));
825
826 CalcBoundingBox(x, y);
827 CalcBoundingBox(x2, y2);
828 }
829
830 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
831 void wxDC::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea)
832 {
833 #ifdef __WXMICROWIN__
834 if (!GetHDC()) return;
835 #endif
836
837 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
838
839 wxCoord x2 = x + w;
840 wxCoord y2 = y + h;
841
842 int rx1 = XLOG2DEV(x+w/2);
843 int ry1 = YLOG2DEV(y+h/2);
844 int rx2 = rx1;
845 int ry2 = ry1;
846
847 sa = DegToRad(sa);
848 ea = DegToRad(ea);
849
850 rx1 += (int)(100.0 * abs(w) * cos(sa));
851 ry1 -= (int)(100.0 * abs(h) * m_signY * sin(sa));
852 rx2 += (int)(100.0 * abs(w) * cos(ea));
853 ry2 -= (int)(100.0 * abs(h) * m_signY * sin(ea));
854
855 // draw pie with NULL_PEN first and then outline otherwise a line is
856 // drawn from the start and end points to the centre
857 HPEN hpenOld = (HPEN) ::SelectObject(GetHdc(), (HPEN) ::GetStockObject(NULL_PEN));
858 if (m_signY > 0)
859 {
860 (void)Pie(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2)+1, YLOG2DEV(y2)+1,
861 rx1, ry1, rx2, ry2);
862 }
863 else
864 {
865 (void)Pie(GetHdc(), XLOG2DEV(x), YLOG2DEV(y)-1, XLOG2DEV(x2)+1, YLOG2DEV(y2),
866 rx1, ry1-1, rx2, ry2-1);
867 }
868
869 ::SelectObject(GetHdc(), hpenOld);
870
871 (void)Arc(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2),
872 rx1, ry1, rx2, ry2);
873
874 CalcBoundingBox(x, y);
875 CalcBoundingBox(x2, y2);
876 }
877
878 void wxDC::DoDrawIcon(const wxIcon& icon, wxCoord x, wxCoord y)
879 {
880 #ifdef __WXMICROWIN__
881 if (!GetHDC()) return;
882 #endif
883
884 wxCHECK_RET( icon.Ok(), wxT("invalid icon in DrawIcon") );
885
886 #ifdef __WIN32__
887 ::DrawIconEx(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), GetHiconOf(icon), icon.GetWidth(), icon.GetHeight(), 0, NULL, DI_NORMAL);
888 #else
889 ::DrawIcon(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), GetHiconOf(icon));
890 #endif
891
892 CalcBoundingBox(x, y);
893 CalcBoundingBox(x + icon.GetWidth(), y + icon.GetHeight());
894 }
895
896 void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask )
897 {
898 #ifdef __WXMICROWIN__
899 if (!GetHDC()) return;
900 #endif
901
902 wxCHECK_RET( bmp.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
903
904 int width = bmp.GetWidth(),
905 height = bmp.GetHeight();
906
907 HBITMAP hbmpMask = 0;
908
909 #if wxUSE_PALETTE
910 HPALETTE oldPal = 0;
911 #endif // wxUSE_PALETTE
912
913 if ( useMask )
914 {
915 wxMask *mask = bmp.GetMask();
916 if ( mask )
917 hbmpMask = (HBITMAP)mask->GetMaskBitmap();
918
919 if ( !hbmpMask )
920 {
921 // don't give assert here because this would break existing
922 // programs - just silently ignore useMask parameter
923 useMask = FALSE;
924 }
925 }
926 if ( useMask )
927 {
928 #ifdef __WIN32__
929 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
930 // points
931 // On some systems, MaskBlt succeeds yet is much much slower
932 // than the wxWindows fall-back implementation. So we need
933 // to be able to switch this on and off at runtime.
934 bool ok = FALSE;
935 #if wxUSE_SYSTEM_OPTIONS
936 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
937 #endif
938 {
939 HDC cdc = GetHdc();
940 HDC hdcMem = ::CreateCompatibleDC(GetHdc());
941 HGDIOBJ hOldBitmap = ::SelectObject(hdcMem, GetHbitmapOf(bmp));
942 #if wxUSE_PALETTE
943 wxPalette *pal = bmp.GetPalette();
944 if ( pal && ::GetDeviceCaps(cdc,BITSPIXEL) <= 8 )
945 {
946 oldPal = ::SelectPalette(hdcMem, GetHpaletteOf(*pal), FALSE);
947 ::RealizePalette(hdcMem);
948 }
949 #endif // wxUSE_PALETTE
950
951 ok = ::MaskBlt(cdc, x, y, width, height,
952 hdcMem, 0, 0,
953 hbmpMask, 0, 0,
954 MAKEROP4(SRCCOPY, DSTCOPY)) != 0;
955
956 #if wxUSE_PALETTE
957 if (oldPal)
958 ::SelectPalette(hdcMem, oldPal, FALSE);
959 #endif // wxUSE_PALETTE
960
961 ::SelectObject(hdcMem, hOldBitmap);
962 ::DeleteDC(hdcMem);
963 }
964
965 if ( !ok )
966 #endif // Win32
967 {
968 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
969 // level
970 wxMemoryDC memDC;
971 memDC.SelectObject(bmp);
972
973 Blit(x, y, width, height, &memDC, 0, 0, wxCOPY, useMask);
974
975 memDC.SelectObject(wxNullBitmap);
976 }
977 }
978 else // no mask, just use BitBlt()
979 {
980 HDC cdc = GetHdc();
981 HDC memdc = ::CreateCompatibleDC( cdc );
982 HBITMAP hbitmap = (HBITMAP) bmp.GetHBITMAP( );
983
984 wxASSERT_MSG( hbitmap, wxT("bitmap is ok but HBITMAP is NULL?") );
985
986 COLORREF old_textground = ::GetTextColor(GetHdc());
987 COLORREF old_background = ::GetBkColor(GetHdc());
988 if (m_textForegroundColour.Ok())
989 {
990 ::SetTextColor(GetHdc(), m_textForegroundColour.GetPixel() );
991 }
992 if (m_textBackgroundColour.Ok())
993 {
994 ::SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() );
995 }
996
997 #if wxUSE_PALETTE
998 wxPalette *pal = bmp.GetPalette();
999 if ( pal && ::GetDeviceCaps(cdc,BITSPIXEL) <= 8 )
1000 {
1001 oldPal = ::SelectPalette(memdc, GetHpaletteOf(*pal), FALSE);
1002 ::RealizePalette(memdc);
1003 }
1004 #endif // wxUSE_PALETTE
1005
1006 HGDIOBJ hOldBitmap = ::SelectObject( memdc, hbitmap );
1007 ::BitBlt( cdc, x, y, width, height, memdc, 0, 0, SRCCOPY);
1008
1009 #if wxUSE_PALETTE
1010 if (oldPal)
1011 ::SelectPalette(memdc, oldPal, FALSE);
1012 #endif // wxUSE_PALETTE
1013
1014 ::SelectObject( memdc, hOldBitmap );
1015 ::DeleteDC( memdc );
1016
1017 ::SetTextColor(GetHdc(), old_textground);
1018 ::SetBkColor(GetHdc(), old_background);
1019 }
1020 }
1021
1022 void wxDC::DoDrawText(const wxString& text, wxCoord x, wxCoord y)
1023 {
1024 #ifdef __WXMICROWIN__
1025 if (!GetHDC()) return;
1026 #endif
1027
1028 DrawAnyText(text, x, y);
1029
1030 // update the bounding box
1031 CalcBoundingBox(x, y);
1032
1033 wxCoord w, h;
1034 GetTextExtent(text, &w, &h);
1035 CalcBoundingBox(x + w, y + h);
1036 }
1037
1038 void wxDC::DrawAnyText(const wxString& text, wxCoord x, wxCoord y)
1039 {
1040 #ifdef __WXMICROWIN__
1041 if (!GetHDC()) return;
1042 #endif
1043
1044 // prepare for drawing the text
1045 if ( m_textForegroundColour.Ok() )
1046 SetTextColor(GetHdc(), m_textForegroundColour.GetPixel());
1047
1048 DWORD old_background = 0;
1049 if ( m_textBackgroundColour.Ok() )
1050 {
1051 old_background = SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() );
1052 }
1053
1054 SetBkMode(GetHdc(), m_backgroundMode == wxTRANSPARENT ? TRANSPARENT
1055 : OPAQUE);
1056
1057 if ( ::TextOut(GetHdc(), XLOG2DEV(x), YLOG2DEV(y),
1058 text.c_str(), text.length()) == 0 )
1059 {
1060 wxLogLastError(wxT("TextOut"));
1061 }
1062
1063 // restore the old parameters (text foreground colour may be left because
1064 // it never is set to anything else, but background should remain
1065 // transparent even if we just drew an opaque string)
1066 if ( m_textBackgroundColour.Ok() )
1067 (void)SetBkColor(GetHdc(), old_background);
1068
1069 SetBkMode(GetHdc(), TRANSPARENT);
1070 }
1071
1072 void wxDC::DoDrawRotatedText(const wxString& text,
1073 wxCoord x, wxCoord y,
1074 double angle)
1075 {
1076 #ifdef __WXMICROWIN__
1077 if (!GetHDC()) return;
1078 #endif
1079
1080 // we test that we have some font because otherwise we should still use the
1081 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1082 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1083 // font for drawing rotated fonts unfortunately)
1084 if ( (angle == 0.0) && m_font.Ok() )
1085 {
1086 DoDrawText(text, x, y);
1087 }
1088 #ifndef __WXMICROWIN__
1089 else
1090 {
1091 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1092 // because it's not TrueType and so can't have non zero
1093 // orientation/escapement under Win9x
1094 wxFont font = m_font.Ok() ? m_font : *wxSWISS_FONT;
1095 HFONT hfont = (HFONT)font.GetResourceHandle();
1096 LOGFONT lf;
1097 if ( ::GetObject(hfont, sizeof(lf), &lf) == 0 )
1098 {
1099 wxLogLastError(wxT("GetObject(hfont)"));
1100 }
1101
1102 // GDI wants the angle in tenth of degree
1103 long angle10 = (long)(angle * 10);
1104 lf.lfEscapement = angle10;
1105 lf. lfOrientation = angle10;
1106
1107 hfont = ::CreateFontIndirect(&lf);
1108 if ( !hfont )
1109 {
1110 wxLogLastError(wxT("CreateFont"));
1111 }
1112 else
1113 {
1114 HFONT hfontOld = (HFONT)::SelectObject(GetHdc(), hfont);
1115
1116 DrawAnyText(text, x, y);
1117
1118 (void)::SelectObject(GetHdc(), hfontOld);
1119 (void)::DeleteObject(hfont);
1120 }
1121
1122 // call the bounding box by adding all four vertices of the rectangle
1123 // containing the text to it (simpler and probably not slower than
1124 // determining which of them is really topmost/leftmost/...)
1125 wxCoord w, h;
1126 GetTextExtent(text, &w, &h);
1127
1128 double rad = DegToRad(angle);
1129
1130 // "upper left" and "upper right"
1131 CalcBoundingBox(x, y);
1132 CalcBoundingBox(x + w*cos(rad), y - h*sin(rad));
1133
1134 // "bottom left" and "bottom right"
1135 x += (wxCoord)(h*sin(rad));
1136 y += (wxCoord)(h*cos(rad));
1137 CalcBoundingBox(x, y);
1138 CalcBoundingBox(x + h*sin(rad), y + h*cos(rad));
1139 }
1140 #endif
1141 }
1142
1143 // ---------------------------------------------------------------------------
1144 // set GDI objects
1145 // ---------------------------------------------------------------------------
1146
1147 #if wxUSE_PALETTE
1148
1149 void wxDC::DoSelectPalette(bool realize)
1150 {
1151 #ifdef __WXMICROWIN__
1152 if (!GetHDC()) return;
1153 #endif
1154
1155 // Set the old object temporarily, in case the assignment deletes an object
1156 // that's not yet selected out.
1157 if (m_oldPalette)
1158 {
1159 ::SelectPalette(GetHdc(), (HPALETTE) m_oldPalette, FALSE);
1160 m_oldPalette = 0;
1161 }
1162
1163 if ( m_palette.Ok() )
1164 {
1165 HPALETTE oldPal = ::SelectPalette(GetHdc(),
1166 GetHpaletteOf(m_palette),
1167 FALSE);
1168 if (!m_oldPalette)
1169 m_oldPalette = (WXHPALETTE) oldPal;
1170
1171 if (realize)
1172 ::RealizePalette(GetHdc());
1173 }
1174 }
1175
1176 void wxDC::SetPalette(const wxPalette& palette)
1177 {
1178 if ( palette.Ok() )
1179 {
1180 m_palette = palette;
1181 DoSelectPalette(TRUE);
1182 }
1183 }
1184
1185 void wxDC::InitializePalette()
1186 {
1187 if ( wxDisplayDepth() <= 8 )
1188 {
1189 // look for any window or parent that has a custom palette. If any has
1190 // one then we need to use it in drawing operations
1191 wxWindow *win = m_canvas->GetAncestorWithCustomPalette();
1192
1193 m_hasCustomPalette = win && win->HasCustomPalette();
1194 if ( m_hasCustomPalette )
1195 {
1196 m_palette = win->GetPalette();
1197
1198 // turn on MSW translation for this palette
1199 DoSelectPalette();
1200 }
1201 }
1202 }
1203
1204 #endif // wxUSE_PALETTE
1205
1206 void wxDC::SetFont(const wxFont& the_font)
1207 {
1208 #ifdef __WXMICROWIN__
1209 if (!GetHDC()) return;
1210 #endif
1211
1212 // Set the old object temporarily, in case the assignment deletes an object
1213 // that's not yet selected out.
1214 if (m_oldFont)
1215 {
1216 ::SelectObject(GetHdc(), (HFONT) m_oldFont);
1217 m_oldFont = 0;
1218 }
1219
1220 m_font = the_font;
1221
1222 if (!the_font.Ok())
1223 {
1224 if (m_oldFont)
1225 ::SelectObject(GetHdc(), (HFONT) m_oldFont);
1226 m_oldFont = 0;
1227 }
1228
1229 if (m_font.Ok() && m_font.GetResourceHandle())
1230 {
1231 HFONT f = (HFONT) ::SelectObject(GetHdc(), (HFONT) m_font.GetResourceHandle());
1232 if (f == (HFONT) NULL)
1233 {
1234 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
1235 }
1236 if (!m_oldFont)
1237 m_oldFont = (WXHFONT) f;
1238 }
1239 }
1240
1241 void wxDC::SetPen(const wxPen& pen)
1242 {
1243 #ifdef __WXMICROWIN__
1244 if (!GetHDC()) return;
1245 #endif
1246
1247 // Set the old object temporarily, in case the assignment deletes an object
1248 // that's not yet selected out.
1249 if (m_oldPen)
1250 {
1251 ::SelectObject(GetHdc(), (HPEN) m_oldPen);
1252 m_oldPen = 0;
1253 }
1254
1255 m_pen = pen;
1256
1257 if (!m_pen.Ok())
1258 {
1259 if (m_oldPen)
1260 ::SelectObject(GetHdc(), (HPEN) m_oldPen);
1261 m_oldPen = 0;
1262 }
1263
1264 if (m_pen.Ok())
1265 {
1266 if (m_pen.GetResourceHandle())
1267 {
1268 HPEN p = (HPEN) ::SelectObject(GetHdc(), (HPEN)m_pen.GetResourceHandle());
1269 if (!m_oldPen)
1270 m_oldPen = (WXHPEN) p;
1271 }
1272 }
1273 }
1274
1275 void wxDC::SetBrush(const wxBrush& brush)
1276 {
1277 #ifdef __WXMICROWIN__
1278 if (!GetHDC()) return;
1279 #endif
1280
1281 // Set the old object temporarily, in case the assignment deletes an object
1282 // that's not yet selected out.
1283 if (m_oldBrush)
1284 {
1285 ::SelectObject(GetHdc(), (HBRUSH) m_oldBrush);
1286 m_oldBrush = 0;
1287 }
1288
1289 m_brush = brush;
1290
1291 if (!m_brush.Ok())
1292 {
1293 if (m_oldBrush)
1294 ::SelectObject(GetHdc(), (HBRUSH) m_oldBrush);
1295 m_oldBrush = 0;
1296 }
1297
1298 if (m_brush.Ok())
1299 {
1300 // to make sure the brush is alligned with the logical coordinates
1301 wxBitmap *stipple = m_brush.GetStipple();
1302 if ( stipple && stipple->Ok() )
1303 {
1304 #ifdef __WIN32__
1305 ::SetBrushOrgEx(GetHdc(),
1306 m_deviceOriginX % stipple->GetWidth(),
1307 m_deviceOriginY % stipple->GetHeight(),
1308 NULL); // don't need previous brush origin
1309 #else
1310 ::SetBrushOrg(GetHdc(),
1311 m_deviceOriginX % stipple->GetWidth(),
1312 m_deviceOriginY % stipple->GetHeight());
1313 #endif
1314 }
1315
1316 if ( m_brush.GetResourceHandle() )
1317 {
1318 HBRUSH b = 0;
1319 b = (HBRUSH) ::SelectObject(GetHdc(), (HBRUSH)m_brush.GetResourceHandle());
1320 if (!m_oldBrush)
1321 m_oldBrush = (WXHBRUSH) b;
1322 }
1323 }
1324 }
1325
1326 void wxDC::SetBackground(const wxBrush& brush)
1327 {
1328 #ifdef __WXMICROWIN__
1329 if (!GetHDC()) return;
1330 #endif
1331
1332 m_backgroundBrush = brush;
1333
1334 if (!m_backgroundBrush.Ok())
1335 return;
1336
1337 if (m_canvas)
1338 {
1339 bool customColours = TRUE;
1340 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
1341 // change background colours from the control-panel specified colours.
1342 if (m_canvas->IsKindOf(CLASSINFO(wxWindow)) && ((m_canvas->GetWindowStyleFlag() & wxUSER_COLOURS) != wxUSER_COLOURS))
1343 customColours = FALSE;
1344
1345 if (customColours)
1346 {
1347 if (m_backgroundBrush.GetStyle()==wxTRANSPARENT)
1348 {
1349 m_canvas->SetTransparent(TRUE);
1350 }
1351 else
1352 {
1353 // New behaviour, 10/2/99: setting the background brush of a DC
1354 // doesn't affect the window background colour. However,
1355 // I'm leaving in the transparency setting because it's needed by
1356 // various controls (e.g. wxStaticText) to determine whether to draw
1357 // transparently or not. TODO: maybe this should be a new function
1358 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
1359 // parent?
1360 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
1361 m_canvas->SetTransparent(FALSE);
1362 }
1363 }
1364 }
1365 COLORREF new_color = m_backgroundBrush.GetColour().GetPixel();
1366 {
1367 (void)SetBkColor(GetHdc(), new_color);
1368 }
1369 }
1370
1371 void wxDC::SetBackgroundMode(int mode)
1372 {
1373 #ifdef __WXMICROWIN__
1374 if (!GetHDC()) return;
1375 #endif
1376
1377 m_backgroundMode = mode;
1378
1379 // SetBackgroundColour now only refers to text background
1380 // and m_backgroundMode is used there
1381 }
1382
1383 void wxDC::SetLogicalFunction(int function)
1384 {
1385 #ifdef __WXMICROWIN__
1386 if (!GetHDC()) return;
1387 #endif
1388
1389 m_logicalFunction = function;
1390
1391 SetRop(m_hDC);
1392 }
1393
1394 void wxDC::SetRop(WXHDC dc)
1395 {
1396 if ( !dc || m_logicalFunction < 0 )
1397 return;
1398
1399 int rop;
1400
1401 switch (m_logicalFunction)
1402 {
1403 case wxCLEAR: rop = R2_BLACK; break;
1404 case wxXOR: rop = R2_XORPEN; break;
1405 case wxINVERT: rop = R2_NOT; break;
1406 case wxOR_REVERSE: rop = R2_MERGEPENNOT; break;
1407 case wxAND_REVERSE: rop = R2_MASKPENNOT; break;
1408 case wxCOPY: rop = R2_COPYPEN; break;
1409 case wxAND: rop = R2_MASKPEN; break;
1410 case wxAND_INVERT: rop = R2_MASKNOTPEN; break;
1411 case wxNO_OP: rop = R2_NOP; break;
1412 case wxNOR: rop = R2_NOTMERGEPEN; break;
1413 case wxEQUIV: rop = R2_NOTXORPEN; break;
1414 case wxSRC_INVERT: rop = R2_NOTCOPYPEN; break;
1415 case wxOR_INVERT: rop = R2_MERGENOTPEN; break;
1416 case wxNAND: rop = R2_NOTMASKPEN; break;
1417 case wxOR: rop = R2_MERGEPEN; break;
1418 case wxSET: rop = R2_WHITE; break;
1419
1420 default:
1421 wxFAIL_MSG( wxT("unsupported logical function") );
1422 return;
1423 }
1424
1425 SetROP2(GetHdc(), rop);
1426 }
1427
1428 bool wxDC::StartDoc(const wxString& WXUNUSED(message))
1429 {
1430 // We might be previewing, so return TRUE to let it continue.
1431 return TRUE;
1432 }
1433
1434 void wxDC::EndDoc()
1435 {
1436 }
1437
1438 void wxDC::StartPage()
1439 {
1440 }
1441
1442 void wxDC::EndPage()
1443 {
1444 }
1445
1446 // ---------------------------------------------------------------------------
1447 // text metrics
1448 // ---------------------------------------------------------------------------
1449
1450 wxCoord wxDC::GetCharHeight() const
1451 {
1452 #ifdef __WXMICROWIN__
1453 if (!GetHDC()) return 0;
1454 #endif
1455
1456 TEXTMETRIC lpTextMetric;
1457
1458 GetTextMetrics(GetHdc(), &lpTextMetric);
1459
1460 return lpTextMetric.tmHeight;
1461 }
1462
1463 wxCoord wxDC::GetCharWidth() const
1464 {
1465 #ifdef __WXMICROWIN__
1466 if (!GetHDC()) return 0;
1467 #endif
1468
1469 TEXTMETRIC lpTextMetric;
1470
1471 GetTextMetrics(GetHdc(), &lpTextMetric);
1472
1473 return lpTextMetric.tmAveCharWidth;
1474 }
1475
1476 void wxDC::DoGetTextExtent(const wxString& string, wxCoord *x, wxCoord *y,
1477 wxCoord *descent, wxCoord *externalLeading,
1478 wxFont *font) const
1479 {
1480 #ifdef __WXMICROWIN__
1481 if (!GetHDC())
1482 {
1483 if (x) *x = 0;
1484 if (y) *y = 0;
1485 if (descent) *descent = 0;
1486 if (externalLeading) *externalLeading = 0;
1487 return;
1488 }
1489 #endif // __WXMICROWIN__
1490
1491 HFONT hfontOld;
1492 if ( font )
1493 {
1494 wxASSERT_MSG( font->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1495
1496 hfontOld = (HFONT)::SelectObject(GetHdc(), GetHfontOf(*font));
1497 }
1498 else // don't change the font
1499 {
1500 hfontOld = 0;
1501 }
1502
1503 SIZE sizeRect;
1504 TEXTMETRIC tm;
1505
1506 GetTextExtentPoint(GetHdc(), string, string.length(), &sizeRect);
1507 GetTextMetrics(GetHdc(), &tm);
1508
1509 if (x)
1510 *x = sizeRect.cx;
1511 if (y)
1512 *y = sizeRect.cy;
1513 if (descent)
1514 *descent = tm.tmDescent;
1515 if (externalLeading)
1516 *externalLeading = tm.tmExternalLeading;
1517
1518 if ( hfontOld )
1519 {
1520 ::SelectObject(GetHdc(), hfontOld);
1521 }
1522 }
1523
1524 void wxDC::SetMapMode(int mode)
1525 {
1526 #ifdef __WXMICROWIN__
1527 if (!GetHDC()) return;
1528 #endif
1529
1530 m_mappingMode = mode;
1531
1532 if ( mode == wxMM_TEXT )
1533 {
1534 m_logicalScaleX =
1535 m_logicalScaleY = 1.0;
1536 }
1537 else // need to do some calculations
1538 {
1539 int pixel_width = ::GetDeviceCaps(GetHdc(), HORZRES),
1540 pixel_height = ::GetDeviceCaps(GetHdc(), VERTRES),
1541 mm_width = ::GetDeviceCaps(GetHdc(), HORZSIZE),
1542 mm_height = ::GetDeviceCaps(GetHdc(), VERTSIZE);
1543
1544 if ( (mm_width == 0) || (mm_height == 0) )
1545 {
1546 // we can't calculate mm2pixels[XY] then!
1547 return;
1548 }
1549
1550 double mm2pixelsX = pixel_width / mm_width,
1551 mm2pixelsY = pixel_height / mm_height;
1552
1553 switch (mode)
1554 {
1555 case wxMM_TWIPS:
1556 m_logicalScaleX = twips2mm * mm2pixelsX;
1557 m_logicalScaleY = twips2mm * mm2pixelsY;
1558 break;
1559
1560 case wxMM_POINTS:
1561 m_logicalScaleX = pt2mm * mm2pixelsX;
1562 m_logicalScaleY = pt2mm * mm2pixelsY;
1563 break;
1564
1565 case wxMM_METRIC:
1566 m_logicalScaleX = mm2pixelsX;
1567 m_logicalScaleY = mm2pixelsY;
1568 break;
1569
1570 case wxMM_LOMETRIC:
1571 m_logicalScaleX = mm2pixelsX / 10.0;
1572 m_logicalScaleY = mm2pixelsY / 10.0;
1573 break;
1574
1575 default:
1576 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1577 }
1578 }
1579
1580 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1581 // cases we could do with MM_TEXT and in the remaining 0.9% with
1582 // MM_ISOTROPIC (TODO!)
1583 ::SetMapMode(GetHdc(), MM_ANISOTROPIC);
1584
1585 int width = DeviceToLogicalXRel(VIEWPORT_EXTENT)*m_signX,
1586 height = DeviceToLogicalYRel(VIEWPORT_EXTENT)*m_signY;
1587
1588 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT, VIEWPORT_EXTENT, NULL);
1589 ::SetWindowExtEx(GetHdc(), width, height, NULL);
1590
1591 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX, m_deviceOriginY, NULL);
1592 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX, m_logicalOriginY, NULL);
1593 }
1594
1595 void wxDC::SetUserScale(double x, double y)
1596 {
1597 #ifdef __WXMICROWIN__
1598 if (!GetHDC()) return;
1599 #endif
1600
1601 if ( x == m_userScaleX && y == m_userScaleY )
1602 return;
1603
1604 m_userScaleX = x;
1605 m_userScaleY = y;
1606
1607 SetMapMode(m_mappingMode);
1608 }
1609
1610 void wxDC::SetAxisOrientation(bool xLeftRight, bool yBottomUp)
1611 {
1612 #ifdef __WXMICROWIN__
1613 if (!GetHDC()) return;
1614 #endif
1615
1616 int signX = xLeftRight ? 1 : -1,
1617 signY = yBottomUp ? -1 : 1;
1618
1619 if ( signX != m_signX || signY != m_signY )
1620 {
1621 m_signX = signX;
1622 m_signY = signY;
1623
1624 SetMapMode(m_mappingMode);
1625 }
1626 }
1627
1628 void wxDC::SetSystemScale(double x, double y)
1629 {
1630 #ifdef __WXMICROWIN__
1631 if (!GetHDC()) return;
1632 #endif
1633
1634 if ( x == m_scaleX && y == m_scaleY )
1635 return;
1636
1637 m_scaleX = x;
1638 m_scaleY = y;
1639
1640 SetMapMode(m_mappingMode);
1641 }
1642
1643 void wxDC::SetLogicalOrigin(wxCoord x, wxCoord y)
1644 {
1645 #ifdef __WXMICROWIN__
1646 if (!GetHDC()) return;
1647 #endif
1648
1649 if ( x == m_logicalOriginX && y == m_logicalOriginY )
1650 return;
1651
1652 m_logicalOriginX = x;
1653 m_logicalOriginY = y;
1654
1655 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX, (int)m_logicalOriginY, NULL);
1656 }
1657
1658 void wxDC::SetDeviceOrigin(wxCoord x, wxCoord y)
1659 {
1660 #ifdef __WXMICROWIN__
1661 if (!GetHDC()) return;
1662 #endif
1663
1664 if ( x == m_deviceOriginX && y == m_deviceOriginY )
1665 return;
1666
1667 m_deviceOriginX = x;
1668 m_deviceOriginY = y;
1669
1670 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL);
1671 }
1672
1673 // ---------------------------------------------------------------------------
1674 // coordinates transformations
1675 // ---------------------------------------------------------------------------
1676
1677 wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
1678 {
1679 return DeviceToLogicalXRel(x - m_deviceOriginX)*m_signX + m_logicalOriginX;
1680 }
1681
1682 wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
1683 {
1684 // axis orientation is not taken into account for conversion of a distance
1685 return (wxCoord)(x / (m_logicalScaleX*m_userScaleX*m_scaleX));
1686 }
1687
1688 wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
1689 {
1690 return DeviceToLogicalYRel(y - m_deviceOriginY)*m_signY + m_logicalOriginY;
1691 }
1692
1693 wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
1694 {
1695 // axis orientation is not taken into account for conversion of a distance
1696 return (wxCoord)( y / (m_logicalScaleY*m_userScaleY*m_scaleY));
1697 }
1698
1699 wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
1700 {
1701 return LogicalToDeviceXRel(x - m_logicalOriginX)*m_signX + m_deviceOriginX;
1702 }
1703
1704 wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
1705 {
1706 // axis orientation is not taken into account for conversion of a distance
1707 return (wxCoord) (x*m_logicalScaleX*m_userScaleX*m_scaleX);
1708 }
1709
1710 wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
1711 {
1712 return LogicalToDeviceYRel(y - m_logicalOriginY)*m_signY + m_deviceOriginY;
1713 }
1714
1715 wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
1716 {
1717 // axis orientation is not taken into account for conversion of a distance
1718 return (wxCoord) (y*m_logicalScaleY*m_userScaleY*m_scaleY);
1719 }
1720
1721 // ---------------------------------------------------------------------------
1722 // bit blit
1723 // ---------------------------------------------------------------------------
1724
1725 bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest,
1726 wxCoord width, wxCoord height,
1727 wxDC *source, wxCoord xsrc, wxCoord ysrc,
1728 int rop, bool useMask,
1729 wxCoord xsrcMask, wxCoord ysrcMask)
1730 {
1731 #ifdef __WXMICROWIN__
1732 if (!GetHDC()) return FALSE;
1733 #endif
1734
1735 wxMask *mask = NULL;
1736 if ( useMask )
1737 {
1738 const wxBitmap& bmp = source->m_selectedBitmap;
1739 mask = bmp.GetMask();
1740
1741 if ( !(bmp.Ok() && mask && mask->GetMaskBitmap()) )
1742 {
1743 // don't give assert here because this would break existing
1744 // programs - just silently ignore useMask parameter
1745 useMask = FALSE;
1746 }
1747 }
1748
1749 if (xsrcMask == -1 && ysrcMask == -1)
1750 {
1751 xsrcMask = xsrc; ysrcMask = ysrc;
1752 }
1753
1754 COLORREF old_textground = ::GetTextColor(GetHdc());
1755 COLORREF old_background = ::GetBkColor(GetHdc());
1756 if (m_textForegroundColour.Ok())
1757 {
1758 ::SetTextColor(GetHdc(), m_textForegroundColour.GetPixel() );
1759 }
1760 if (m_textBackgroundColour.Ok())
1761 {
1762 ::SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() );
1763 }
1764
1765 DWORD dwRop = SRCCOPY;
1766 switch (rop)
1767 {
1768 case wxXOR: dwRop = SRCINVERT; break;
1769 case wxINVERT: dwRop = DSTINVERT; break;
1770 case wxOR_REVERSE: dwRop = 0x00DD0228; break;
1771 case wxAND_REVERSE: dwRop = SRCERASE; break;
1772 case wxCLEAR: dwRop = BLACKNESS; break;
1773 case wxSET: dwRop = WHITENESS; break;
1774 case wxOR_INVERT: dwRop = MERGEPAINT; break;
1775 case wxAND: dwRop = SRCAND; break;
1776 case wxOR: dwRop = SRCPAINT; break;
1777 case wxEQUIV: dwRop = 0x00990066; break;
1778 case wxNAND: dwRop = 0x007700E6; break;
1779 case wxAND_INVERT: dwRop = 0x00220326; break;
1780 case wxCOPY: dwRop = SRCCOPY; break;
1781 case wxNO_OP: dwRop = DSTCOPY; break;
1782 case wxSRC_INVERT: dwRop = NOTSRCCOPY; break;
1783 case wxNOR: dwRop = NOTSRCCOPY; break;
1784 default:
1785 wxFAIL_MSG( wxT("unsupported logical function") );
1786 return FALSE;
1787 }
1788
1789 bool success = FALSE;
1790
1791 if (useMask)
1792 {
1793 #ifdef __WIN32__
1794 // we want the part of the image corresponding to the mask to be
1795 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1796 // meaning of fg and bg is inverted which corresponds to wxWin notion
1797 // of the mask which is also contrary to the Windows one)
1798
1799 // On some systems, MaskBlt succeeds yet is much much slower
1800 // than the wxWindows fall-back implementation. So we need
1801 // to be able to switch this on and off at runtime.
1802 #if wxUSE_SYSTEM_OPTIONS
1803 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1804 #endif
1805 {
1806 success = ::MaskBlt(GetHdc(), xdest, ydest, width, height,
1807 GetHdcOf(*source), xsrc, ysrc,
1808 (HBITMAP)mask->GetMaskBitmap(), xsrcMask, ysrcMask,
1809 MAKEROP4(dwRop, DSTCOPY)) != 0;
1810 }
1811
1812 if ( !success )
1813 #endif // Win32
1814 {
1815 // Blit bitmap with mask
1816 HDC dc_mask ;
1817 HDC dc_buffer ;
1818 HBITMAP buffer_bmap ;
1819
1820 #if wxUSE_DC_CACHEING
1821 // create a temp buffer bitmap and DCs to access it and the mask
1822 wxDCCacheEntry* dcCacheEntry1 = FindDCInCache(NULL, source->GetHDC());
1823 dc_mask = (HDC) dcCacheEntry1->m_dc;
1824
1825 wxDCCacheEntry* dcCacheEntry2 = FindDCInCache(dcCacheEntry1, GetHDC());
1826 dc_buffer = (HDC) dcCacheEntry2->m_dc;
1827
1828 wxDCCacheEntry* bitmapCacheEntry = FindBitmapInCache(GetHDC(),
1829 width, height);
1830
1831 buffer_bmap = (HBITMAP) bitmapCacheEntry->m_bitmap;
1832 #else // !wxUSE_DC_CACHEING
1833 // create a temp buffer bitmap and DCs to access it and the mask
1834 dc_mask = ::CreateCompatibleDC(GetHdcOf(*source));
1835 dc_buffer = ::CreateCompatibleDC(GetHdc());
1836 buffer_bmap = ::CreateCompatibleBitmap(GetHdc(), width, height);
1837 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
1838 HGDIOBJ hOldMaskBitmap = ::SelectObject(dc_mask, (HBITMAP) mask->GetMaskBitmap());
1839 HGDIOBJ hOldBufferBitmap = ::SelectObject(dc_buffer, buffer_bmap);
1840
1841 // copy dest to buffer
1842 if ( !::BitBlt(dc_buffer, 0, 0, (int)width, (int)height,
1843 GetHdc(), xdest, ydest, SRCCOPY) )
1844 {
1845 wxLogLastError(wxT("BitBlt"));
1846 }
1847
1848 // copy src to buffer using selected raster op
1849 if ( !::BitBlt(dc_buffer, 0, 0, (int)width, (int)height,
1850 GetHdcOf(*source), xsrc, ysrc, dwRop) )
1851 {
1852 wxLogLastError(wxT("BitBlt"));
1853 }
1854
1855 // set masked area in buffer to BLACK (pixel value 0)
1856 COLORREF prevBkCol = ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1857 COLORREF prevCol = ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1858 if ( !::BitBlt(dc_buffer, 0, 0, (int)width, (int)height,
1859 dc_mask, xsrcMask, ysrcMask, SRCAND) )
1860 {
1861 wxLogLastError(wxT("BitBlt"));
1862 }
1863
1864 // set unmasked area in dest to BLACK
1865 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1866 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1867 if ( !::BitBlt(GetHdc(), xdest, ydest, (int)width, (int)height,
1868 dc_mask, xsrcMask, ysrcMask, SRCAND) )
1869 {
1870 wxLogLastError(wxT("BitBlt"));
1871 }
1872 ::SetBkColor(GetHdc(), prevBkCol); // restore colours to original values
1873 ::SetTextColor(GetHdc(), prevCol);
1874
1875 // OR buffer to dest
1876 success = ::BitBlt(GetHdc(), xdest, ydest,
1877 (int)width, (int)height,
1878 dc_buffer, 0, 0, SRCPAINT) != 0;
1879 if ( !success )
1880 {
1881 wxLogLastError(wxT("BitBlt"));
1882 }
1883
1884 // tidy up temporary DCs and bitmap
1885 ::SelectObject(dc_mask, hOldMaskBitmap);
1886 ::SelectObject(dc_buffer, hOldBufferBitmap);
1887
1888 #if !wxUSE_DC_CACHEING
1889 {
1890 ::DeleteDC(dc_mask);
1891 ::DeleteDC(dc_buffer);
1892 ::DeleteObject(buffer_bmap);
1893 }
1894 #endif
1895 }
1896 }
1897 else // no mask, just BitBlt() it
1898 {
1899 success = ::BitBlt(GetHdc(), xdest, ydest,
1900 (int)width, (int)height,
1901 GetHdcOf(*source), xsrc, ysrc, dwRop) != 0;
1902 if ( !success )
1903 {
1904 wxLogLastError(wxT("BitBlt"));
1905 }
1906 }
1907 ::SetTextColor(GetHdc(), old_textground);
1908 ::SetBkColor(GetHdc(), old_background);
1909
1910 return success;
1911 }
1912
1913 void wxDC::DoGetSize(int *w, int *h) const
1914 {
1915 #ifdef __WXMICROWIN__
1916 if (!GetHDC()) return;
1917 #endif
1918
1919 if ( w ) *w = ::GetDeviceCaps(GetHdc(), HORZRES);
1920 if ( h ) *h = ::GetDeviceCaps(GetHdc(), VERTRES);
1921 }
1922
1923 void wxDC::DoGetSizeMM(int *w, int *h) const
1924 {
1925 #ifdef __WXMICROWIN__
1926 if (!GetHDC()) return;
1927 #endif
1928
1929 // if we implement it in terms of DoGetSize() instead of directly using the
1930 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
1931 // will also work for wxWindowDC and wxClientDC even though their size is
1932 // not the same as the total size of the screen
1933 int wPixels, hPixels;
1934 DoGetSize(&wPixels, &hPixels);
1935
1936 if ( w )
1937 {
1938 int wTotal = ::GetDeviceCaps(GetHdc(), HORZRES);
1939
1940 wxCHECK_RET( wTotal, _T("0 width device?") );
1941
1942 *w = (wPixels * ::GetDeviceCaps(GetHdc(), HORZSIZE)) / wTotal;
1943 }
1944
1945 if ( h )
1946 {
1947 int hTotal = ::GetDeviceCaps(GetHdc(), VERTRES);
1948
1949 wxCHECK_RET( hTotal, _T("0 height device?") );
1950
1951 *h = (hPixels * ::GetDeviceCaps(GetHdc(), VERTSIZE)) / hTotal;
1952 }
1953 }
1954
1955 wxSize wxDC::GetPPI() const
1956 {
1957 #ifdef __WXMICROWIN__
1958 if (!GetHDC()) return wxSize();
1959 #endif
1960
1961 int x = ::GetDeviceCaps(GetHdc(), LOGPIXELSX);
1962 int y = ::GetDeviceCaps(GetHdc(), LOGPIXELSY);
1963
1964 return wxSize(x, y);
1965 }
1966
1967 // For use by wxWindows only, unless custom units are required.
1968 void wxDC::SetLogicalScale(double x, double y)
1969 {
1970 #ifdef __WXMICROWIN__
1971 if (!GetHDC()) return;
1972 #endif
1973
1974 m_logicalScaleX = x;
1975 m_logicalScaleY = y;
1976 }
1977
1978 #if WXWIN_COMPATIBILITY
1979 void wxDC::DoGetTextExtent(const wxString& string, float *x, float *y,
1980 float *descent, float *externalLeading,
1981 wxFont *theFont, bool use16bit) const
1982 {
1983 #ifdef __WXMICROWIN__
1984 if (!GetHDC()) return;
1985 #endif
1986
1987 wxCoord x1, y1, descent1, externalLeading1;
1988 GetTextExtent(string, & x1, & y1, & descent1, & externalLeading1, theFont, use16bit);
1989 *x = x1; *y = y1;
1990 if (descent)
1991 *descent = descent1;
1992 if (externalLeading)
1993 *externalLeading = externalLeading1;
1994 }
1995 #endif
1996
1997 #if wxUSE_DC_CACHEING
1998
1999 /*
2000 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2001 * improve it in due course, either using arrays, or simply storing pointers to one
2002 * entry for the bitmap, and two for the DCs. -- JACS
2003 */
2004
2005 wxList wxDC::sm_bitmapCache;
2006 wxList wxDC::sm_dcCache;
2007
2008 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap, int w, int h, int depth)
2009 {
2010 m_bitmap = hBitmap;
2011 m_dc = 0;
2012 m_width = w;
2013 m_height = h;
2014 m_depth = depth;
2015 }
2016
2017 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC, int depth)
2018 {
2019 m_bitmap = 0;
2020 m_dc = hDC;
2021 m_width = 0;
2022 m_height = 0;
2023 m_depth = depth;
2024 }
2025
2026 wxDCCacheEntry::~wxDCCacheEntry()
2027 {
2028 if (m_bitmap)
2029 ::DeleteObject((HBITMAP) m_bitmap);
2030 if (m_dc)
2031 ::DeleteDC((HDC) m_dc);
2032 }
2033
2034 wxDCCacheEntry* wxDC::FindBitmapInCache(WXHDC dc, int w, int h)
2035 {
2036 int depth = ::GetDeviceCaps((HDC) dc, PLANES) * ::GetDeviceCaps((HDC) dc, BITSPIXEL);
2037 wxNode* node = sm_bitmapCache.First();
2038 while (node)
2039 {
2040 wxDCCacheEntry* entry = (wxDCCacheEntry*) node->Data();
2041
2042 if (entry->m_depth == depth)
2043 {
2044 if (entry->m_width < w || entry->m_height < h)
2045 {
2046 ::DeleteObject((HBITMAP) entry->m_bitmap);
2047 entry->m_bitmap = (WXHBITMAP) ::CreateCompatibleBitmap((HDC) dc, w, h);
2048 if ( !entry->m_bitmap)
2049 {
2050 wxLogLastError(wxT("CreateCompatibleBitmap"));
2051 }
2052 entry->m_width = w; entry->m_height = h;
2053 return entry;
2054 }
2055 return entry;
2056 }
2057
2058 node = node->Next();
2059 }
2060 WXHBITMAP hBitmap = (WXHBITMAP) ::CreateCompatibleBitmap((HDC) dc, w, h);
2061 if ( !hBitmap)
2062 {
2063 wxLogLastError(wxT("CreateCompatibleBitmap"));
2064 }
2065 wxDCCacheEntry* entry = new wxDCCacheEntry(hBitmap, w, h, depth);
2066 AddToBitmapCache(entry);
2067 return entry;
2068 }
2069
2070 wxDCCacheEntry* wxDC::FindDCInCache(wxDCCacheEntry* notThis, WXHDC dc)
2071 {
2072 int depth = ::GetDeviceCaps((HDC) dc, PLANES) * ::GetDeviceCaps((HDC) dc, BITSPIXEL);
2073 wxNode* node = sm_dcCache.First();
2074 while (node)
2075 {
2076 wxDCCacheEntry* entry = (wxDCCacheEntry*) node->Data();
2077
2078 // Don't return the same one as we already have
2079 if (!notThis || (notThis != entry))
2080 {
2081 if (entry->m_depth == depth)
2082 {
2083 return entry;
2084 }
2085 }
2086
2087 node = node->Next();
2088 }
2089 WXHDC hDC = (WXHDC) ::CreateCompatibleDC((HDC) dc);
2090 if ( !hDC)
2091 {
2092 wxLogLastError(wxT("CreateCompatibleDC"));
2093 }
2094 wxDCCacheEntry* entry = new wxDCCacheEntry(hDC, depth);
2095 AddToDCCache(entry);
2096 return entry;
2097 }
2098
2099 void wxDC::AddToBitmapCache(wxDCCacheEntry* entry)
2100 {
2101 sm_bitmapCache.Append(entry);
2102 }
2103
2104 void wxDC::AddToDCCache(wxDCCacheEntry* entry)
2105 {
2106 sm_dcCache.Append(entry);
2107 }
2108
2109 void wxDC::ClearCache()
2110 {
2111 sm_bitmapCache.DeleteContents(TRUE);
2112 sm_bitmapCache.Clear();
2113 sm_bitmapCache.DeleteContents(FALSE);
2114 sm_dcCache.DeleteContents(TRUE);
2115 sm_dcCache.Clear();
2116 sm_dcCache.DeleteContents(FALSE);
2117 }
2118
2119 // Clean up cache at app exit
2120 class wxDCModule : public wxModule
2121 {
2122 public:
2123 virtual bool OnInit() { return TRUE; }
2124 virtual void OnExit() { wxDC::ClearCache(); }
2125
2126 private:
2127 DECLARE_DYNAMIC_CLASS(wxDCModule)
2128 };
2129
2130 IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule)
2131
2132 #endif
2133 // wxUSE_DC_CACHEING
2134