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