]> git.saurik.com Git - wxWidgets.git/blob - src/msw/dc.cpp
Added a wxDataFormat::SetAtom() inline function.
[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/frame.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 #endif
40
41 #include "wx/dcprint.h"
42 #include "wx/msw/private.h"
43
44 #include <string.h>
45 #include <math.h>
46
47 #if wxUSE_COMMON_DIALOGS
48 #include <commdlg.h>
49 #endif
50
51 #ifndef __WIN32__
52 #include <print.h>
53 #endif
54
55 #ifdef DrawText
56 #undef DrawText
57 #endif
58
59 #ifdef GetCharWidth
60 #undef GetCharWidth
61 #endif
62
63 #ifdef StartDoc
64 #undef StartDoc
65 #endif
66
67 #if !USE_SHARED_LIBRARY
68 IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
69 #endif
70
71 // ---------------------------------------------------------------------------
72 // constants
73 // ---------------------------------------------------------------------------
74
75 #define VIEWPORT_EXTENT 1000
76
77 // ---------------------------------------------------------------------------
78 // macros
79 // ---------------------------------------------------------------------------
80
81 #define YSCALE(y) (yorigin - (y))
82
83 // ===========================================================================
84 // implementation
85 // ===========================================================================
86
87 // ---------------------------------------------------------------------------
88 // wxDC
89 // ---------------------------------------------------------------------------
90
91 // Default constructor
92 wxDC::wxDC()
93 {
94 m_canvas = NULL;
95
96 m_oldBitmap = 0;
97 m_oldPen = 0;
98 m_oldBrush = 0;
99 m_oldFont = 0;
100 m_oldPalette = 0;
101
102 m_bOwnsDC = FALSE;
103 m_hDC = 0;
104
105 m_windowExtX = VIEWPORT_EXTENT;
106 m_windowExtY = VIEWPORT_EXTENT;
107
108 m_hDCCount = 0;
109 }
110
111
112 wxDC::~wxDC()
113 {
114 if ( m_hDC != 0 ) {
115 SelectOldObjects(m_hDC);
116 if ( m_bOwnsDC ) {
117 if ( m_canvas == NULL )
118 ::DeleteDC(GetHdc());
119 else
120 ::ReleaseDC((HWND)m_canvas->GetHWND(), GetHdc());
121 }
122 }
123
124 }
125
126 // This will select current objects out of the DC,
127 // which is what you have to do before deleting the
128 // DC.
129 void wxDC::SelectOldObjects(WXHDC dc)
130 {
131 if (dc)
132 {
133 if (m_oldBitmap)
134 {
135 ::SelectObject((HDC) dc, (HBITMAP) m_oldBitmap);
136 if (m_selectedBitmap.Ok())
137 {
138 m_selectedBitmap.SetSelectedInto(NULL);
139 }
140 }
141 m_oldBitmap = 0;
142 if (m_oldPen)
143 {
144 ::SelectObject((HDC) dc, (HPEN) m_oldPen);
145 }
146 m_oldPen = 0;
147 if (m_oldBrush)
148 {
149 ::SelectObject((HDC) dc, (HBRUSH) m_oldBrush);
150 }
151 m_oldBrush = 0;
152 if (m_oldFont)
153 {
154 ::SelectObject((HDC) dc, (HFONT) m_oldFont);
155 }
156 m_oldFont = 0;
157 if (m_oldPalette)
158 {
159 ::SelectPalette((HDC) dc, (HPALETTE) m_oldPalette, TRUE);
160 }
161 m_oldPalette = 0;
162 }
163
164 m_brush = wxNullBrush;
165 m_pen = wxNullPen;
166 m_palette = wxNullPalette;
167 m_font = wxNullFont;
168 m_backgroundBrush = wxNullBrush;
169 m_selectedBitmap = wxNullBitmap;
170 }
171
172 // ---------------------------------------------------------------------------
173 // clipping
174 // ---------------------------------------------------------------------------
175
176 void wxDC::DoSetClippingRegion(long cx, long cy, long cw, long ch)
177 {
178 m_clipping = TRUE;
179 m_clipX1 = (int)cx;
180 m_clipY1 = (int)cy;
181 m_clipX2 = (int)(cx + cw);
182 m_clipY2 = (int)(cy + ch);
183
184 DoClipping((WXHDC) m_hDC);
185 }
186
187 void wxDC::DoSetClippingRegionAsRegion(const wxRegion& region)
188 {
189 wxCHECK_RET( region.GetHRGN(), _T("invalid clipping region") );
190
191 wxRect box = region.GetBox();
192
193 m_clipping = TRUE;
194 m_clipX1 = box.x;
195 m_clipY1 = box.y;
196 m_clipX2 = box.x + box.width;
197 m_clipY2 = box.y + box.height;
198
199 #ifdef __WIN16__
200 SelectClipRgn(GetHdc(), (HRGN) region.GetHRGN());
201 #else
202 ExtSelectClipRgn(GetHdc(), (HRGN) region.GetHRGN(), RGN_AND);
203 #endif
204 }
205
206 void wxDC::DoClipping(WXHDC dc)
207 {
208 if (m_clipping && dc)
209 {
210 IntersectClipRect((HDC) dc, XLOG2DEV(m_clipX1), YLOG2DEV(m_clipY1),
211 XLOG2DEV(m_clipX2), YLOG2DEV(m_clipY2));
212 }
213 }
214
215 void wxDC::DestroyClippingRegion()
216 {
217 if (m_clipping && m_hDC)
218 {
219 // TODO: this should restore the previous clipping region,
220 // so that OnPaint processing works correctly, and the update clipping region
221 // doesn't get destroyed after the first DestroyClippingRegion.
222 HRGN rgn = CreateRectRgn(0, 0, 32000, 32000);
223 SelectClipRgn(GetHdc(), rgn);
224 DeleteObject(rgn);
225 }
226 m_clipping = FALSE;
227 }
228
229 // ---------------------------------------------------------------------------
230 // query capabilities
231 // ---------------------------------------------------------------------------
232
233 bool wxDC::CanDrawBitmap() const
234 {
235 return TRUE;
236 }
237
238 bool wxDC::CanGetTextExtent() const
239 {
240 // What sort of display is it?
241 int technology = ::GetDeviceCaps(GetHdc(), TECHNOLOGY);
242
243 return (technology == DT_RASDISPLAY) || (technology == DT_RASPRINTER);
244 }
245
246 int wxDC::GetDepth() const
247 {
248 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL);
249 }
250
251 // ---------------------------------------------------------------------------
252 // drawing
253 // ---------------------------------------------------------------------------
254
255 void wxDC::Clear()
256 {
257 RECT rect;
258 if (m_canvas)
259 GetClientRect((HWND) m_canvas->GetHWND(), &rect);
260 else if (m_selectedBitmap.Ok())
261 {
262 rect.left = 0; rect.top = 0;
263 rect.right = m_selectedBitmap.GetWidth();
264 rect.bottom = m_selectedBitmap.GetHeight();
265 }
266 (void) ::SetMapMode(GetHdc(), MM_TEXT);
267
268 DWORD colour = GetBkColor(GetHdc());
269 HBRUSH brush = CreateSolidBrush(colour);
270 FillRect(GetHdc(), &rect, brush);
271 DeleteObject(brush);
272
273 ::SetMapMode(GetHdc(), MM_ANISOTROPIC);
274 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT, VIEWPORT_EXTENT, NULL);
275 ::SetWindowExtEx(GetHdc(), m_windowExtX, m_windowExtY, NULL);
276 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL);
277 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX, (int)m_logicalOriginY, NULL);
278 }
279
280 void wxDC::DoFloodFill(long x, long y, const wxColour& col, int style)
281 {
282 (void)ExtFloodFill(GetHdc(), XLOG2DEV(x), YLOG2DEV(y),
283 col.GetPixel(),
284 style == wxFLOOD_SURFACE ? FLOODFILLSURFACE
285 : FLOODFILLBORDER);
286
287 CalcBoundingBox(x, y);
288 }
289
290 bool wxDC::DoGetPixel(long x, long y, wxColour *col) const
291 {
292 // added by steve 29.12.94 (copied from DrawPoint)
293 // returns TRUE for pixels in the color of the current pen
294 // and FALSE for all other pixels colors
295 // if col is non-NULL return the color of the pixel
296
297 // get the color of the pixel
298 COLORREF pixelcolor = ::GetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y));
299 // get the color of the pen
300 COLORREF pencolor = 0x00ffffff;
301 if (m_pen.Ok())
302 {
303 pencolor = m_pen.GetColour().GetPixel();
304 }
305
306 // return the color of the pixel
307 if(col)
308 col->Set(GetRValue(pixelcolor),GetGValue(pixelcolor),GetBValue(pixelcolor));
309
310 // check, if color of the pixels is the same as the color
311 // of the current pen
312 return(pixelcolor==pencolor);
313 }
314
315 void wxDC::DoCrossHair(long x, long y)
316 {
317 long x1 = x-VIEWPORT_EXTENT;
318 long y1 = y-VIEWPORT_EXTENT;
319 long x2 = x+VIEWPORT_EXTENT;
320 long y2 = y+VIEWPORT_EXTENT;
321
322 (void)MoveToEx(GetHdc(), XLOG2DEV(x1), YLOG2DEV(y), NULL);
323 (void)LineTo(GetHdc(), XLOG2DEV(x2), YLOG2DEV(y));
324
325 (void)MoveToEx(GetHdc(), XLOG2DEV(x), YLOG2DEV(y1), NULL);
326 (void)LineTo(GetHdc(), XLOG2DEV(x), YLOG2DEV(y2));
327
328 CalcBoundingBox(x1, y1);
329 CalcBoundingBox(x2, y2);
330 }
331
332 void wxDC::DoDrawLine(long x1, long y1, long x2, long y2)
333 {
334 (void)MoveToEx(GetHdc(), XLOG2DEV(x1), YLOG2DEV(y1), NULL);
335 (void)LineTo(GetHdc(), XLOG2DEV(x2), YLOG2DEV(y2));
336
337 /* MATTHEW: [6] New normalization */
338 #if WX_STANDARD_GRAPHICS
339 (void)LineTo(GetHdc(), XLOG2DEV(x2) + 1, YLOG2DEV(y2));
340 #endif
341
342 CalcBoundingBox(x1, y1);
343 CalcBoundingBox(x2, y2);
344 }
345
346 void wxDC::DoDrawArc(long x1,long y1,long x2,long y2, long xc, long yc)
347 {
348 double dx = xc-x1;
349 double dy = yc-y1;
350 double radius = (double)sqrt(dx*dx+dy*dy) ;;
351 if (x1==x2 && x2==y2)
352 {
353 DrawEllipse(xc,yc,(long)(radius*2.0),(long)(radius*2.0));
354 return;
355 }
356
357 long xx1 = XLOG2DEV(x1);
358 long yy1 = YLOG2DEV(y1);
359 long xx2 = XLOG2DEV(x2);
360 long yy2 = YLOG2DEV(y2);
361 long xxc = XLOG2DEV(xc);
362 long yyc = YLOG2DEV(yc);
363 long ray = (long) sqrt(double((xxc-xx1)*(xxc-xx1)+(yyc-yy1)*(yyc-yy1)));
364
365 (void)MoveToEx(GetHdc(), (int) xx1, (int) yy1, NULL);
366 long xxx1 = (long) (xxc-ray);
367 long yyy1 = (long) (yyc-ray);
368 long xxx2 = (long) (xxc+ray);
369 long yyy2 = (long) (yyc+ray);
370 if (m_brush.Ok() && m_brush.GetStyle() !=wxTRANSPARENT)
371 {
372 // Have to add 1 to bottom-right corner of rectangle
373 // to make semi-circles look right (crooked line otherwise).
374 // Unfortunately this is not a reliable method, depends
375 // on the size of shape.
376 // TODO: figure out why this happens!
377 Pie(GetHdc(),xxx1,yyy1,xxx2+1,yyy2+1,
378 xx1,yy1,xx2,yy2);
379 }
380 else
381 Arc(GetHdc(),xxx1,yyy1,xxx2,yyy2,
382 xx1,yy1,xx2,yy2);
383
384 CalcBoundingBox((xc-radius), (yc-radius));
385 CalcBoundingBox((xc+radius), (yc+radius));
386 }
387
388 void wxDC::DoDrawPoint(long x, long y)
389 {
390 COLORREF color = 0x00ffffff;
391 if (m_pen.Ok())
392 {
393 color = m_pen.GetColour().GetPixel();
394 }
395
396 SetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), color);
397
398 CalcBoundingBox(x, y);
399 }
400
401 void wxDC::DoDrawPolygon(int n, wxPoint points[], long xoffset, long yoffset,int fillStyle)
402 {
403 // Do things less efficiently if we have offsets
404 if (xoffset != 0 || yoffset != 0)
405 {
406 POINT *cpoints = new POINT[n];
407 int i;
408 for (i = 0; i < n; i++)
409 {
410 cpoints[i].x = (int)(points[i].x + xoffset);
411 cpoints[i].y = (int)(points[i].y + yoffset);
412
413 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
414 }
415 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
416 (void)Polygon(GetHdc(), cpoints, n);
417 SetPolyFillMode(GetHdc(),prev);
418 delete[] cpoints;
419 }
420 else
421 {
422 int i;
423 for (i = 0; i < n; i++)
424 CalcBoundingBox(points[i].x, points[i].y);
425
426 int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
427 (void)Polygon(GetHdc(), (POINT*) points, n);
428 SetPolyFillMode(GetHdc(),prev);
429 }
430 }
431
432 void wxDC::DoDrawLines(int n, wxPoint points[], long xoffset, long yoffset)
433 {
434 // Do things less efficiently if we have offsets
435 if (xoffset != 0 || yoffset != 0)
436 {
437 POINT *cpoints = new POINT[n];
438 int i;
439 for (i = 0; i < n; i++)
440 {
441 cpoints[i].x = (int)(points[i].x + xoffset);
442 cpoints[i].y = (int)(points[i].y + yoffset);
443
444 CalcBoundingBox(cpoints[i].x, cpoints[i].y);
445 }
446 (void)Polyline(GetHdc(), cpoints, n);
447 delete[] cpoints;
448 }
449 else
450 {
451 int i;
452 for (i = 0; i < n; i++)
453 CalcBoundingBox(points[i].x, points[i].y);
454
455 (void)Polyline(GetHdc(), (POINT*) points, n);
456 }
457 }
458
459 void wxDC::DoDrawRectangle(long x, long y, long width, long height)
460 {
461 long x2 = x + width;
462 long y2 = y + height;
463
464 /* MATTHEW: [6] new normalization */
465 #if WX_STANDARD_GRAPHICS
466 bool do_brush, do_pen;
467
468 do_brush = m_brush.Ok() && m_brush.GetStyle() != wxTRANSPARENT;
469 do_pen = m_pen.Ok() && m_pen.GetStyle() != wxTRANSPARENT;
470
471 if (do_brush) {
472 HPEN orig_pen = NULL;
473
474 if (do_pen || !m_pen.Ok())
475 orig_pen = (HPEN) ::SelectObject(GetHdc(), (HPEN) ::GetStockObject(NULL_PEN));
476
477 (void)Rectangle(GetHdc(), XLOG2DEV(x), YLOG2DEV(y),
478 XLOG2DEV(x2) + 1, YLOG2DEV(y2) + 1);
479
480 if (do_pen || !m_pen.Ok())
481 ::SelectObject(GetHdc() , orig_pen);
482 }
483 if (do_pen) {
484 HBRUSH orig_brush = NULL;
485
486 if (do_brush || !m_brush.Ok())
487 orig_brush = (HBRUSH) ::SelectObject(GetHdc(), (HBRUSH) ::GetStockObject(NULL_BRUSH));
488
489 (void)Rectangle(GetHdc(), XLOG2DEV(x), YLOG2DEV(y),
490 XLOG2DEV(x2), YLOG2DEV(y2));
491
492 if (do_brush || !m_brush.Ok())
493 ::SelectObject(GetHdc(), orig_brush);
494 }
495 #else
496 (void)Rectangle(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2));
497 #endif
498
499 CalcBoundingBox(x, y);
500 CalcBoundingBox(x2, y2);
501 }
502
503 void wxDC::DoDrawRoundedRectangle(long x, long y, long width, long height, double radius)
504 {
505 // Now, a negative radius value is interpreted to mean
506 // 'the proportion of the smallest X or Y dimension'
507
508 if (radius < 0.0)
509 {
510 double smallest = 0.0;
511 if (width < height)
512 smallest = width;
513 else
514 smallest = height;
515 radius = (- radius * smallest);
516 }
517
518 long x2 = (x+width);
519 long y2 = (y+height);
520
521 (void)RoundRect(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2),
522 YLOG2DEV(y2), 2*XLOG2DEV(radius), 2*YLOG2DEV(radius));
523
524 CalcBoundingBox(x, y);
525 CalcBoundingBox(x2, y2);
526 }
527
528 void wxDC::DoDrawEllipse(long x, long y, long width, long height)
529 {
530 long x2 = (x+width);
531 long y2 = (y+height);
532
533 (void)Ellipse(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2));
534
535 CalcBoundingBox(x, y);
536 CalcBoundingBox(x2, y2);
537 }
538
539 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
540 void wxDC::DoDrawEllipticArc(long x,long y,long w,long h,double sa,double ea)
541 {
542 long x2 = (x+w);
543 long y2 = (y+h);
544
545 const double deg2rad = 3.14159265359 / 180.0;
546 int rx1 = XLOG2DEV(x+w/2);
547 int ry1 = YLOG2DEV(y+h/2);
548 int rx2 = rx1;
549 int ry2 = ry1;
550 rx1 += (int)(100.0 * abs(w) * cos(sa * deg2rad));
551 ry1 -= (int)(100.0 * abs(h) * m_signY * sin(sa * deg2rad));
552 rx2 += (int)(100.0 * abs(w) * cos(ea * deg2rad));
553 ry2 -= (int)(100.0 * abs(h) * m_signY * sin(ea * deg2rad));
554
555 // draw pie with NULL_PEN first and then outline otherwise a line is
556 // drawn from the start and end points to the centre
557 HPEN orig_pen = (HPEN) ::SelectObject(GetHdc(), (HPEN) ::GetStockObject(NULL_PEN));
558 if (m_signY > 0)
559 {
560 (void)Pie(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2)+1, YLOG2DEV(y2)+1,
561 rx1, ry1, rx2, ry2);
562 }
563 else
564 {
565 (void)Pie(GetHdc(), XLOG2DEV(x), YLOG2DEV(y)-1, XLOG2DEV(x2)+1, YLOG2DEV(y2),
566 rx1, ry1-1, rx2, ry2-1);
567 }
568 ::SelectObject(GetHdc(), orig_pen);
569 (void)Arc(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2),
570 rx1, ry1, rx2, ry2);
571
572 CalcBoundingBox(x, y);
573 CalcBoundingBox(x2, y2);
574 }
575
576 void wxDC::DoDrawIcon(const wxIcon& icon, long x, long y)
577 {
578 #if defined(__WIN32__) && !defined(__SC__) && !defined(__TWIN32__)
579 ::DrawIconEx(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), (HICON) icon.GetHICON(),
580 icon.GetWidth(), icon.GetHeight(), 0, 0, DI_NORMAL);
581 #else
582 ::DrawIcon(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), (HICON) icon.GetHICON());
583 #endif
584
585 CalcBoundingBox(x, y);
586 CalcBoundingBox(x+icon.GetWidth(), y+icon.GetHeight());
587 }
588
589 void wxDC::DoDrawBitmap( const wxBitmap &bmp, long x, long y, bool useMask )
590 {
591 if (!bmp.Ok())
592 return;
593
594 // If we're not drawing transparently, and not drawing to a printer,
595 // optimize this function to use Windows functions.
596 if (!useMask && !IsKindOf(CLASSINFO(wxPrinterDC)))
597 {
598 HDC cdc = GetHdc();
599 HDC memdc = ::CreateCompatibleDC( cdc );
600 HBITMAP hbitmap = (HBITMAP) bmp.GetHBITMAP( );
601 ::SelectObject( memdc, hbitmap );
602 ::BitBlt( cdc, x, y, bmp.GetWidth(), bmp.GetHeight(), memdc, 0, 0, SRCCOPY);
603 ::SelectObject( memdc, 0 );
604 ::DeleteDC( memdc );
605 }
606 else
607 {
608 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API level
609 wxMemoryDC memDC;
610 memDC.SelectObject(bmp);
611
612 /* Not sure if we need this. The mask should leave the
613 * masked areas as per the original background of this DC.
614 */
615 /*
616 // There might be transparent areas, so make these
617 // the same colour as this DC
618 memDC.SetBackground(* GetBackground());
619 memDC.Clear();
620 */
621
622 Blit(x, y, bmp.GetWidth(), bmp.GetHeight(), & memDC, 0, 0, wxCOPY, useMask);
623
624 memDC.SelectObject(wxNullBitmap);
625 }
626 }
627
628 void wxDC::DoDrawText(const wxString& text, long x, long y)
629 {
630 if (m_textForegroundColour.Ok())
631 SetTextColor(GetHdc(), m_textForegroundColour.GetPixel() );
632
633 DWORD old_background = 0;
634 if (m_textBackgroundColour.Ok())
635 {
636 old_background = SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() );
637 }
638
639 if (m_backgroundMode == wxTRANSPARENT)
640 SetBkMode(GetHdc(), TRANSPARENT);
641 else
642 SetBkMode(GetHdc(), OPAQUE);
643
644 (void)TextOut(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), (char *) (const char *)text, strlen((const char *)text));
645
646 if (m_textBackgroundColour.Ok())
647 (void)SetBkColor(GetHdc(), old_background);
648
649 CalcBoundingBox(x, y);
650
651 long w, h;
652 GetTextExtent(text, &w, &h);
653 CalcBoundingBox((x + w), (y + h));
654 }
655
656 // ---------------------------------------------------------------------------
657 // set GDI objects
658 // ---------------------------------------------------------------------------
659
660 void wxDC::SetPalette(const wxPalette& palette)
661 {
662 // Set the old object temporarily, in case the assignment deletes an object
663 // that's not yet selected out.
664 if (m_oldPalette)
665 {
666 ::SelectPalette(GetHdc(), (HPALETTE) m_oldPalette, TRUE);
667 m_oldPalette = 0;
668 }
669
670 m_palette = palette;
671
672 if (!m_palette.Ok())
673 {
674 // Setting a NULL colourmap is a way of restoring
675 // the original colourmap
676 if (m_oldPalette)
677 {
678 ::SelectPalette(GetHdc(), (HPALETTE) m_oldPalette, TRUE);
679 m_oldPalette = 0;
680 }
681
682 return;
683 }
684
685 if (m_palette.Ok() && m_palette.GetHPALETTE())
686 {
687 HPALETTE oldPal = ::SelectPalette(GetHdc(), (HPALETTE) m_palette.GetHPALETTE(), TRUE);
688 if (!m_oldPalette)
689 m_oldPalette = (WXHPALETTE) oldPal;
690
691 ::RealizePalette(GetHdc());
692 }
693 }
694
695 void wxDC::SetFont(const wxFont& the_font)
696 {
697 // Set the old object temporarily, in case the assignment deletes an object
698 // that's not yet selected out.
699 if (m_oldFont)
700 {
701 ::SelectObject(GetHdc(), (HFONT) m_oldFont);
702 m_oldFont = 0;
703 }
704
705 m_font = the_font;
706
707 if (!the_font.Ok())
708 {
709 if (m_oldFont)
710 ::SelectObject(GetHdc(), (HFONT) m_oldFont);
711 m_oldFont = 0;
712 }
713
714 if (m_font.Ok() && m_font.GetResourceHandle())
715 {
716 HFONT f = (HFONT) ::SelectObject(GetHdc(), (HFONT) m_font.GetResourceHandle());
717 if (f == (HFONT) NULL)
718 {
719 wxLogDebug("::SelectObject failed in wxDC::SetFont.");
720 }
721 if (!m_oldFont)
722 m_oldFont = (WXHFONT) f;
723 }
724 }
725
726 void wxDC::SetPen(const wxPen& pen)
727 {
728 // Set the old object temporarily, in case the assignment deletes an object
729 // that's not yet selected out.
730 if (m_oldPen)
731 {
732 ::SelectObject(GetHdc(), (HPEN) m_oldPen);
733 m_oldPen = 0;
734 }
735
736 m_pen = pen;
737
738 if (!m_pen.Ok())
739 {
740 if (m_oldPen)
741 ::SelectObject(GetHdc(), (HPEN) m_oldPen);
742 m_oldPen = 0;
743 }
744
745 if (m_pen.Ok())
746 {
747 if (m_pen.GetResourceHandle())
748 {
749 HPEN p = (HPEN) ::SelectObject(GetHdc(), (HPEN)m_pen.GetResourceHandle());
750 if (!m_oldPen)
751 m_oldPen = (WXHPEN) p;
752 }
753 }
754 }
755
756 void wxDC::SetBrush(const wxBrush& brush)
757 {
758 // Set the old object temporarily, in case the assignment deletes an object
759 // that's not yet selected out.
760 if (m_oldBrush)
761 {
762 ::SelectObject(GetHdc(), (HBRUSH) m_oldBrush);
763 m_oldBrush = 0;
764 }
765
766 m_brush = brush;
767
768 if (!m_brush.Ok())
769 {
770 if (m_oldBrush)
771 ::SelectObject(GetHdc(), (HBRUSH) m_oldBrush);
772 m_oldBrush = 0;
773 }
774
775 if (m_brush.Ok())
776 {
777 if (m_brush.GetResourceHandle())
778 {
779 HBRUSH b = 0;
780 b = (HBRUSH) ::SelectObject(GetHdc(), (HBRUSH)m_brush.GetResourceHandle());
781 if (!m_oldBrush)
782 m_oldBrush = (WXHBRUSH) b;
783 }
784 }
785 }
786
787 void wxDC::SetBackground(const wxBrush& brush)
788 {
789 m_backgroundBrush = brush;
790
791 if (!m_backgroundBrush.Ok())
792 return;
793
794 if (m_canvas)
795 {
796 bool customColours = TRUE;
797 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
798 // change background colours from the control-panel specified colours.
799 if (m_canvas->IsKindOf(CLASSINFO(wxWindow)) && ((m_canvas->GetWindowStyleFlag() & wxUSER_COLOURS) != wxUSER_COLOURS))
800 customColours = FALSE;
801
802 if (customColours)
803 {
804 if (m_backgroundBrush.GetStyle()==wxTRANSPARENT)
805 {
806 m_canvas->SetTransparent(TRUE);
807 }
808 else
809 {
810 // New behaviour, 10/2/99: setting the background brush of a DC
811 // doesn't affect the window background colour. However,
812 // I'm leaving in the transparency setting because it's needed by
813 // various controls (e.g. wxStaticText) to determine whether to draw
814 // transparently or not. TODO: maybe this should be a new function
815 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
816 // parent?
817 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
818 m_canvas->SetTransparent(FALSE);
819 }
820 }
821 }
822 COLORREF new_color = m_backgroundBrush.GetColour().GetPixel();
823 {
824 (void)SetBkColor(GetHdc(), new_color);
825 }
826 }
827
828 void wxDC::SetBackgroundMode(int mode)
829 {
830 m_backgroundMode = mode;
831
832 if (m_backgroundMode == wxTRANSPARENT)
833 ::SetBkMode(GetHdc(), TRANSPARENT);
834 else
835 ::SetBkMode(GetHdc(), OPAQUE);
836 }
837
838 void wxDC::SetLogicalFunction(int function)
839 {
840 m_logicalFunction = function;
841
842 SetRop((WXHDC) m_hDC);
843 }
844
845 void wxDC::SetRop(WXHDC dc)
846 {
847 if (!dc || m_logicalFunction < 0)
848 return;
849
850 int c_rop;
851 // These may be wrong
852 switch (m_logicalFunction)
853 {
854 // case wxXOR: c_rop = R2_XORPEN; break;
855 case wxXOR: c_rop = R2_NOTXORPEN; break;
856 case wxINVERT: c_rop = R2_NOT; break;
857 case wxOR_REVERSE: c_rop = R2_MERGEPENNOT; break;
858 case wxAND_REVERSE: c_rop = R2_MASKPENNOT; break;
859 case wxCLEAR: c_rop = R2_WHITE; break;
860 case wxSET: c_rop = R2_BLACK; break;
861 case wxSRC_INVERT: c_rop = R2_NOTCOPYPEN; break;
862 case wxOR_INVERT: c_rop = R2_MERGENOTPEN; break;
863 case wxAND: c_rop = R2_MASKPEN; break;
864 case wxOR: c_rop = R2_MERGEPEN; break;
865 case wxAND_INVERT: c_rop = R2_MASKNOTPEN; break;
866 case wxEQUIV:
867 case wxNAND:
868 case wxCOPY:
869 default:
870 c_rop = R2_COPYPEN; break;
871 }
872 SetROP2((HDC) dc, c_rop);
873 }
874
875 bool wxDC::StartDoc(const wxString& message)
876 {
877 // We might be previewing, so return TRUE to let it continue.
878 return TRUE;
879 }
880
881 void wxDC::EndDoc()
882 {
883 }
884
885 void wxDC::StartPage()
886 {
887 }
888
889 void wxDC::EndPage()
890 {
891 }
892
893 // ---------------------------------------------------------------------------
894 // text metrics
895 // ---------------------------------------------------------------------------
896
897 long wxDC::GetCharHeight() const
898 {
899 TEXTMETRIC lpTextMetric;
900
901 GetTextMetrics(GetHdc(), &lpTextMetric);
902
903 return YDEV2LOGREL(lpTextMetric.tmHeight);
904 }
905
906 long wxDC::GetCharWidth() const
907 {
908 TEXTMETRIC lpTextMetric;
909
910 GetTextMetrics(GetHdc(), &lpTextMetric);
911
912 return XDEV2LOGREL(lpTextMetric.tmAveCharWidth);
913 }
914
915 void wxDC::GetTextExtent(const wxString& string, long *x, long *y,
916 long *descent, long *externalLeading,
917 wxFont *theFont) const
918 {
919 wxFont *fontToUse = (wxFont*) theFont;
920 if (!fontToUse)
921 fontToUse = (wxFont*) &m_font;
922
923 SIZE sizeRect;
924 TEXTMETRIC tm;
925
926 GetTextExtentPoint(GetHdc(), (char *)(const char *) string, strlen((char *)(const char *) string), &sizeRect);
927 GetTextMetrics(GetHdc(), &tm);
928
929 if (x) *x = XDEV2LOGREL(sizeRect.cx);
930 if (y) *y = YDEV2LOGREL(sizeRect.cy);
931 if (descent) *descent = tm.tmDescent;
932 if (externalLeading) *externalLeading = tm.tmExternalLeading;
933 }
934
935 void wxDC::SetMapMode(int mode)
936 {
937 m_mappingMode = mode;
938
939 int pixel_width = 0;
940 int pixel_height = 0;
941 int mm_width = 0;
942 int mm_height = 0;
943
944 pixel_width = GetDeviceCaps(GetHdc(), HORZRES);
945 pixel_height = GetDeviceCaps(GetHdc(), VERTRES);
946 mm_width = GetDeviceCaps(GetHdc(), HORZSIZE);
947 mm_height = GetDeviceCaps(GetHdc(), VERTSIZE);
948
949 if ((pixel_width == 0) || (pixel_height == 0) || (mm_width == 0) || (mm_height == 0))
950 {
951 return;
952 }
953
954 double mm2pixelsX = pixel_width/mm_width;
955 double mm2pixelsY = pixel_height/mm_height;
956
957 switch (mode)
958 {
959 case wxMM_TWIPS:
960 {
961 m_logicalScaleX = (twips2mm * mm2pixelsX);
962 m_logicalScaleY = (twips2mm * mm2pixelsY);
963 break;
964 }
965 case wxMM_POINTS:
966 {
967 m_logicalScaleX = (pt2mm * mm2pixelsX);
968 m_logicalScaleY = (pt2mm * mm2pixelsY);
969 break;
970 }
971 case wxMM_METRIC:
972 {
973 m_logicalScaleX = mm2pixelsX;
974 m_logicalScaleY = mm2pixelsY;
975 break;
976 }
977 case wxMM_LOMETRIC:
978 {
979 m_logicalScaleX = (mm2pixelsX/10.0);
980 m_logicalScaleY = (mm2pixelsY/10.0);
981 break;
982 }
983 default:
984 case wxMM_TEXT:
985 {
986 m_logicalScaleX = 1.0;
987 m_logicalScaleY = 1.0;
988 break;
989 }
990 }
991
992 if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC)
993 ::SetMapMode(GetHdc(), MM_ANISOTROPIC);
994
995 SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT, VIEWPORT_EXTENT, NULL);
996 m_windowExtX = (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT);
997 m_windowExtY = (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT);
998 ::SetWindowExtEx(GetHdc(), m_windowExtX, m_windowExtY, NULL);
999 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL);
1000 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX, (int)m_logicalOriginY, NULL);
1001 }
1002
1003 void wxDC::SetUserScale(double x, double y)
1004 {
1005 m_userScaleX = x;
1006 m_userScaleY = y;
1007
1008 SetMapMode(m_mappingMode);
1009 }
1010
1011 void wxDC::SetAxisOrientation(bool xLeftRight, bool yBottomUp)
1012 {
1013 m_signX = xLeftRight ? 1 : -1;
1014 m_signY = yBottomUp ? -1 : 1;
1015
1016 SetMapMode(m_mappingMode);
1017 }
1018
1019 void wxDC::SetSystemScale(double x, double y)
1020 {
1021 m_scaleX = x;
1022 m_scaleY = y;
1023
1024 SetMapMode(m_mappingMode);
1025 }
1026
1027 void wxDC::SetLogicalOrigin(long x, long y)
1028 {
1029 m_logicalOriginX = x;
1030 m_logicalOriginY = y;
1031
1032 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX, (int)m_logicalOriginY, NULL);
1033 }
1034
1035 void wxDC::SetDeviceOrigin(long x, long y)
1036 {
1037 m_deviceOriginX = x;
1038 m_deviceOriginY = y;
1039
1040 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL);
1041 }
1042
1043 // ---------------------------------------------------------------------------
1044 // coordinates transformations
1045 // ---------------------------------------------------------------------------
1046
1047 long wxDCBase::DeviceToLogicalX(long x) const
1048 {
1049 return (long) (((x) - m_deviceOriginX)/(m_logicalScaleX*m_userScaleX*m_signX*m_scaleX) - m_logicalOriginX);
1050 }
1051
1052 long wxDCBase::DeviceToLogicalXRel(long x) const
1053 {
1054 return (long) ((x)/(m_logicalScaleX*m_userScaleX*m_signX*m_scaleX));
1055 }
1056
1057 long wxDCBase::DeviceToLogicalY(long y) const
1058 {
1059 return (long) (((y) - m_deviceOriginY)/(m_logicalScaleY*m_userScaleY*m_signY*m_scaleY) - m_logicalOriginY);
1060 }
1061
1062 long wxDCBase::DeviceToLogicalYRel(long y) const
1063 {
1064 return (long) ((y)/(m_logicalScaleY*m_userScaleY*m_signY*m_scaleY));
1065 }
1066
1067 long wxDCBase::LogicalToDeviceX(long x) const
1068 {
1069 return (long) (floor((x) - m_logicalOriginX)*m_logicalScaleX*m_userScaleX*m_signX*m_scaleX + m_deviceOriginX);
1070 }
1071
1072 long wxDCBase::LogicalToDeviceXRel(long x) const
1073 {
1074 return (long) (floor(x)*m_logicalScaleX*m_userScaleX*m_signX*m_scaleX);
1075 }
1076
1077 long wxDCBase::LogicalToDeviceY(long y) const
1078 {
1079 return (long) (floor((y) - m_logicalOriginY)*m_logicalScaleY*m_userScaleY*m_signY*m_scaleY + m_deviceOriginY);
1080 }
1081
1082 long wxDCBase::LogicalToDeviceYRel(long y) const
1083 {
1084 return (long) (floor(y)*m_logicalScaleY*m_userScaleY*m_signY*m_scaleY);
1085 }
1086
1087 // ---------------------------------------------------------------------------
1088 // bit blit
1089 // ---------------------------------------------------------------------------
1090 bool wxDC::DoBlit(long xdest, long ydest, long width, long height,
1091 wxDC *source, long xsrc, long ysrc, int rop, bool useMask)
1092 {
1093 long xdest1 = xdest;
1094 long ydest1 = ydest;
1095 long xsrc1 = xsrc;
1096 long ysrc1 = ysrc;
1097
1098 // Chris Breeze 18/5/98: use text foreground/background colours
1099 // when blitting from 1-bit bitmaps
1100 COLORREF old_textground = ::GetTextColor(GetHdc());
1101 COLORREF old_background = ::GetBkColor(GetHdc());
1102 if (m_textForegroundColour.Ok())
1103 {
1104 ::SetTextColor(GetHdc(), m_textForegroundColour.GetPixel() );
1105 }
1106 if (m_textBackgroundColour.Ok())
1107 {
1108 ::SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() );
1109 }
1110
1111 DWORD dwRop = rop == wxCOPY ? SRCCOPY :
1112 rop == wxCLEAR ? WHITENESS :
1113 rop == wxSET ? BLACKNESS :
1114 rop == wxINVERT ? DSTINVERT :
1115 rop == wxAND ? MERGECOPY :
1116 rop == wxOR ? MERGEPAINT :
1117 rop == wxSRC_INVERT ? NOTSRCCOPY :
1118 rop == wxXOR ? SRCINVERT :
1119 rop == wxOR_REVERSE ? MERGEPAINT :
1120 rop == wxAND_REVERSE ? SRCERASE :
1121 rop == wxSRC_OR ? SRCPAINT :
1122 rop == wxSRC_AND ? SRCAND :
1123 SRCCOPY;
1124
1125 bool success = TRUE;
1126 if (useMask && source->m_selectedBitmap.Ok() && source->m_selectedBitmap.GetMask())
1127 {
1128
1129 #if 0 // __WIN32__
1130 // Not implemented under Win95 (or maybe a specific device?)
1131 if (MaskBlt(GetHdc(), xdest1, ydest1, (int)width, (int)height,
1132 (HDC) source->m_hDC, xsrc1, ysrc1, (HBITMAP) source->m_selectedBitmap.GetMask()->GetMaskBitmap(),
1133 0, 0, 0xAACC0020))
1134 {
1135 // Success
1136 }
1137 else
1138 #endif
1139 {
1140 // Old code
1141 #if 0
1142 HDC dc_mask = CreateCompatibleDC((HDC) source->m_hDC);
1143 ::SelectObject(dc_mask, (HBITMAP) source->m_selectedBitmap.GetMask()->GetMaskBitmap());
1144 success = (BitBlt(GetHdc(), xdest1, ydest1, (int)width, (int)height,
1145 dc_mask, xsrc1, ysrc1, 0x00220326 /* NOTSRCAND */) != 0);
1146 success = (BitBlt(GetHdc(), xdest1, ydest1, (int)width, (int)height,
1147 (HDC) source->m_hDC, xsrc1, ysrc1, SRCPAINT) != 0);
1148 ::SelectObject(dc_mask, 0);
1149 ::DeleteDC(dc_mask);
1150 #endif
1151 // New code from Chris Breeze, 15/7/98
1152 // Blit bitmap with mask
1153
1154 if (IsKindOf(CLASSINFO(wxPrinterDC)))
1155 {
1156 // If we are printing source colours are screen colours
1157 // not printer colours and so we need copy the bitmap
1158 // pixel by pixel.
1159 RECT rect;
1160 HDC dc_mask = ::CreateCompatibleDC((HDC) source->m_hDC);
1161 HDC dc_src = (HDC) source->m_hDC;
1162
1163 ::SelectObject(dc_mask, (HBITMAP) source->m_selectedBitmap.GetMask()->GetMaskBitmap());
1164 for (int x = 0; x < width; x++)
1165 {
1166 for (int y = 0; y < height; y++)
1167 {
1168 COLORREF cref = ::GetPixel(dc_mask, x, y);
1169 if (cref)
1170 {
1171 HBRUSH brush = ::CreateSolidBrush(::GetPixel(dc_src, x, y));
1172 rect.left = xdest1 + x; rect.right = rect.left + 1;
1173 rect.top = ydest1 + y; rect.bottom = rect.top + 1;
1174 ::FillRect(GetHdc(), &rect, brush);
1175 ::DeleteObject(brush);
1176 }
1177 }
1178 }
1179 ::SelectObject(dc_mask, 0);
1180 ::DeleteDC(dc_mask);
1181 }
1182 else
1183 {
1184 // create a temp buffer bitmap and DCs to access it and the mask
1185 HDC dc_mask = ::CreateCompatibleDC((HDC) source->m_hDC);
1186 HDC dc_buffer = ::CreateCompatibleDC(GetHdc());
1187 HBITMAP buffer_bmap = ::CreateCompatibleBitmap(GetHdc(), width, height);
1188 ::SelectObject(dc_mask, (HBITMAP) source->m_selectedBitmap.GetMask()->GetMaskBitmap());
1189 ::SelectObject(dc_buffer, buffer_bmap);
1190
1191 // copy dest to buffer
1192 ::BitBlt(dc_buffer, 0, 0, (int)width, (int)height,
1193 GetHdc(), xdest1, ydest1, SRCCOPY);
1194
1195 // copy src to buffer using selected raster op
1196 ::BitBlt(dc_buffer, 0, 0, (int)width, (int)height,
1197 (HDC) source->m_hDC, xsrc1, ysrc1, dwRop);
1198
1199 // set masked area in buffer to BLACK (pixel value 0)
1200 COLORREF prevBkCol = ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1201 COLORREF prevCol = ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1202 ::BitBlt(dc_buffer, 0, 0, (int)width, (int)height,
1203 dc_mask, xsrc1, ysrc1, SRCAND);
1204
1205 // set unmasked area in dest to BLACK
1206 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1207 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1208 ::BitBlt(GetHdc(), xdest1, ydest1, (int)width, (int)height,
1209 dc_mask, xsrc1, ysrc1, SRCAND);
1210 ::SetBkColor(GetHdc(), prevBkCol); // restore colours to original values
1211 ::SetTextColor(GetHdc(), prevCol);
1212
1213 // OR buffer to dest
1214 success = (::BitBlt(GetHdc(), xdest1, ydest1, (int)width, (int)height,
1215 dc_buffer, 0, 0, SRCPAINT) != 0);
1216
1217 // tidy up temporary DCs and bitmap
1218 ::SelectObject(dc_mask, 0);
1219 ::DeleteDC(dc_mask);
1220 ::SelectObject(dc_buffer, 0);
1221 ::DeleteDC(dc_buffer);
1222 ::DeleteObject(buffer_bmap);
1223 }
1224 }
1225 }
1226 else
1227 {
1228 if (IsKindOf(CLASSINFO(wxPrinterDC)))
1229 {
1230 // If we are printing, source colours are screen colours
1231 // not printer colours and so we need copy the bitmap
1232 // pixel by pixel.
1233 HDC dc_src = (HDC) source->m_hDC;
1234 RECT rect;
1235 for (int x = 0; x < width; x++)
1236 {
1237 for (int y = 0; y < height; y++)
1238 {
1239 HBRUSH brush = ::CreateSolidBrush(::GetPixel(dc_src, x, y));
1240 rect.left = xdest1 + x; rect.right = rect.left + 1;
1241 rect.top = ydest1 + y; rect.bottom = rect.top + 1;
1242 ::FillRect(GetHdc(), &rect, brush);
1243 ::DeleteObject(brush);
1244 }
1245 }
1246 }
1247 else
1248 {
1249 success = (BitBlt(GetHdc(), xdest1, ydest1, (int)width, (int)height, (HDC) source->m_hDC,
1250 xsrc1, ysrc1, dwRop) != 0);
1251 }
1252 }
1253 ::SetTextColor(GetHdc(), old_textground);
1254 ::SetBkColor(GetHdc(), old_background);
1255
1256 return success;
1257 }
1258
1259 void wxDC::DoGetSize(int *w, int *h) const
1260 {
1261 if ( w ) *w = ::GetDeviceCaps(GetHdc(), HORZRES);
1262 if ( h ) *h = ::GetDeviceCaps(GetHdc(), VERTRES);
1263 }
1264
1265 void wxDC::DoGetSizeMM(int *w, int *h) const
1266 {
1267 if ( w ) *w = ::GetDeviceCaps(GetHdc(), HORZSIZE);
1268 if ( h ) *h = ::GetDeviceCaps(GetHdc(), VERTSIZE);
1269 }
1270
1271 wxSize wxDC::GetPPI() const
1272 {
1273 int x = ::GetDeviceCaps(GetHdc(), LOGPIXELSX);
1274 int y = ::GetDeviceCaps(GetHdc(), LOGPIXELSY);
1275
1276 return wxSize(x, y);
1277 }
1278
1279 // For use by wxWindows only, unless custom units are required.
1280 void wxDC::SetLogicalScale(double x, double y)
1281 {
1282 m_logicalScaleX = x;
1283 m_logicalScaleY = y;
1284 }
1285
1286 #if WXWIN_COMPATIBILITY
1287 void wxDC::DoGetTextExtent(const wxString& string, float *x, float *y,
1288 float *descent, float *externalLeading,
1289 wxFont *theFont, bool use16bit) const
1290 {
1291 long x1, y1, descent1, externalLeading1;
1292 GetTextExtent(string, & x1, & y1, & descent1, & externalLeading1, theFont, use16bit);
1293 *x = x1; *y = y1;
1294 if (descent)
1295 *descent = descent1;
1296 if (externalLeading)
1297 *externalLeading = externalLeading1;
1298 }
1299 #endif
1300
1301 // ---------------------------------------------------------------------------
1302 // spline drawing code
1303 // ---------------------------------------------------------------------------
1304
1305 #if wxUSE_SPLINES
1306
1307 class wxSpline: public wxObject
1308 {
1309 public:
1310 int type;
1311 wxList *points;
1312
1313 wxSpline(wxList *list);
1314 void DeletePoints();
1315
1316 // Doesn't delete points
1317 ~wxSpline();
1318 };
1319
1320 void wx_draw_open_spline(wxDC *dc, wxSpline *spline);
1321
1322 void wx_quadratic_spline(double a1, double b1, double a2, double b2,
1323 double a3, double b3, double a4, double b4);
1324 void wx_clear_stack();
1325 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
1326 double *y3, double *x4, double *y4);
1327 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
1328 double x4, double y4);
1329 static bool wx_spline_add_point(double x, double y);
1330 static void wx_spline_draw_point_array(wxDC *dc);
1331 wxSpline *wx_make_spline(int x1, int y1, int x2, int y2, int x3, int y3);
1332
1333 void wxDC::DoDrawSpline(wxList *list)
1334 {
1335 wxSpline spline(list);
1336
1337 wx_draw_open_spline(this, &spline);
1338 }
1339
1340 wxList wx_spline_point_list;
1341
1342 void wx_draw_open_spline(wxDC *dc, wxSpline *spline)
1343 {
1344 wxPoint *p;
1345 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
1346 double x1, y1, x2, y2;
1347
1348 wxNode *node = spline->points->First();
1349 p = (wxPoint *)node->Data();
1350
1351 x1 = p->x;
1352 y1 = p->y;
1353
1354 node = node->Next();
1355 p = (wxPoint *)node->Data();
1356
1357 x2 = p->x;
1358 y2 = p->y;
1359 cx1 = (double)((x1 + x2) / 2);
1360 cy1 = (double)((y1 + y2) / 2);
1361 cx2 = (double)((cx1 + x2) / 2);
1362 cy2 = (double)((cy1 + y2) / 2);
1363
1364 wx_spline_add_point(x1, y1);
1365
1366 while ((node = node->Next()) != NULL)
1367 {
1368 p = (wxPoint *)node->Data();
1369 x1 = x2;
1370 y1 = y2;
1371 x2 = p->x;
1372 y2 = p->y;
1373 cx4 = (double)(x1 + x2) / 2;
1374 cy4 = (double)(y1 + y2) / 2;
1375 cx3 = (double)(x1 + cx4) / 2;
1376 cy3 = (double)(y1 + cy4) / 2;
1377
1378 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
1379
1380 cx1 = cx4;
1381 cy1 = cy4;
1382 cx2 = (double)(cx1 + x2) / 2;
1383 cy2 = (double)(cy1 + y2) / 2;
1384 }
1385
1386 wx_spline_add_point((double)wx_round(cx1), (double)wx_round(cy1));
1387 wx_spline_add_point(x2, y2);
1388
1389 wx_spline_draw_point_array(dc);
1390
1391 }
1392
1393 /********************* CURVES FOR SPLINES *****************************
1394
1395 The following spline drawing routine is from
1396
1397 "An Algorithm for High-Speed Curve Generation"
1398 by George Merrill Chaikin,
1399 Computer Graphics and Image Processing, 3, Academic Press,
1400 1974, 346-349.
1401
1402 and
1403
1404 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1405 Computer Graphics and Image Processing, 4, Academic Press,
1406 1975, 304-310.
1407
1408 ***********************************************************************/
1409
1410 #define half(z1, z2) ((z1+z2)/2.0)
1411 #define THRESHOLD 5
1412
1413 /* iterative version */
1414
1415 void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
1416 double b4)
1417 {
1418 register double xmid, ymid;
1419 double x1, y1, x2, y2, x3, y3, x4, y4;
1420
1421 wx_clear_stack();
1422 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
1423
1424 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
1425 xmid = (double)half(x2, x3);
1426 ymid = (double)half(y2, y3);
1427 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
1428 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
1429 wx_spline_add_point((double)wx_round(x1), (double)wx_round(y1));
1430 wx_spline_add_point((double)wx_round(xmid), (double)wx_round(ymid));
1431 } else {
1432 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
1433 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
1434 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
1435 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
1436 }
1437 }
1438 }
1439
1440
1441 /* utilities used by spline drawing routines */
1442
1443
1444 typedef struct wx_spline_stack_struct {
1445 double x1, y1, x2, y2, x3, y3, x4, y4;
1446 }
1447 Stack;
1448
1449 #define SPLINE_STACK_DEPTH 20
1450 static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
1451 static Stack *wx_stack_top;
1452 static int wx_stack_count;
1453
1454 void wx_clear_stack()
1455 {
1456 wx_stack_top = wx_spline_stack;
1457 wx_stack_count = 0;
1458 }
1459
1460 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
1461 {
1462 wx_stack_top->x1 = x1;
1463 wx_stack_top->y1 = y1;
1464 wx_stack_top->x2 = x2;
1465 wx_stack_top->y2 = y2;
1466 wx_stack_top->x3 = x3;
1467 wx_stack_top->y3 = y3;
1468 wx_stack_top->x4 = x4;
1469 wx_stack_top->y4 = y4;
1470 wx_stack_top++;
1471 wx_stack_count++;
1472 }
1473
1474 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
1475 double *x3, double *y3, double *x4, double *y4)
1476 {
1477 if (wx_stack_count == 0)
1478 return (0);
1479 wx_stack_top--;
1480 wx_stack_count--;
1481 *x1 = wx_stack_top->x1;
1482 *y1 = wx_stack_top->y1;
1483 *x2 = wx_stack_top->x2;
1484 *y2 = wx_stack_top->y2;
1485 *x3 = wx_stack_top->x3;
1486 *y3 = wx_stack_top->y3;
1487 *x4 = wx_stack_top->x4;
1488 *y4 = wx_stack_top->y4;
1489 return (1);
1490 }
1491
1492 static bool wx_spline_add_point(double x, double y)
1493 {
1494 wxPoint *point = new wxPoint;
1495 point->x = (int) x;
1496 point->y = (int) y;
1497 wx_spline_point_list.Append((wxObject*)point);
1498 return TRUE;
1499 }
1500
1501 static void wx_spline_draw_point_array(wxDC *dc)
1502 {
1503 dc->DrawLines(&wx_spline_point_list, 0, 0);
1504 wxNode *node = wx_spline_point_list.First();
1505 while (node)
1506 {
1507 wxPoint *point = (wxPoint *)node->Data();
1508 delete point;
1509 delete node;
1510 node = wx_spline_point_list.First();
1511 }
1512 }
1513
1514 wxSpline::wxSpline(wxList *list)
1515 {
1516 points = list;
1517 }
1518
1519 wxSpline::~wxSpline()
1520 {
1521 }
1522
1523 void wxSpline::DeletePoints()
1524 {
1525 for(wxNode *node = points->First(); node; node = points->First())
1526 {
1527 wxPoint *point = (wxPoint *)node->Data();
1528 delete point;
1529 delete node;
1530 }
1531 delete points;
1532 }
1533
1534
1535 #endif // wxUSE_SPLINES
1536