1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "dc.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
27 #include "wx/dialog.h"
29 #include "wx/bitmap.h"
30 #include "wx/dcmemory.h"
33 #include "wx/dcprint.h"
34 #include "wx/msw/private.h"
39 #if wxUSE_COMMON_DIALOGS
59 #if !USE_SHARED_LIBRARY
60 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
63 // Declarations local to this file
65 #define YSCALE(y) (yorigin - (y))
67 // #define wx_round(a) (int)((a)+.5)
69 // Default constructor
72 m_minX
= 0; m_minY
= 0; m_maxX
= 0; m_maxY
= 0;
81 m_minX
= 0; m_minY
= 0; m_maxX
= 0; m_maxY
= 0;
86 m_logicalScaleX
= 1.0;
87 m_logicalScaleY
= 1.0;
94 m_mappingMode
= wxMM_TEXT
;
99 m_windowExtX
= VIEWPORT_EXTENT
;
100 m_windowExtY
= VIEWPORT_EXTENT
;
101 m_logicalFunction
= -1;
103 m_backgroundBrush
= *wxWHITE_BRUSH
;
105 m_textForegroundColour
= *wxBLACK
;
106 m_textBackgroundColour
= *wxWHITE
;
108 m_colour
= wxColourDisplay();
117 SelectOldObjects(m_hDC
);
119 if ( m_canvas
== NULL
)
120 ::DeleteDC((HDC
)m_hDC
);
122 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), (HDC
)m_hDC
);
128 // This will select current objects out of the DC,
129 // which is what you have to do before deleting the
131 void wxDC::SelectOldObjects(WXHDC dc
)
137 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
138 if (m_selectedBitmap
.Ok())
140 m_selectedBitmap
.SetSelectedInto(NULL
);
146 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
151 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
156 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
161 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, TRUE
);
166 m_brush
= wxNullBrush
;
168 m_palette
= wxNullPalette
;
170 m_backgroundBrush
= wxNullBrush
;
171 m_selectedBitmap
= wxNullBitmap
;
174 void wxDC::SetClippingRegion(long cx
, long cy
, long cw
, long ch
)
179 m_clipX2
= (int)(cx
+ cw
);
180 m_clipY2
= (int)(cy
+ ch
);
182 DoClipping((WXHDC
) m_hDC
);
185 void wxDC::SetClippingRegion(const wxRegion
& region
)
187 if (!region
.GetHRGN())
190 wxRect box
= region
.GetBox();
195 m_clipX2
= box
.x
+ box
.width
;
196 m_clipY2
= box
.y
+ box
.height
;
199 SelectClipRgn((HDC
) m_hDC
, (HRGN
) region
.GetHRGN());
201 ExtSelectClipRgn((HDC
) m_hDC
, (HRGN
) region
.GetHRGN(), RGN_AND
);
205 void wxDC::DoClipping(WXHDC dc
)
207 if (m_clipping
&& dc
)
209 IntersectClipRect((HDC
) dc
, XLOG2DEV(m_clipX1
), YLOG2DEV(m_clipY1
),
210 XLOG2DEV(m_clipX2
), YLOG2DEV(m_clipY2
));
214 void wxDC::DestroyClippingRegion(void)
216 if (m_clipping
&& m_hDC
)
218 // TODO: this should restore the previous clipping region,
219 // so that OnPaint processing works correctly, and the update clipping region
220 // doesn't get destroyed after the first DestroyClippingRegion.
221 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
222 SelectClipRgn((HDC
) m_hDC
, rgn
);
228 bool wxDC::CanDrawBitmap(void) const
233 bool wxDC::CanGetTextExtent(void) const
235 // What sort of display is it?
236 int technology
= ::GetDeviceCaps((HDC
) m_hDC
, TECHNOLOGY
);
240 if (technology
!= DT_RASDISPLAY
&& technology
!= DT_RASPRINTER
)
247 void wxDC::SetPalette(const wxPalette
& palette
)
249 // Set the old object temporarily, in case the assignment deletes an object
250 // that's not yet selected out.
253 ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_oldPalette
, TRUE
);
261 // Setting a NULL colourmap is a way of restoring
262 // the original colourmap
265 ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_oldPalette
, TRUE
);
272 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
274 HPALETTE oldPal
= ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
276 m_oldPalette
= (WXHPALETTE
) oldPal
;
278 ::RealizePalette((HDC
) m_hDC
);
282 void wxDC::Clear(void)
286 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
287 else if (m_selectedBitmap
.Ok())
289 rect
.left
= 0; rect
.top
= 0;
290 rect
.right
= m_selectedBitmap
.GetWidth();
291 rect
.bottom
= m_selectedBitmap
.GetHeight();
293 (void) ::SetMapMode((HDC
) m_hDC
, MM_TEXT
);
295 DWORD colour
= GetBkColor((HDC
) m_hDC
);
296 HBRUSH brush
= CreateSolidBrush(colour
);
297 FillRect((HDC
) m_hDC
, &rect
, brush
);
300 ::SetMapMode((HDC
) m_hDC
, MM_ANISOTROPIC
);
301 ::SetViewportExtEx((HDC
) m_hDC
, VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
302 ::SetWindowExtEx((HDC
) m_hDC
, m_windowExtX
, m_windowExtY
, NULL
);
303 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
304 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
307 void wxDC::FloodFill(long x
, long y
, const wxColour
& col
, int style
)
309 (void)ExtFloodFill((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
311 style
==wxFLOOD_SURFACE
?
312 FLOODFILLSURFACE
:FLOODFILLBORDER
315 CalcBoundingBox(x
, y
);
318 bool wxDC::GetPixel(long x
, long y
, wxColour
*col
) const
320 // added by steve 29.12.94 (copied from DrawPoint)
321 // returns TRUE for pixels in the color of the current pen
322 // and FALSE for all other pixels colors
323 // if col is non-NULL return the color of the pixel
325 // get the color of the pixel
326 COLORREF pixelcolor
= ::GetPixel((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
));
327 // get the color of the pen
328 COLORREF pencolor
= 0x00ffffff;
331 pencolor
= m_pen
.GetColour().GetPixel() ;
334 // return the color of the pixel
336 col
->Set(GetRValue(pixelcolor
),GetGValue(pixelcolor
),GetBValue(pixelcolor
));
338 // check, if color of the pixels is the same as the color
339 // of the current pen
340 return(pixelcolor
==pencolor
);
343 void wxDC::CrossHair(long x
, long y
)
345 // We suppose that our screen is 2000x2000 max.
351 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
352 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
), YLOG2DEV(y
));
354 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
355 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y2
));
357 CalcBoundingBox(x1
, y1
);
358 CalcBoundingBox(x2
, y2
);
361 void wxDC::DrawLine(long x1
, long y1
, long x2
, long y2
)
363 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
364 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
), YLOG2DEV(y2
));
366 /* MATTHEW: [6] New normalization */
367 #if WX_STANDARD_GRAPHICS
368 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
) + 1, YLOG2DEV(y2
));
371 CalcBoundingBox(x1
, y1
);
372 CalcBoundingBox(x2
, y2
);
375 void wxDC::DrawArc(long x1
,long y1
,long x2
,long y2
, long xc
, long yc
)
379 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
380 if (x1
==x2
&& x2
==y2
)
382 DrawEllipse(xc
,yc
,(long)(radius
*2.0),(long)(radius
*2.0)) ;
386 long xx1
= XLOG2DEV(x1
) ;
387 long yy1
= YLOG2DEV(y1
) ;
388 long xx2
= XLOG2DEV(x2
) ;
389 long yy2
= YLOG2DEV(y2
) ;
390 long xxc
= XLOG2DEV(xc
) ;
391 long yyc
= YLOG2DEV(yc
) ;
392 long ray
= (long) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
))) ;
394 (void)MoveToEx((HDC
) m_hDC
, (int) xx1
, (int) yy1
, NULL
);
395 long xxx1
= (long) (xxc
-ray
);
396 long yyy1
= (long) (yyc
-ray
);
397 long xxx2
= (long) (xxc
+ray
);
398 long yyy2
= (long) (yyc
+ray
);
399 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
401 // Have to add 1 to bottom-right corner of rectangle
402 // to make semi-circles look right (crooked line otherwise).
403 // Unfortunately this is not a reliable method, depends
404 // on the size of shape.
405 // TODO: figure out why this happens!
406 Pie((HDC
) m_hDC
,xxx1
,yyy1
,xxx2
+1,yyy2
+1,
410 Arc((HDC
) m_hDC
,xxx1
,yyy1
,xxx2
,yyy2
,
413 CalcBoundingBox((xc
-radius
), (yc
-radius
));
414 CalcBoundingBox((xc
+radius
), (yc
+radius
));
417 void wxDC::DrawPoint(long x
, long y
)
419 COLORREF color
= 0x00ffffff;
422 color
= m_pen
.GetColour().GetPixel() ;
425 SetPixel((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), color
);
427 CalcBoundingBox(x
, y
);
430 void wxDC::DrawPolygon(int n
, wxPoint points
[], long xoffset
, long yoffset
,int fillStyle
)
432 // Do things less efficiently if we have offsets
433 if (xoffset
!= 0 || yoffset
!= 0)
435 POINT
*cpoints
= new POINT
[n
];
437 for (i
= 0; i
< n
; i
++)
439 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
440 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
442 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
444 int prev
= SetPolyFillMode((HDC
) m_hDC
,fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
) ;
445 (void)Polygon((HDC
) m_hDC
, cpoints
, n
);
446 SetPolyFillMode((HDC
) m_hDC
,prev
) ;
452 for (i
= 0; i
< n
; i
++)
453 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
455 int prev
= SetPolyFillMode((HDC
) m_hDC
,fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
) ;
456 (void)Polygon((HDC
) m_hDC
, (POINT
*) points
, n
);
457 SetPolyFillMode((HDC
) m_hDC
,prev
) ;
461 void wxDC::DrawLines(int n
, wxPoint points
[], long xoffset
, long yoffset
)
463 // Do things less efficiently if we have offsets
464 if (xoffset
!= 0 || yoffset
!= 0)
466 POINT
*cpoints
= new POINT
[n
];
468 for (i
= 0; i
< n
; i
++)
470 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
471 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
473 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
475 (void)Polyline((HDC
) m_hDC
, cpoints
, n
);
481 for (i
= 0; i
< n
; i
++)
482 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
484 (void)Polyline((HDC
) m_hDC
, (POINT
*) points
, n
);
488 void wxDC::DrawRectangle(long x
, long y
, long width
, long height
)
491 long y2
= y
+ height
;
493 /* MATTHEW: [6] new normalization */
494 #if WX_STANDARD_GRAPHICS
495 bool do_brush
, do_pen
;
497 do_brush
= m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
;
498 do_pen
= m_pen
.Ok() && m_pen
.GetStyle() != wxTRANSPARENT
;
501 HPEN orig_pen
= NULL
;
503 if (do_pen
|| !m_pen
.Ok())
504 orig_pen
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
) ::GetStockObject(NULL_PEN
));
506 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
507 XLOG2DEV(x2
) + 1, YLOG2DEV(y2
) + 1);
509 if (do_pen
|| !m_pen
.Ok())
510 ::SelectObject((HDC
) m_hDC
, orig_pen
);
513 HBRUSH orig_brush
= NULL
;
515 if (do_brush
|| !m_brush
.Ok())
516 orig_brush
= (HBRUSH
) ::SelectObject((HDC
) m_hDC
, (HBRUSH
) ::GetStockObject(NULL_BRUSH
));
518 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
519 XLOG2DEV(x2
), YLOG2DEV(y2
));
521 if (do_brush
|| !m_brush
.Ok())
522 ::SelectObject((HDC
) m_hDC
, orig_brush
);
525 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
528 CalcBoundingBox(x
, y
);
529 CalcBoundingBox(x2
, y2
);
532 void wxDC::DrawRoundedRectangle(long x
, long y
, long width
, long height
, double radius
)
534 // Now, a negative radius value is interpreted to mean
535 // 'the proportion of the smallest X or Y dimension'
539 double smallest
= 0.0;
544 radius
= (- radius
* smallest
);
548 long y2
= (y
+height
);
550 (void)RoundRect((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
551 YLOG2DEV(y2
), 2*XLOG2DEV(radius
), 2*YLOG2DEV(radius
));
553 CalcBoundingBox(x
, y
);
554 CalcBoundingBox(x2
, y2
);
557 void wxDC::DrawEllipse(long x
, long y
, long width
, long height
)
560 long y2
= (y
+height
);
562 (void)Ellipse((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
564 CalcBoundingBox(x
, y
);
565 CalcBoundingBox(x2
, y2
);
568 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
569 void wxDC::DrawEllipticArc(long x
,long y
,long w
,long h
,double sa
,double ea
)
574 const double deg2rad
= 3.14159265359 / 180.0;
575 int rx1
= XLOG2DEV(x
+w
/2);
576 int ry1
= YLOG2DEV(y
+h
/2);
579 rx1
+= (int)(100.0 * abs(w
) * cos(sa
* deg2rad
));
580 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
* deg2rad
));
581 rx2
+= (int)(100.0 * abs(w
) * cos(ea
* deg2rad
));
582 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
* deg2rad
));
584 // draw pie with NULL_PEN first and then outline otherwise a line is
585 // drawn from the start and end points to the centre
586 HPEN orig_pen
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
) ::GetStockObject(NULL_PEN
));
589 (void)Pie((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
594 (void)Pie((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
595 rx1
, ry1
-1, rx2
, ry2
-1);
597 ::SelectObject((HDC
) m_hDC
, orig_pen
);
598 (void)Arc((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
601 CalcBoundingBox(x
, y
);
602 CalcBoundingBox(x2
, y2
);
605 void wxDC::DrawIcon(const wxIcon
& icon
, long x
, long y
)
607 #if defined(__WIN32__) && !defined(__SC__) && !defined(__TWIN32__)
608 ::DrawIconEx((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON(),
609 icon
.GetWidth(), icon
.GetHeight(), 0, 0, DI_NORMAL
);
611 ::DrawIcon((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON());
614 CalcBoundingBox(x
, y
);
615 CalcBoundingBox(x
+icon
.GetWidth(), y
+icon
.GetHeight());
618 void wxDC::DrawBitmap( const wxBitmap
&bmp
, long x
, long y
, bool useMask
)
623 // If we're not drawing transparently, and not drawing to a printer,
624 // optimize this function to use Windows functions.
625 if (!useMask
&& !IsKindOf(CLASSINFO(wxPrinterDC
)))
627 HDC cdc
= (HDC
)m_hDC
;
628 HDC memdc
= ::CreateCompatibleDC( cdc
);
629 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
630 ::SelectObject( memdc
, hbitmap
);
631 ::BitBlt( cdc
, x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), memdc
, 0, 0, SRCCOPY
);
632 ::SelectObject( memdc
, 0 );
637 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API level
639 memDC
.SelectObject(bmp
);
641 /* Not sure if we need this. The mask should leave the
642 * masked areas as per the original background of this DC.
645 // There might be transparent areas, so make these
646 // the same colour as this DC
647 memDC.SetBackground(* GetBackground());
651 Blit(x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), & memDC
, 0, 0, wxCOPY
, useMask
);
653 memDC
.SelectObject(wxNullBitmap
);
657 void wxDC::SetFont(const wxFont
& the_font
)
659 // Set the old object temporarily, in case the assignment deletes an object
660 // that's not yet selected out.
663 ::SelectObject((HDC
) m_hDC
, (HFONT
) m_oldFont
);
672 ::SelectObject((HDC
) m_hDC
, (HFONT
) m_oldFont
);
676 if (m_font
.Ok() && m_font
.GetResourceHandle())
678 HFONT f
= (HFONT
) ::SelectObject((HDC
) m_hDC
, (HFONT
) m_font
.GetResourceHandle());
679 if (f
== (HFONT
) NULL
)
681 wxDebugMsg("::SelectObject failed in wxDC::SetFont.");
684 m_oldFont
= (WXHFONT
) f
;
688 void wxDC::SetPen(const wxPen
& pen
)
690 // Set the old object temporarily, in case the assignment deletes an object
691 // that's not yet selected out.
694 ::SelectObject((HDC
) m_hDC
, (HPEN
) m_oldPen
);
703 ::SelectObject((HDC
) m_hDC
, (HPEN
) m_oldPen
);
709 if (m_pen
.GetResourceHandle())
711 HPEN p
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
)m_pen
.GetResourceHandle()) ;
713 m_oldPen
= (WXHPEN
) p
;
718 void wxDC::SetBrush(const wxBrush
& brush
)
720 // Set the old object temporarily, in case the assignment deletes an object
721 // that's not yet selected out.
724 ::SelectObject((HDC
) m_hDC
, (HBRUSH
) m_oldBrush
);
733 ::SelectObject((HDC
) m_hDC
, (HBRUSH
) m_oldBrush
);
739 if (m_brush
.GetResourceHandle())
742 b
= (HBRUSH
) ::SelectObject((HDC
) m_hDC
, (HBRUSH
)m_brush
.GetResourceHandle()) ;
744 m_oldBrush
= (WXHBRUSH
) b
;
749 void wxDC::DrawText(const wxString
& text
, long x
, long y
, bool use16bit
)
751 // Should be unnecessary: SetFont should have done this already.
753 if (m_font
.Ok() && m_font
.GetResourceHandle())
755 HFONT f
= (HFONT
) ::SelectObject((HDC
) m_hDC
, (HFONT
) m_font
.GetResourceHandle());
757 m_oldFont
= (WXHFONT
) f
;
761 if (m_textForegroundColour
.Ok())
762 SetTextColor((HDC
) m_hDC
, m_textForegroundColour
.GetPixel() ) ;
764 DWORD old_background
= 0;
765 if (m_textBackgroundColour
.Ok())
767 old_background
= SetBkColor((HDC
) m_hDC
, m_textBackgroundColour
.GetPixel() ) ;
770 if (m_backgroundMode
== wxTRANSPARENT
)
771 SetBkMode((HDC
) m_hDC
, TRANSPARENT
);
773 SetBkMode((HDC
) m_hDC
, OPAQUE
);
775 (void)TextOut((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), (char *) (const char *)text
, strlen((const char *)text
));
777 if (m_textBackgroundColour
.Ok())
778 (void)SetBkColor((HDC
) m_hDC
, old_background
);
780 CalcBoundingBox(x
, y
);
783 GetTextExtent(text
, &w
, &h
);
784 CalcBoundingBox((x
+ w
), (y
+ h
));
787 void wxDC::SetBackground(const wxBrush
& brush
)
789 m_backgroundBrush
= brush
;
791 if (!m_backgroundBrush
.Ok())
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
;
804 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
806 m_canvas
->m_backgroundTransparent
= TRUE
;
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
817 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
818 m_canvas
->m_backgroundTransparent
= FALSE
;
822 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel() ;
824 (void)SetBkColor((HDC
) m_hDC
, new_color
);
828 void wxDC::SetBackgroundMode(int mode
)
830 m_backgroundMode
= mode
;
832 if (m_backgroundMode
== wxTRANSPARENT
)
833 ::SetBkMode((HDC
) m_hDC
, TRANSPARENT
);
835 ::SetBkMode((HDC
) m_hDC
, OPAQUE
);
838 void wxDC::SetLogicalFunction(int function
)
840 m_logicalFunction
= function
;
842 SetRop((WXHDC
) m_hDC
);
845 void wxDC::SetRop(WXHDC dc
)
847 if (!dc
|| m_logicalFunction
< 0)
851 // These may be wrong
852 switch (m_logicalFunction
)
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;
870 c_rop
= R2_COPYPEN
; break;
872 SetROP2((HDC
) dc
, c_rop
);
875 bool wxDC::StartDoc(const wxString
& message
)
877 // We might be previewing, so return TRUE to let it continue.
881 void wxDC::EndDoc(void)
885 void wxDC::StartPage(void)
889 void wxDC::EndPage(void)
893 long wxDC::GetCharHeight(void) const
895 TEXTMETRIC lpTextMetric
;
897 GetTextMetrics((HDC
) m_hDC
, &lpTextMetric
);
899 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
902 long wxDC::GetCharWidth(void) const
904 TEXTMETRIC lpTextMetric
;
906 GetTextMetrics((HDC
) m_hDC
, &lpTextMetric
);
908 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
911 void wxDC::GetTextExtent(const wxString
& string
, long *x
, long *y
,
912 long *descent
, long *externalLeading
, wxFont
*theFont
, bool use16bit
) const
914 wxFont
*fontToUse
= (wxFont
*) theFont
;
916 fontToUse
= (wxFont
*) &m_font
;
921 GetTextExtentPoint((HDC
) m_hDC
, (char *)(const char *) string
, strlen((char *)(const char *) string
), &sizeRect
);
922 GetTextMetrics((HDC
) m_hDC
, &tm
);
924 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
925 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
926 if (descent
) *descent
= tm
.tmDescent
;
927 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
930 void wxDC::SetMapMode(int mode
)
932 m_mappingMode
= mode
;
935 int pixel_height
= 0;
939 pixel_width
= GetDeviceCaps((HDC
) m_hDC
, HORZRES
);
940 pixel_height
= GetDeviceCaps((HDC
) m_hDC
, VERTRES
);
941 mm_width
= GetDeviceCaps((HDC
) m_hDC
, HORZSIZE
);
942 mm_height
= GetDeviceCaps((HDC
) m_hDC
, VERTSIZE
);
944 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
949 double mm2pixelsX
= pixel_width
/mm_width
;
950 double mm2pixelsY
= pixel_height
/mm_height
;
956 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
957 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
962 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
963 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
968 m_logicalScaleX
= mm2pixelsX
;
969 m_logicalScaleY
= mm2pixelsY
;
974 m_logicalScaleX
= (mm2pixelsX
/10.0);
975 m_logicalScaleY
= (mm2pixelsY
/10.0);
981 m_logicalScaleX
= 1.0;
982 m_logicalScaleY
= 1.0;
987 if (::GetMapMode((HDC
) m_hDC
) != MM_ANISOTROPIC
)
988 ::SetMapMode((HDC
) m_hDC
, MM_ANISOTROPIC
);
990 SetViewportExtEx((HDC
) m_hDC
, VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
991 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
992 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
993 ::SetWindowExtEx((HDC
) m_hDC
, m_windowExtX
, m_windowExtY
, NULL
);
994 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
995 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
998 void wxDC::SetUserScale(double x
, double y
)
1003 SetMapMode(m_mappingMode
);
1006 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1008 m_signX
= xLeftRight
? 1 : -1;
1009 m_signY
= yBottomUp
? -1 : 1;
1011 SetMapMode(m_mappingMode
);
1014 void wxDC::SetSystemScale(double x
, double y
)
1019 SetMapMode(m_mappingMode
);
1022 void wxDC::SetLogicalOrigin(long x
, long y
)
1024 m_logicalOriginX
= x
;
1025 m_logicalOriginY
= y
;
1027 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1030 void wxDC::SetDeviceOrigin(long x
, long y
)
1032 m_deviceOriginX
= x
;
1033 m_deviceOriginY
= y
;
1035 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1038 long wxDC::DeviceToLogicalX(long x
) const
1040 return (long) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
) - m_logicalOriginX
) ;
1043 long wxDC::DeviceToLogicalXRel(long x
) const
1045 return (long) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
)) ;
1048 long wxDC::DeviceToLogicalY(long y
) const
1050 return (long) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
) - m_logicalOriginY
) ;
1053 long wxDC::DeviceToLogicalYRel(long y
) const
1055 return (long) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
)) ;
1058 long wxDC::LogicalToDeviceX(long x
) const
1060 return (long) (floor((x
) - m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
+ m_deviceOriginX
) ;
1063 long wxDC::LogicalToDeviceXRel(long x
) const
1065 return (long) (floor(x
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
) ;
1068 long wxDC::LogicalToDeviceY(long y
) const
1070 return (long) (floor((y
) - m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
+ m_deviceOriginY
);
1073 long wxDC::LogicalToDeviceYRel(long y
) const
1075 return (long) (floor(y
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
) ;
1078 // This group of functions may not do any conversion
1079 // if m_scaleGDI is TRUE, since the HDC does the
1080 // conversion automatically.
1082 long wxDC::ImplDeviceToLogicalX(long x
) const
1084 // return (m_scaleGDI ? x : DeviceToLogicalX(x));
1088 long wxDC::ImplDeviceToLogicalY(long y
) const
1090 // return (m_scaleGDI ? y : DeviceToLogicalY(y));
1094 long wxDC::ImplDeviceToLogicalXRel(long x
) const
1096 // return (m_scaleGDI ? x : DeviceToLogicalXRel(x));
1100 long wxDC::ImplDeviceToLogicalYRel(long y
) const
1102 // return (m_scaleGDI ? y : DeviceToLogicalYRel(y));
1106 long wxDC::ImplLogicalToDeviceX(long x
) const
1108 // return (m_scaleGDI ? (floor(double(x))) : LogicalToDeviceX(x));
1112 long wxDC::ImplLogicalToDeviceY(long y
) const
1114 // return (m_scaleGDI ? (floor(double(y))) : LogicalToDeviceY(y));
1118 long wxDC::ImplLogicalToDeviceXRel(long x
) const
1120 // return (m_scaleGDI ? (floor(double(x))) : LogicalToDeviceXRel(x));
1124 long wxDC::ImplLogicalToDeviceYRel(long y
) const
1126 // return (m_scaleGDI ? (floor(double(y))) : LogicalToDeviceYRel(y));
1130 bool wxDC::Blit(long xdest
, long ydest
, long width
, long height
,
1131 wxDC
*source
, long xsrc
, long ysrc
, int rop
, bool useMask
)
1133 long xdest1
= xdest
;
1134 long ydest1
= ydest
;
1138 // Chris Breeze 18/5/98: use text foreground/background colours
1139 // when blitting from 1-bit bitmaps
1140 COLORREF old_textground
= ::GetTextColor((HDC
)m_hDC
);
1141 COLORREF old_background
= ::GetBkColor((HDC
)m_hDC
);
1142 if (m_textForegroundColour
.Ok())
1144 ::SetTextColor((HDC
) m_hDC
, m_textForegroundColour
.GetPixel() ) ;
1146 if (m_textBackgroundColour
.Ok())
1148 ::SetBkColor((HDC
) m_hDC
, m_textBackgroundColour
.GetPixel() ) ;
1151 DWORD dwRop
= rop
== wxCOPY
? SRCCOPY
:
1152 rop
== wxCLEAR
? WHITENESS
:
1153 rop
== wxSET
? BLACKNESS
:
1154 rop
== wxINVERT
? DSTINVERT
:
1155 rop
== wxAND
? MERGECOPY
:
1156 rop
== wxOR
? MERGEPAINT
:
1157 rop
== wxSRC_INVERT
? NOTSRCCOPY
:
1158 rop
== wxXOR
? SRCINVERT
:
1159 rop
== wxOR_REVERSE
? MERGEPAINT
:
1160 rop
== wxAND_REVERSE
? SRCERASE
:
1161 rop
== wxSRC_OR
? SRCPAINT
:
1162 rop
== wxSRC_AND
? SRCAND
:
1165 bool success
= TRUE
;
1166 if (useMask
&& source
->m_selectedBitmap
.Ok() && source
->m_selectedBitmap
.GetMask())
1170 // Not implemented under Win95 (or maybe a specific device?)
1171 if (MaskBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1172 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap(),
1182 HDC dc_mask
= CreateCompatibleDC((HDC
) source
->m_hDC
);
1183 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1184 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1185 dc_mask
, xsrc1
, ysrc1
, 0x00220326 /* NOTSRCAND */) != 0);
1186 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1187 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, SRCPAINT
) != 0);
1188 ::SelectObject(dc_mask
, 0);
1189 ::DeleteDC(dc_mask
);
1191 // New code from Chris Breeze, 15/7/98
1192 // Blit bitmap with mask
1194 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1196 // If we are printing source colours are screen colours
1197 // not printer colours and so we need copy the bitmap
1200 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1201 HDC dc_src
= (HDC
) source
->m_hDC
;
1203 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1204 for (int x
= 0; x
< width
; x
++)
1206 for (int y
= 0; y
< height
; y
++)
1208 COLORREF cref
= ::GetPixel(dc_mask
, x
, y
);
1211 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1212 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1213 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1214 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1215 ::DeleteObject(brush
);
1219 ::SelectObject(dc_mask
, 0);
1220 ::DeleteDC(dc_mask
);
1224 // create a temp buffer bitmap and DCs to access it and the mask
1225 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1226 HDC dc_buffer
= ::CreateCompatibleDC((HDC
) m_hDC
);
1227 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap((HDC
) m_hDC
, width
, height
);
1228 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1229 ::SelectObject(dc_buffer
, buffer_bmap
);
1231 // copy dest to buffer
1232 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1233 (HDC
) m_hDC
, xdest1
, ydest1
, SRCCOPY
);
1235 // copy src to buffer using selected raster op
1236 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1237 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, dwRop
);
1239 // set masked area in buffer to BLACK (pixel value 0)
1240 COLORREF prevBkCol
= ::SetBkColor((HDC
) m_hDC
, RGB(255, 255, 255));
1241 COLORREF prevCol
= ::SetTextColor((HDC
) m_hDC
, RGB(0, 0, 0));
1242 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1243 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1245 // set unmasked area in dest to BLACK
1246 ::SetBkColor((HDC
) m_hDC
, RGB(0, 0, 0));
1247 ::SetTextColor((HDC
) m_hDC
, RGB(255, 255, 255));
1248 ::BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1249 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1250 ::SetBkColor((HDC
) m_hDC
, prevBkCol
); // restore colours to original values
1251 ::SetTextColor((HDC
) m_hDC
, prevCol
);
1253 // OR buffer to dest
1254 success
= (::BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1255 dc_buffer
, 0, 0, SRCPAINT
) != 0);
1257 // tidy up temporary DCs and bitmap
1258 ::SelectObject(dc_mask
, 0);
1259 ::DeleteDC(dc_mask
);
1260 ::SelectObject(dc_buffer
, 0);
1261 ::DeleteDC(dc_buffer
);
1262 ::DeleteObject(buffer_bmap
);
1268 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1270 // If we are printing, source colours are screen colours
1271 // not printer colours and so we need copy the bitmap
1273 HDC dc_src
= (HDC
) source
->m_hDC
;
1275 for (int x
= 0; x
< width
; x
++)
1277 for (int y
= 0; y
< height
; y
++)
1279 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1280 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1281 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1282 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1283 ::DeleteObject(brush
);
1289 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
, (HDC
) source
->m_hDC
,
1290 xsrc1
, ysrc1
, dwRop
) != 0);
1293 ::SetTextColor((HDC
)m_hDC
, old_textground
);
1294 ::SetBkColor((HDC
)m_hDC
, old_background
);
1299 void wxDC::GetSize(int* width
, int* height
) const
1301 long w
=::GetDeviceCaps((HDC
) m_hDC
,HORZRES
);
1302 long h
=::GetDeviceCaps((HDC
) m_hDC
,VERTRES
);
1307 void wxDC::GetSizeMM(int *width
, int *height
) const
1309 int w
=::GetDeviceCaps((HDC
) m_hDC
,HORZSIZE
);
1310 int h
=::GetDeviceCaps((HDC
) m_hDC
,VERTSIZE
);
1315 // Resolution in Pixels per inch
1316 wxSize
wxDC::GetPPI(void) const
1318 int x
=::GetDeviceCaps((HDC
) m_hDC
,LOGPIXELSX
);
1319 int y
=::GetDeviceCaps((HDC
) m_hDC
,LOGPIXELSY
);
1320 return wxSize(x
, y
);
1323 void wxDC::DrawPolygon(wxList
*list
, long xoffset
, long yoffset
,int fillStyle
)
1325 int n
= list
->Number();
1326 wxPoint
*points
= new wxPoint
[n
];
1329 for(wxNode
*node
= list
->First(); node
; node
= node
->Next()) {
1330 wxPoint
*point
= (wxPoint
*)node
->Data();
1331 points
[i
].x
= point
->x
;
1332 points
[i
++].y
= point
->y
;
1334 DrawPolygon(n
, points
, xoffset
, yoffset
,fillStyle
);
1338 void wxDC::DrawLines(wxList
*list
, long xoffset
, long yoffset
)
1340 int n
= list
->Number();
1341 wxPoint
*points
= new wxPoint
[n
];
1344 for(wxNode
*node
= list
->First(); node
; node
= node
->Next()) {
1345 wxPoint
*point
= (wxPoint
*)node
->Data();
1346 points
[i
].x
= point
->x
;
1347 points
[i
++].y
= point
->y
;
1349 DrawLines(n
, points
, xoffset
, yoffset
);
1353 void wxDC::SetTextForeground(const wxColour
& colour
)
1355 m_textForegroundColour
= colour
;
1358 void wxDC::SetTextBackground(const wxColour
& colour
)
1360 m_textBackgroundColour
= colour
;
1363 // For use by wxWindows only, unless custom units are required.
1364 void wxDC::SetLogicalScale(double x
, double y
)
1366 m_logicalScaleX
= x
;
1367 m_logicalScaleY
= y
;
1370 void wxDC::CalcBoundingBox(long x
, long y
)
1372 if (x
< m_minX
) m_minX
= x
;
1373 if (y
< m_minY
) m_minY
= y
;
1374 if (x
> m_maxX
) m_maxX
= x
;
1375 if (y
> m_maxY
) m_maxY
= y
;
1378 void wxDC::GetClippingBox(long *x
,long *y
,long *w
,long *h
) const
1384 *w
= (m_clipX2
- m_clipX1
) ;
1385 *h
= (m_clipY2
- m_clipY1
) ;
1388 *x
= *y
= *w
= *h
= 0 ;
1391 #if WXWIN_COMPATIBILITY
1392 void wxDC::GetTextExtent(const wxString
& string
, float *x
, float *y
,
1393 float *descent
, float *externalLeading
,
1394 wxFont
*theFont
, bool use16bit
) const
1396 long x1
, y1
, descent1
, externalLeading1
;
1397 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1400 *descent
= descent1
;
1401 if (externalLeading
)
1402 *externalLeading
= externalLeading1
;
1406 int wxDC::GetDepth(void) const
1408 return (int) ::GetDeviceCaps((HDC
) m_hDC
,BITSPIXEL
);
1413 // Make a 3-point spline
1414 void wxDC::DrawSpline(long x1
, long y1
, long x2
, long y2
, long x3
, long y3
)
1416 wxList
*point_list
= new wxList
;
1418 wxPoint
*point1
= new wxPoint
;
1419 point1
->x
= x1
; point1
->y
= y1
;
1420 point_list
->Append((wxObject
*)point1
);
1422 wxPoint
*point2
= new wxPoint
;
1423 point2
->x
= x2
; point2
->y
= y2
;
1424 point_list
->Append((wxObject
*)point2
);
1426 wxPoint
*point3
= new wxPoint
;
1427 point3
->x
= x3
; point3
->y
= y3
;
1428 point_list
->Append((wxObject
*)point3
);
1430 DrawSpline(point_list
);
1432 for(wxNode
*node
= point_list
->First(); node
; node
= node
->Next()) {
1433 wxPoint
*p
= (wxPoint
*)node
->Data();
1439 ////#define wx_round(a) (int)((a)+.5)
1440 //#define wx_round(a) (a)
1442 class wxSpline
: public wxObject
1448 wxSpline(wxList
*list
);
1449 void DeletePoints(void);
1451 // Doesn't delete points
1455 void wxDC::DrawSpline(int n
, wxPoint points
[])
1459 for (i
=0; i
< n
; i
++)
1460 list
.Append((wxObject
*)&points
[i
]);
1461 DrawSpline((wxList
*)&list
);
1464 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1466 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1467 double a3
, double b3
, double a4
, double b4
);
1468 void wx_clear_stack(void);
1469 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1470 double *y3
, double *x4
, double *y4
);
1471 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1472 double x4
, double y4
);
1473 static bool wx_spline_add_point(double x
, double y
);
1474 static void wx_spline_draw_point_array(wxDC
*dc
);
1475 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1477 void wxDC::DrawSpline(wxList
*list
)
1479 wxSpline
spline(list
);
1481 wx_draw_open_spline(this, &spline
);
1485 wxList wx_spline_point_list
;
1487 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1490 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1491 double x1
, y1
, x2
, y2
;
1493 wxNode
*node
= spline
->points
->First();
1494 p
= (wxPoint
*)node
->Data();
1499 node
= node
->Next();
1500 p
= (wxPoint
*)node
->Data();
1504 cx1
= (double)((x1
+ x2
) / 2);
1505 cy1
= (double)((y1
+ y2
) / 2);
1506 cx2
= (double)((cx1
+ x2
) / 2);
1507 cy2
= (double)((cy1
+ y2
) / 2);
1509 wx_spline_add_point(x1
, y1
);
1511 while ((node
= node
->Next()) != NULL
)
1513 p
= (wxPoint
*)node
->Data();
1518 cx4
= (double)(x1
+ x2
) / 2;
1519 cy4
= (double)(y1
+ y2
) / 2;
1520 cx3
= (double)(x1
+ cx4
) / 2;
1521 cy3
= (double)(y1
+ cy4
) / 2;
1523 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1527 cx2
= (double)(cx1
+ x2
) / 2;
1528 cy2
= (double)(cy1
+ y2
) / 2;
1531 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1532 wx_spline_add_point(x2
, y2
);
1534 wx_spline_draw_point_array(dc
);
1538 /********************* CURVES FOR SPLINES *****************************
1540 The following spline drawing routine is from
1542 "An Algorithm for High-Speed Curve Generation"
1543 by George Merrill Chaikin,
1544 Computer Graphics and Image Processing, 3, Academic Press,
1549 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1550 Computer Graphics and Image Processing, 4, Academic Press,
1553 ***********************************************************************/
1555 #define half(z1, z2) ((z1+z2)/2.0)
1558 /* iterative version */
1560 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1563 register double xmid
, ymid
;
1564 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1567 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1569 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1570 xmid
= (double)half(x2
, x3
);
1571 ymid
= (double)half(y2
, y3
);
1572 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1573 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1574 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1575 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1577 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1578 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1579 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1580 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1586 /* utilities used by spline drawing routines */
1589 typedef struct wx_spline_stack_struct
{
1590 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1594 #define SPLINE_STACK_DEPTH 20
1595 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1596 static Stack
*wx_stack_top
;
1597 static int wx_stack_count
;
1599 void wx_clear_stack(void)
1601 wx_stack_top
= wx_spline_stack
;
1605 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1607 wx_stack_top
->x1
= x1
;
1608 wx_stack_top
->y1
= y1
;
1609 wx_stack_top
->x2
= x2
;
1610 wx_stack_top
->y2
= y2
;
1611 wx_stack_top
->x3
= x3
;
1612 wx_stack_top
->y3
= y3
;
1613 wx_stack_top
->x4
= x4
;
1614 wx_stack_top
->y4
= y4
;
1619 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1620 double *x3
, double *y3
, double *x4
, double *y4
)
1622 if (wx_stack_count
== 0)
1626 *x1
= wx_stack_top
->x1
;
1627 *y1
= wx_stack_top
->y1
;
1628 *x2
= wx_stack_top
->x2
;
1629 *y2
= wx_stack_top
->y2
;
1630 *x3
= wx_stack_top
->x3
;
1631 *y3
= wx_stack_top
->y3
;
1632 *x4
= wx_stack_top
->x4
;
1633 *y4
= wx_stack_top
->y4
;
1637 static bool wx_spline_add_point(double x
, double y
)
1639 wxPoint
*point
= new wxPoint
;
1642 wx_spline_point_list
.Append((wxObject
*)point
);
1646 static void wx_spline_draw_point_array(wxDC
*dc
)
1648 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
1649 wxNode
*node
= wx_spline_point_list
.First();
1652 wxPoint
*point
= (wxPoint
*)node
->Data();
1655 node
= wx_spline_point_list
.First();
1659 wxSpline::wxSpline(wxList
*list
)
1664 wxSpline::~wxSpline(void)
1668 void wxSpline::DeletePoints(void)
1670 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1672 wxPoint
*point
= (wxPoint
*)node
->Data();
1680 #endif // wxUSE_SPLINES