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