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"
31 #include "wx/dcprint.h"
32 #include "wx/msw/private.h"
37 #if wxUSE_COMMON_DIALOGS
57 #if !USE_SHARED_LIBRARY
58 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
61 // Declarations local to this file
63 #define YSCALE(y) (yorigin - (y))
65 // #define wx_round(a) (int)((a)+.5)
67 // Default constructor
70 m_minX
= 0; m_minY
= 0; m_maxX
= 0; m_maxY
= 0;
80 m_minX
= 0; m_minY
= 0; m_maxX
= 0; m_maxY
= 0;
85 m_logicalScaleX
= 1.0;
86 m_logicalScaleY
= 1.0;
93 m_mappingMode
= MM_TEXT
;
98 m_windowExtX
= VIEWPORT_EXTENT
;
99 m_windowExtY
= VIEWPORT_EXTENT
;
100 m_logicalFunction
= -1;
102 m_backgroundBrush
= *wxWHITE_BRUSH
;
104 m_textForegroundColour
= *wxBLACK
;
105 m_textBackgroundColour
= *wxWHITE
;
107 m_colour
= wxColourDisplay();
116 SelectOldObjects(m_hDC
);
118 if ( m_canvas
== NULL
)
119 ::DeleteDC((HDC
)m_hDC
);
121 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), (HDC
)m_hDC
);
127 // This will select current objects out of the DC,
128 // which is what you have to do before deleting the
130 void wxDC::SelectOldObjects(WXHDC dc
)
136 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
137 if (m_selectedBitmap
.Ok())
139 m_selectedBitmap
.SetSelectedInto(NULL
);
145 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
150 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
155 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
160 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, TRUE
);
165 m_brush
= wxNullBrush
;
167 m_palette
= wxNullPalette
;
169 m_backgroundBrush
= wxNullBrush
;
170 m_selectedBitmap
= wxNullBitmap
;
173 void wxDC::SetClippingRegion(long cx
, long cy
, long cw
, long ch
)
178 m_clipX2
= (int)(cx
+ cw
);
179 m_clipY2
= (int)(cy
+ ch
);
181 DoClipping((WXHDC
) m_hDC
);
184 void wxDC::SetClippingRegion(const wxRegion
& region
)
186 if (!region
.GetHRGN())
189 wxRect box
= region
.GetBox();
194 m_clipX2
= box
.x
+ box
.width
;
195 m_clipY2
= box
.y
+ box
.height
;
198 SelectClipRgn((HDC
) m_hDC
, (HRGN
) region
.GetHRGN());
200 ExtSelectClipRgn((HDC
) m_hDC
, (HRGN
) region
.GetHRGN(), RGN_AND
);
204 void wxDC::DoClipping(WXHDC dc
)
206 if (m_clipping
&& dc
)
208 IntersectClipRect((HDC
) dc
, XLOG2DEV(m_clipX1
), YLOG2DEV(m_clipY1
),
209 XLOG2DEV(m_clipX2
), YLOG2DEV(m_clipY2
));
213 void wxDC::DestroyClippingRegion(void)
215 if (m_clipping
&& m_hDC
)
217 // TODO: this should restore the previous clipping region,
218 // so that OnPaint processing works correctly, and the update clipping region
219 // doesn't get destroyed after the first DestroyClippingRegion.
220 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
221 SelectClipRgn((HDC
) m_hDC
, rgn
);
227 bool wxDC::CanDrawBitmap(void) const
232 bool wxDC::CanGetTextExtent(void) const
234 // What sort of display is it?
235 int technology
= ::GetDeviceCaps((HDC
) m_hDC
, TECHNOLOGY
);
239 if (technology
!= DT_RASDISPLAY
&& technology
!= DT_RASPRINTER
)
246 void wxDC::SetPalette(const wxPalette
& palette
)
248 // Set the old object temporarily, in case the assignment deletes an object
249 // that's not yet selected out.
252 ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_oldPalette
, TRUE
);
256 m_palette
= m_palette
;
260 // Setting a NULL colourmap is a way of restoring
261 // the original colourmap
264 ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_oldPalette
, TRUE
);
271 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
273 HPALETTE oldPal
= ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
275 m_oldPalette
= (WXHPALETTE
) oldPal
;
277 ::RealizePalette((HDC
) m_hDC
);
281 void wxDC::Clear(void)
285 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
286 else if (m_selectedBitmap
.Ok())
288 rect
.left
= 0; rect
.top
= 0;
289 rect
.right
= m_selectedBitmap
.GetWidth();
290 rect
.bottom
= m_selectedBitmap
.GetHeight();
292 (void) ::SetMapMode((HDC
) m_hDC
, MM_TEXT
);
294 DWORD colour
= GetBkColor((HDC
) m_hDC
);
295 HBRUSH brush
= CreateSolidBrush(colour
);
296 FillRect((HDC
) m_hDC
, &rect
, brush
);
299 ::SetMapMode((HDC
) m_hDC
, MM_ANISOTROPIC
);
300 ::SetViewportExtEx((HDC
) m_hDC
, VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
301 ::SetWindowExtEx((HDC
) m_hDC
, m_windowExtX
, m_windowExtY
, NULL
);
302 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
303 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
306 void wxDC::FloodFill(long x
, long y
, const wxColour
& col
, int style
)
308 (void)ExtFloodFill((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
310 style
==wxFLOOD_SURFACE
?
311 FLOODFILLSURFACE
:FLOODFILLBORDER
314 CalcBoundingBox(x
, y
);
317 bool wxDC::GetPixel(long x
, long y
, wxColour
*col
) const
319 // added by steve 29.12.94 (copied from DrawPoint)
320 // returns TRUE for pixels in the color of the current pen
321 // and FALSE for all other pixels colors
322 // if col is non-NULL return the color of the pixel
324 // get the color of the pixel
325 COLORREF pixelcolor
= ::GetPixel((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
));
326 // get the color of the pen
327 COLORREF pencolor
= 0x00ffffff;
330 pencolor
= m_pen
.GetColour().GetPixel() ;
333 // return the color of the pixel
335 col
->Set(GetRValue(pixelcolor
),GetGValue(pixelcolor
),GetBValue(pixelcolor
));
337 // check, if color of the pixels is the same as the color
338 // of the current pen
339 return(pixelcolor
==pencolor
);
342 void wxDC::CrossHair(long x
, long y
)
344 // We suppose that our screen is 2000x2000 max.
350 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
351 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
), YLOG2DEV(y
));
353 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
354 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y2
));
356 CalcBoundingBox(x1
, y1
);
357 CalcBoundingBox(x2
, y2
);
360 void wxDC::DrawLine(long x1
, long y1
, long x2
, long y2
)
362 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
363 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
), YLOG2DEV(y2
));
365 /* MATTHEW: [6] New normalization */
366 #if WX_STANDARD_GRAPHICS
367 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
) + 1, YLOG2DEV(y2
));
370 CalcBoundingBox(x1
, y1
);
371 CalcBoundingBox(x2
, y2
);
374 void wxDC::DrawArc(long x1
,long y1
,long x2
,long y2
, long xc
, long yc
)
378 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
379 if (x1
==x2
&& x2
==y2
)
381 DrawEllipse(xc
,yc
,(double)(radius
*2.0),(double)(radius
*2)) ;
385 long xx1
= XLOG2DEV(x1
) ;
386 long yy1
= YLOG2DEV(y1
) ;
387 long xx2
= XLOG2DEV(x2
) ;
388 long yy2
= YLOG2DEV(y2
) ;
389 long xxc
= XLOG2DEV(xc
) ;
390 long yyc
= YLOG2DEV(yc
) ;
391 long ray
= (long) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
))) ;
393 (void)MoveToEx((HDC
) m_hDC
, (int) xx1
, (int) yy1
, NULL
);
394 long xxx1
= (long) (xxc
-ray
);
395 long yyy1
= (long) (yyc
-ray
);
396 long xxx2
= (long) (xxc
+ray
);
397 long yyy2
= (long) (yyc
+ray
);
398 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
400 // Have to add 1 to bottom-right corner of rectangle
401 // to make semi-circles look right (crooked line otherwise).
402 // Unfortunately this is not a reliable method, depends
403 // on the size of shape.
404 // TODO: figure out why this happens!
405 Pie((HDC
) m_hDC
,xxx1
,yyy1
,xxx2
+1,yyy2
+1,
409 Arc((HDC
) m_hDC
,xxx1
,yyy1
,xxx2
,yyy2
,
412 CalcBoundingBox((xc
-radius
), (yc
-radius
));
413 CalcBoundingBox((xc
+radius
), (yc
+radius
));
416 void wxDC::DrawPoint(long x
, long y
)
418 COLORREF color
= 0x00ffffff;
421 color
= m_pen
.GetColour().GetPixel() ;
424 SetPixel((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), color
);
426 CalcBoundingBox(x
, y
);
429 void wxDC::DrawPolygon(int n
, wxPoint points
[], long xoffset
, long yoffset
,int fillStyle
)
431 // Do things less efficiently if we have offsets
432 if (xoffset
!= 0 || yoffset
!= 0)
434 POINT
*cpoints
= new POINT
[n
];
436 for (i
= 0; i
< n
; i
++)
438 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
439 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
441 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
443 int prev
= SetPolyFillMode((HDC
) m_hDC
,fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
) ;
444 (void)Polygon((HDC
) m_hDC
, cpoints
, n
);
445 SetPolyFillMode((HDC
) m_hDC
,prev
) ;
451 for (i
= 0; i
< n
; i
++)
452 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
454 int prev
= SetPolyFillMode((HDC
) m_hDC
,fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
) ;
455 (void)Polygon((HDC
) m_hDC
, (POINT
*) points
, n
);
456 SetPolyFillMode((HDC
) m_hDC
,prev
) ;
460 void wxDC::DrawLines(int n
, wxPoint points
[], long xoffset
, long yoffset
)
462 // Do things less efficiently if we have offsets
463 if (xoffset
!= 0 || yoffset
!= 0)
465 POINT
*cpoints
= new POINT
[n
];
467 for (i
= 0; i
< n
; i
++)
469 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
470 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
472 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
474 (void)Polyline((HDC
) m_hDC
, cpoints
, n
);
480 for (i
= 0; i
< n
; i
++)
481 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
483 (void)Polyline((HDC
) m_hDC
, (POINT
*) points
, n
);
487 void wxDC::DrawRectangle(long x
, long y
, long width
, long height
)
490 long y2
= y
+ height
;
492 /* MATTHEW: [6] new normalization */
493 #if WX_STANDARD_GRAPHICS
494 bool do_brush
, do_pen
;
496 do_brush
= m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
;
497 do_pen
= m_pen
.Ok() && m_pen
.GetStyle() != wxTRANSPARENT
;
500 HPEN orig_pen
= NULL
;
502 if (do_pen
|| !m_pen
.Ok())
503 orig_pen
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
) ::GetStockObject(NULL_PEN
));
505 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
506 XLOG2DEV(x2
) + 1, YLOG2DEV(y2
) + 1);
508 if (do_pen
|| !m_pen
.Ok())
509 ::SelectObject((HDC
) m_hDC
, orig_pen
);
512 HBRUSH orig_brush
= NULL
;
514 if (do_brush
|| !m_brush
.Ok())
515 orig_brush
= (HBRUSH
) ::SelectObject((HDC
) m_hDC
, (HBRUSH
) ::GetStockObject(NULL_BRUSH
));
517 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
518 XLOG2DEV(x2
), YLOG2DEV(y2
));
520 if (do_brush
|| !m_brush
.Ok())
521 ::SelectObject((HDC
) m_hDC
, orig_brush
);
524 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
527 CalcBoundingBox(x
, y
);
528 CalcBoundingBox(x2
, y2
);
531 void wxDC::DrawRoundedRectangle(long x
, long y
, long width
, long height
, double radius
)
533 // Now, a negative radius value is interpreted to mean
534 // 'the proportion of the smallest X or Y dimension'
538 double smallest
= 0.0;
543 radius
= (- radius
* smallest
);
547 long y2
= (y
+height
);
549 (void)RoundRect((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
550 YLOG2DEV(y2
), 2*XLOG2DEV(radius
), 2*YLOG2DEV(radius
));
552 CalcBoundingBox(x
, y
);
553 CalcBoundingBox(x2
, y2
);
556 void wxDC::DrawEllipse(long x
, long y
, long width
, long height
)
559 long y2
= (y
+height
);
561 (void)Ellipse((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
563 CalcBoundingBox(x
, y
);
564 CalcBoundingBox(x2
, y2
);
567 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
568 void wxDC::DrawEllipticArc(long x
,long y
,long w
,long h
,double sa
,double ea
)
573 const double deg2rad
= 3.14159265359 / 180.0;
574 int rx1
= XLOG2DEV(x
+w
/2);
575 int ry1
= YLOG2DEV(y
+h
/2);
578 rx1
+= (int)(100.0 * abs(w
) * cos(sa
* deg2rad
));
579 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
* deg2rad
));
580 rx2
+= (int)(100.0 * abs(w
) * cos(ea
* deg2rad
));
581 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
* deg2rad
));
583 // draw pie with NULL_PEN first and then outline otherwise a line is
584 // drawn from the start and end points to the centre
585 HPEN orig_pen
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
) ::GetStockObject(NULL_PEN
));
588 (void)Pie((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
593 (void)Pie((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
594 rx1
, ry1
-1, rx2
, ry2
-1);
596 ::SelectObject((HDC
) m_hDC
, orig_pen
);
597 (void)Arc((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
600 CalcBoundingBox(x
, y
);
601 CalcBoundingBox(x2
, y2
);
604 void wxDC::DrawIcon(const wxIcon
& icon
, long x
, long y
)
606 ::DrawIcon((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON());
607 CalcBoundingBox(x
, y
);
608 CalcBoundingBox(x
+icon
.GetWidth(), y
+icon
.GetHeight());
611 void wxDC::DrawBitmap( const wxBitmap
&bmp
, long x
, long y
, bool useMask
)
616 // If we're not drawing transparently, and not drawing to a printer,
617 // optimize this function to use Windows functions.
618 if (!useMask
&& !IsKindOf(CLASSINFO(wxPrinterDC
)))
620 HDC cdc
= (HDC
)m_hDC
;
621 HDC memdc
= ::CreateCompatibleDC( cdc
);
622 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
623 ::SelectObject( memdc
, hbitmap
);
624 ::BitBlt( cdc
, x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), memdc
, 0, 0, SRCCOPY
);
625 ::SelectObject( memdc
, 0 );
630 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API level
632 memDC
.SelectObject(bmp
);
634 /* Not sure if we need this. The mask should leave the
635 * masked areas as per the original background of this DC.
638 // There might be transparent areas, so make these
639 // the same colour as this DC
640 memDC.SetBackground(* GetBackground());
644 Blit(x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), & memDC
, 0, 0, wxCOPY
, useMask
);
646 memDC
.SelectObject(wxNullBitmap
);
650 void wxDC::SetFont(const wxFont
& the_font
)
652 // Set the old object temporarily, in case the assignment deletes an object
653 // that's not yet selected out.
656 ::SelectObject((HDC
) m_hDC
, (HFONT
) m_oldFont
);
665 ::SelectObject((HDC
) m_hDC
, (HFONT
) m_oldFont
);
669 if (m_font
.Ok() && m_font
.GetResourceHandle())
671 HFONT f
= (HFONT
) ::SelectObject((HDC
) m_hDC
, (HFONT
) m_font
.GetResourceHandle());
674 wxDebugMsg("::SelectObject failed in wxDC::SetFont.");
677 m_oldFont
= (WXHFONT
) f
;
681 void wxDC::SetPen(const wxPen
& pen
)
683 // Set the old object temporarily, in case the assignment deletes an object
684 // that's not yet selected out.
687 ::SelectObject((HDC
) m_hDC
, (HPEN
) m_oldPen
);
696 ::SelectObject((HDC
) m_hDC
, (HPEN
) m_oldPen
);
702 if (m_pen
.GetResourceHandle())
704 HPEN p
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
)m_pen
.GetResourceHandle()) ;
706 m_oldPen
= (WXHPEN
) p
;
711 void wxDC::SetBrush(const wxBrush
& brush
)
713 // Set the old object temporarily, in case the assignment deletes an object
714 // that's not yet selected out.
717 ::SelectObject((HDC
) m_hDC
, (HBRUSH
) m_oldBrush
);
726 ::SelectObject((HDC
) m_hDC
, (HBRUSH
) m_oldBrush
);
732 if (m_brush
.GetResourceHandle())
735 b
= (HBRUSH
) ::SelectObject((HDC
) m_hDC
, (HBRUSH
)m_brush
.GetResourceHandle()) ;
737 m_oldBrush
= (WXHBRUSH
) b
;
742 void wxDC::DrawText(const wxString
& text
, long x
, long y
, bool use16bit
)
744 // Should be unnecessary: SetFont should have done this already.
746 if (m_font
.Ok() && m_font
.GetResourceHandle())
748 HFONT f
= (HFONT
) ::SelectObject((HDC
) m_hDC
, (HFONT
) m_font
.GetResourceHandle());
750 m_oldFont
= (WXHFONT
) f
;
754 if (m_textForegroundColour
.Ok())
755 SetTextColor((HDC
) m_hDC
, m_textForegroundColour
.GetPixel() ) ;
757 DWORD old_background
= 0;
758 if (m_textBackgroundColour
.Ok())
760 old_background
= SetBkColor((HDC
) m_hDC
, m_textBackgroundColour
.GetPixel() ) ;
763 if (m_backgroundMode
== wxTRANSPARENT
)
764 SetBkMode((HDC
) m_hDC
, TRANSPARENT
);
766 SetBkMode((HDC
) m_hDC
, OPAQUE
);
768 (void)TextOut((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), (char *) (const char *)text
, strlen((const char *)text
));
770 if (m_textBackgroundColour
.Ok())
771 (void)SetBkColor((HDC
) m_hDC
, old_background
);
773 CalcBoundingBox(x
, y
);
776 GetTextExtent(text
, &w
, &h
);
777 CalcBoundingBox((x
+ w
), (y
+ h
));
780 void wxDC::SetBackground(const wxBrush
& brush
)
782 m_backgroundBrush
= brush
;
784 if (!m_backgroundBrush
.Ok())
789 bool customColours
= TRUE
;
790 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
791 // change background colours from the control-panel specified colours.
792 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
793 customColours
= FALSE
;
797 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
799 m_canvas
->m_backgroundTransparent
= TRUE
;
803 m_canvas
->SetBackgroundColour(m_backgroundBrush
.GetColour());
804 m_canvas
->m_backgroundTransparent
= FALSE
;
808 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel() ;
810 (void)SetBkColor((HDC
) m_hDC
, new_color
);
814 void wxDC::SetBackgroundMode(int mode
)
816 m_backgroundMode
= mode
;
818 if (m_backgroundMode
== wxTRANSPARENT
)
819 ::SetBkMode((HDC
) m_hDC
, TRANSPARENT
);
821 ::SetBkMode((HDC
) m_hDC
, OPAQUE
);
824 void wxDC::SetLogicalFunction(int function
)
826 m_logicalFunction
= function
;
828 SetRop((WXHDC
) m_hDC
);
831 void wxDC::SetRop(WXHDC dc
)
833 if (!dc
|| m_logicalFunction
< 0)
837 // These may be wrong
838 switch (m_logicalFunction
)
840 // case wxXOR: c_rop = R2_XORPEN; break;
841 case wxXOR
: c_rop
= R2_NOTXORPEN
; break;
842 case wxINVERT
: c_rop
= R2_NOT
; break;
843 case wxOR_REVERSE
: c_rop
= R2_MERGEPENNOT
; break;
844 case wxAND_REVERSE
: c_rop
= R2_MASKPENNOT
; break;
845 case wxCLEAR
: c_rop
= R2_WHITE
; break;
846 case wxSET
: c_rop
= R2_BLACK
; break;
847 case wxSRC_INVERT
: c_rop
= R2_NOTCOPYPEN
; break;
848 case wxOR_INVERT
: c_rop
= R2_MERGENOTPEN
; break;
849 case wxAND
: c_rop
= R2_MASKPEN
; break;
850 case wxOR
: c_rop
= R2_MERGEPEN
; break;
851 case wxAND_INVERT
: c_rop
= R2_MASKNOTPEN
; break;
856 c_rop
= R2_COPYPEN
; break;
858 SetROP2((HDC
) dc
, c_rop
);
861 bool wxDC::StartDoc(const wxString
& message
)
863 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
867 docinfo
.cbSize
= sizeof(DOCINFO
);
868 docinfo
.lpszDocName
= (const char *)message
;
870 if (m_filename
.IsEmpty())
871 docinfo
.lpszOutput
= NULL
;
873 docinfo
.lpszOutput
= (const char *)m_filename
;
875 #if defined(__WIN95__)
876 docinfo
.lpszDatatype
= NULL
;
885 ::StartDoc((HDC
) m_hDC
, &docinfo
);
888 ::StartDocW((HDC
) m_hDC
, &docinfo
);
890 ::StartDocA((HDC
) m_hDC
, &docinfo
);
897 DWORD lastError
= GetLastError();
898 wxDebugMsg("wxDC::StartDoc failed with error: %d\n", lastError
);
905 void wxDC::EndDoc(void)
907 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
909 if (m_hDC
) ::EndDoc((HDC
) m_hDC
);
912 void wxDC::StartPage(void)
914 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
917 ::StartPage((HDC
) m_hDC
);
920 void wxDC::EndPage(void)
922 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
925 ::EndPage((HDC
) m_hDC
);
928 long wxDC::GetCharHeight(void) const
930 TEXTMETRIC lpTextMetric
;
932 GetTextMetrics((HDC
) m_hDC
, &lpTextMetric
);
934 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
937 long wxDC::GetCharWidth(void) const
939 TEXTMETRIC lpTextMetric
;
941 GetTextMetrics((HDC
) m_hDC
, &lpTextMetric
);
943 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
946 void wxDC::GetTextExtent(const wxString
& string
, long *x
, long *y
,
947 long *descent
, long *externalLeading
, wxFont
*theFont
, bool use16bit
) const
949 wxFont
*fontToUse
= (wxFont
*) theFont
;
951 fontToUse
= (wxFont
*) &m_font
;
956 GetTextExtentPoint((HDC
) m_hDC
, (char *)(const char *) string
, strlen((char *)(const char *) string
), &sizeRect
);
957 GetTextMetrics((HDC
) m_hDC
, &tm
);
959 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
960 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
961 if (descent
) *descent
= tm
.tmDescent
;
962 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
965 void wxDC::SetMapMode(int mode
)
967 m_mappingMode
= mode
;
970 int pixel_height
= 0;
974 pixel_width
= GetDeviceCaps((HDC
) m_hDC
, HORZRES
);
975 pixel_height
= GetDeviceCaps((HDC
) m_hDC
, VERTRES
);
976 mm_width
= GetDeviceCaps((HDC
) m_hDC
, HORZSIZE
);
977 mm_height
= GetDeviceCaps((HDC
) m_hDC
, VERTSIZE
);
979 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
984 double mm2pixelsX
= pixel_width
/mm_width
;
985 double mm2pixelsY
= pixel_height
/mm_height
;
991 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
992 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
997 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
998 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
1003 m_logicalScaleX
= mm2pixelsX
;
1004 m_logicalScaleY
= mm2pixelsY
;
1009 m_logicalScaleX
= (mm2pixelsX
/10.0);
1010 m_logicalScaleY
= (mm2pixelsY
/10.0);
1016 m_logicalScaleX
= 1.0;
1017 m_logicalScaleY
= 1.0;
1022 if (::GetMapMode((HDC
) m_hDC
) != MM_ANISOTROPIC
)
1023 ::SetMapMode((HDC
) m_hDC
, MM_ANISOTROPIC
);
1025 SetViewportExtEx((HDC
) m_hDC
, VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1026 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1027 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1028 ::SetWindowExtEx((HDC
) m_hDC
, m_windowExtX
, m_windowExtY
, NULL
);
1029 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1030 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1033 void wxDC::SetUserScale(double x
, double y
)
1038 SetMapMode(m_mappingMode
);
1041 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1043 m_signX
= xLeftRight
? 1 : -1;
1044 m_signY
= yBottomUp
? -1 : 1;
1046 SetMapMode(m_mappingMode
);
1049 void wxDC::SetSystemScale(double x
, double y
)
1054 SetMapMode(m_mappingMode
);
1057 void wxDC::SetLogicalOrigin(long x
, long y
)
1059 m_logicalOriginX
= x
;
1060 m_logicalOriginY
= y
;
1062 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1065 void wxDC::SetDeviceOrigin(long x
, long y
)
1067 m_deviceOriginX
= x
;
1068 m_deviceOriginY
= y
;
1070 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1073 long wxDC::DeviceToLogicalX(long x
) const
1075 return (long) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
) - m_logicalOriginX
) ;
1078 long wxDC::DeviceToLogicalXRel(long x
) const
1080 return (long) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
)) ;
1083 long wxDC::DeviceToLogicalY(long y
) const
1085 return (long) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
) - m_logicalOriginY
) ;
1088 long wxDC::DeviceToLogicalYRel(long y
) const
1090 return (long) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
)) ;
1093 long wxDC::LogicalToDeviceX(long x
) const
1095 return (long) (floor((x
) - m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
+ m_deviceOriginX
) ;
1098 long wxDC::LogicalToDeviceXRel(long x
) const
1100 return (long) (floor(x
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
) ;
1103 long wxDC::LogicalToDeviceY(long y
) const
1105 return (long) (floor((y
) - m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
+ m_deviceOriginY
);
1108 long wxDC::LogicalToDeviceYRel(long y
) const
1110 return (long) (floor(y
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
) ;
1113 // This group of functions may not do any conversion
1114 // if m_scaleGDI is TRUE, since the HDC does the
1115 // conversion automatically.
1117 long wxDC::ImplDeviceToLogicalX(long x
) const
1119 // return (m_scaleGDI ? x : DeviceToLogicalX(x));
1123 long wxDC::ImplDeviceToLogicalY(long y
) const
1125 // return (m_scaleGDI ? y : DeviceToLogicalY(y));
1129 long wxDC::ImplDeviceToLogicalXRel(long x
) const
1131 // return (m_scaleGDI ? x : DeviceToLogicalXRel(x));
1135 long wxDC::ImplDeviceToLogicalYRel(long y
) const
1137 // return (m_scaleGDI ? y : DeviceToLogicalYRel(y));
1141 long wxDC::ImplLogicalToDeviceX(long x
) const
1143 // return (m_scaleGDI ? (floor(double(x))) : LogicalToDeviceX(x));
1147 long wxDC::ImplLogicalToDeviceY(long y
) const
1149 // return (m_scaleGDI ? (floor(double(y))) : LogicalToDeviceY(y));
1153 long wxDC::ImplLogicalToDeviceXRel(long x
) const
1155 // return (m_scaleGDI ? (floor(double(x))) : LogicalToDeviceXRel(x));
1159 long wxDC::ImplLogicalToDeviceYRel(long y
) const
1161 // return (m_scaleGDI ? (floor(double(y))) : LogicalToDeviceYRel(y));
1165 bool wxDC::Blit(long xdest
, long ydest
, long width
, long height
,
1166 wxDC
*source
, long xsrc
, long ysrc
, int rop
, bool useMask
)
1168 long xdest1
= xdest
;
1169 long ydest1
= ydest
;
1173 // Chris Breeze 18/5/98: use text foreground/background colours
1174 // when blitting from 1-bit bitmaps
1175 COLORREF old_textground
= ::GetTextColor((HDC
)m_hDC
);
1176 COLORREF old_background
= ::GetBkColor((HDC
)m_hDC
);
1177 if (m_textForegroundColour
.Ok())
1179 ::SetTextColor((HDC
) m_hDC
, m_textForegroundColour
.GetPixel() ) ;
1181 if (m_textBackgroundColour
.Ok())
1183 ::SetBkColor((HDC
) m_hDC
, m_textBackgroundColour
.GetPixel() ) ;
1186 DWORD dwRop
= rop
== wxCOPY
? SRCCOPY
:
1187 rop
== wxCLEAR
? WHITENESS
:
1188 rop
== wxSET
? BLACKNESS
:
1189 rop
== wxINVERT
? DSTINVERT
:
1190 rop
== wxAND
? MERGECOPY
:
1191 rop
== wxOR
? MERGEPAINT
:
1192 rop
== wxSRC_INVERT
? NOTSRCCOPY
:
1193 rop
== wxXOR
? SRCINVERT
:
1194 rop
== wxOR_REVERSE
? MERGEPAINT
:
1195 rop
== wxAND_REVERSE
? SRCERASE
:
1196 rop
== wxSRC_OR
? SRCPAINT
:
1197 rop
== wxSRC_AND
? SRCAND
:
1200 bool success
= TRUE
;
1201 if (useMask
&& source
->m_selectedBitmap
.Ok() && source
->m_selectedBitmap
.GetMask())
1205 // Not implemented under Win95 (or maybe a specific device?)
1206 if (MaskBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1207 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap(),
1217 HDC dc_mask
= CreateCompatibleDC((HDC
) source
->m_hDC
);
1218 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1219 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1220 dc_mask
, xsrc1
, ysrc1
, 0x00220326 /* NOTSRCAND */) != 0);
1221 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1222 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, SRCPAINT
) != 0);
1223 ::SelectObject(dc_mask
, 0);
1224 ::DeleteDC(dc_mask
);
1226 // New code from Chris Breeze, 15/7/98
1227 // Blit bitmap with mask
1229 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1231 // If we are printing source colours are screen colours
1232 // not printer colours and so we need copy the bitmap
1235 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1236 HDC dc_src
= (HDC
) source
->m_hDC
;
1238 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1239 for (int x
= 0; x
< width
; x
++)
1241 for (int y
= 0; y
< height
; y
++)
1243 COLORREF cref
= ::GetPixel(dc_mask
, x
, y
);
1246 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1247 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1248 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1249 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1250 ::DeleteObject(brush
);
1254 ::SelectObject(dc_mask
, 0);
1255 ::DeleteDC(dc_mask
);
1259 // create a temp buffer bitmap and DCs to access it and the mask
1260 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1261 HDC dc_buffer
= ::CreateCompatibleDC((HDC
) m_hDC
);
1262 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap((HDC
) m_hDC
, width
, height
);
1263 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1264 ::SelectObject(dc_buffer
, buffer_bmap
);
1266 // copy dest to buffer
1267 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1268 (HDC
) m_hDC
, xdest1
, ydest1
, SRCCOPY
);
1270 // copy src to buffer using selected raster op
1271 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1272 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, dwRop
);
1274 // set masked area in buffer to BLACK (pixel value 0)
1275 COLORREF prevBkCol
= ::SetBkColor((HDC
) m_hDC
, RGB(255, 255, 255));
1276 COLORREF prevCol
= ::SetTextColor((HDC
) m_hDC
, RGB(0, 0, 0));
1277 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1278 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1280 // set unmasked area in dest to BLACK
1281 ::SetBkColor((HDC
) m_hDC
, RGB(0, 0, 0));
1282 ::SetTextColor((HDC
) m_hDC
, RGB(255, 255, 255));
1283 ::BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1284 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1285 ::SetBkColor((HDC
) m_hDC
, prevBkCol
); // restore colours to original values
1286 ::SetTextColor((HDC
) m_hDC
, prevCol
);
1288 // OR buffer to dest
1289 success
= (::BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1290 dc_buffer
, 0, 0, SRCPAINT
) != 0);
1292 // tidy up temporary DCs and bitmap
1293 ::SelectObject(dc_mask
, 0);
1294 ::DeleteDC(dc_mask
);
1295 ::SelectObject(dc_buffer
, 0);
1296 ::DeleteDC(dc_buffer
);
1297 ::DeleteObject(buffer_bmap
);
1303 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1305 // If we are printing, source colours are screen colours
1306 // not printer colours and so we need copy the bitmap
1308 HDC dc_src
= (HDC
) source
->m_hDC
;
1310 for (int x
= 0; x
< width
; x
++)
1312 for (int y
= 0; y
< height
; y
++)
1314 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1315 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1316 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1317 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1318 ::DeleteObject(brush
);
1324 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
, (HDC
) source
->m_hDC
,
1325 xsrc1
, ysrc1
, dwRop
) != 0);
1328 ::SetTextColor((HDC
)m_hDC
, old_textground
);
1329 ::SetBkColor((HDC
)m_hDC
, old_background
);
1334 void wxDC::GetSize(int* width
, int* height
) const
1336 long w
=::GetDeviceCaps((HDC
) m_hDC
,HORZRES
);
1337 long h
=::GetDeviceCaps((HDC
) m_hDC
,VERTRES
);
1342 void wxDC::GetSizeMM(long *width
, long *height
) const
1344 long w
=::GetDeviceCaps((HDC
) m_hDC
,HORZSIZE
);
1345 long h
=::GetDeviceCaps((HDC
) m_hDC
,VERTSIZE
);
1350 void wxDC::DrawPolygon(wxList
*list
, long xoffset
, long yoffset
,int fillStyle
)
1352 int n
= list
->Number();
1353 wxPoint
*points
= new wxPoint
[n
];
1356 for(wxNode
*node
= list
->First(); node
; node
= node
->Next()) {
1357 wxPoint
*point
= (wxPoint
*)node
->Data();
1358 points
[i
].x
= point
->x
;
1359 points
[i
++].y
= point
->y
;
1361 DrawPolygon(n
, points
, xoffset
, yoffset
,fillStyle
);
1365 void wxDC::DrawLines(wxList
*list
, long xoffset
, long yoffset
)
1367 int n
= list
->Number();
1368 wxPoint
*points
= new wxPoint
[n
];
1371 for(wxNode
*node
= list
->First(); node
; node
= node
->Next()) {
1372 wxPoint
*point
= (wxPoint
*)node
->Data();
1373 points
[i
].x
= point
->x
;
1374 points
[i
++].y
= point
->y
;
1376 DrawLines(n
, points
, xoffset
, yoffset
);
1380 void wxDC::SetTextForeground(const wxColour
& colour
)
1382 m_textForegroundColour
= colour
;
1385 void wxDC::SetTextBackground(const wxColour
& colour
)
1387 m_textBackgroundColour
= colour
;
1390 // For use by wxWindows only, unless custom units are required.
1391 void wxDC::SetLogicalScale(double x
, double y
)
1393 m_logicalScaleX
= x
;
1394 m_logicalScaleY
= y
;
1397 void wxDC::CalcBoundingBox(long x
, long y
)
1399 if (x
< m_minX
) m_minX
= x
;
1400 if (y
< m_minY
) m_minY
= y
;
1401 if (x
> m_maxX
) m_maxX
= x
;
1402 if (y
> m_maxY
) m_maxY
= y
;
1405 void wxDC::GetClippingBox(long *x
,long *y
,long *w
,long *h
) const
1411 *w
= (m_clipX2
- m_clipX1
) ;
1412 *h
= (m_clipY2
- m_clipY1
) ;
1415 *x
= *y
= *w
= *h
= 0 ;
1418 #if WXWIN_COMPATIBILITY
1419 void wxDC::GetTextExtent(const wxString
& string
, float *x
, float *y
,
1420 float *descent
, float *externalLeading
,
1421 wxFont
*theFont
, bool use16bit
) const
1423 long x1
, y1
, descent1
, externalLeading1
;
1424 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1427 *descent
= descent1
;
1428 if (externalLeading
)
1429 *externalLeading
= externalLeading1
;
1433 int wxDC::GetDepth(void) const
1435 return (int) ::GetDeviceCaps((HDC
) m_hDC
,BITSPIXEL
);
1440 // Make a 3-point spline
1441 void wxDC::DrawSpline(long x1
, long y1
, long x2
, long y2
, long x3
, long y3
)
1443 wxList
*point_list
= new wxList
;
1445 wxPoint
*point1
= new wxPoint
;
1446 point1
->x
= x1
; point1
->y
= y1
;
1447 point_list
->Append((wxObject
*)point1
);
1449 wxPoint
*point2
= new wxPoint
;
1450 point2
->x
= x2
; point2
->y
= y2
;
1451 point_list
->Append((wxObject
*)point2
);
1453 wxPoint
*point3
= new wxPoint
;
1454 point3
->x
= x3
; point3
->y
= y3
;
1455 point_list
->Append((wxObject
*)point3
);
1457 DrawSpline(point_list
);
1459 for(wxNode
*node
= point_list
->First(); node
; node
= node
->Next()) {
1460 wxPoint
*p
= (wxPoint
*)node
->Data();
1466 ////#define wx_round(a) (int)((a)+.5)
1467 //#define wx_round(a) (a)
1469 class wxSpline
: public wxObject
1475 wxSpline(wxList
*list
);
1476 void DeletePoints(void);
1478 // Doesn't delete points
1482 void wxDC::DrawSpline(int n
, wxPoint points
[])
1486 for (i
=0; i
< n
; i
++)
1487 list
.Append((wxObject
*)&points
[i
]);
1488 DrawSpline((wxList
*)&list
);
1491 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1493 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1494 double a3
, double b3
, double a4
, double b4
);
1495 void wx_clear_stack(void);
1496 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1497 double *y3
, double *x4
, double *y4
);
1498 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1499 double x4
, double y4
);
1500 static bool wx_spline_add_point(double x
, double y
);
1501 static void wx_spline_draw_point_array(wxDC
*dc
);
1502 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1504 void wxDC::DrawSpline(wxList
*list
)
1506 wxSpline
spline(list
);
1508 wx_draw_open_spline(this, &spline
);
1512 wxList wx_spline_point_list
;
1514 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1517 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1518 double x1
, y1
, x2
, y2
;
1520 wxNode
*node
= spline
->points
->First();
1521 p
= (wxPoint
*)node
->Data();
1526 node
= node
->Next();
1527 p
= (wxPoint
*)node
->Data();
1531 cx1
= (double)((x1
+ x2
) / 2);
1532 cy1
= (double)((y1
+ y2
) / 2);
1533 cx2
= (double)((cx1
+ x2
) / 2);
1534 cy2
= (double)((cy1
+ y2
) / 2);
1536 wx_spline_add_point(x1
, y1
);
1538 while ((node
= node
->Next()) != NULL
)
1540 p
= (wxPoint
*)node
->Data();
1545 cx4
= (double)(x1
+ x2
) / 2;
1546 cy4
= (double)(y1
+ y2
) / 2;
1547 cx3
= (double)(x1
+ cx4
) / 2;
1548 cy3
= (double)(y1
+ cy4
) / 2;
1550 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1554 cx2
= (double)(cx1
+ x2
) / 2;
1555 cy2
= (double)(cy1
+ y2
) / 2;
1558 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1559 wx_spline_add_point(x2
, y2
);
1561 wx_spline_draw_point_array(dc
);
1565 /********************* CURVES FOR SPLINES *****************************
1567 The following spline drawing routine is from
1569 "An Algorithm for High-Speed Curve Generation"
1570 by George Merrill Chaikin,
1571 Computer Graphics and Image Processing, 3, Academic Press,
1576 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1577 Computer Graphics and Image Processing, 4, Academic Press,
1580 ***********************************************************************/
1582 #define half(z1, z2) ((z1+z2)/2.0)
1585 /* iterative version */
1587 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1590 register double xmid
, ymid
;
1591 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1594 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1596 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1597 xmid
= (double)half(x2
, x3
);
1598 ymid
= (double)half(y2
, y3
);
1599 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1600 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1601 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1602 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1604 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1605 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1606 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1607 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1613 /* utilities used by spline drawing routines */
1616 typedef struct wx_spline_stack_struct
{
1617 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1621 #define SPLINE_STACK_DEPTH 20
1622 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1623 static Stack
*wx_stack_top
;
1624 static int wx_stack_count
;
1626 void wx_clear_stack(void)
1628 wx_stack_top
= wx_spline_stack
;
1632 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1634 wx_stack_top
->x1
= x1
;
1635 wx_stack_top
->y1
= y1
;
1636 wx_stack_top
->x2
= x2
;
1637 wx_stack_top
->y2
= y2
;
1638 wx_stack_top
->x3
= x3
;
1639 wx_stack_top
->y3
= y3
;
1640 wx_stack_top
->x4
= x4
;
1641 wx_stack_top
->y4
= y4
;
1646 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1647 double *x3
, double *y3
, double *x4
, double *y4
)
1649 if (wx_stack_count
== 0)
1653 *x1
= wx_stack_top
->x1
;
1654 *y1
= wx_stack_top
->y1
;
1655 *x2
= wx_stack_top
->x2
;
1656 *y2
= wx_stack_top
->y2
;
1657 *x3
= wx_stack_top
->x3
;
1658 *y3
= wx_stack_top
->y3
;
1659 *x4
= wx_stack_top
->x4
;
1660 *y4
= wx_stack_top
->y4
;
1664 static bool wx_spline_add_point(double x
, double y
)
1666 wxPoint
*point
= new wxPoint
;
1669 wx_spline_point_list
.Append((wxObject
*)point
);
1673 static void wx_spline_draw_point_array(wxDC
*dc
)
1675 dc
->DrawLines(&wx_spline_point_list
, (double)0.0, (double)0.0);
1676 wxNode
*node
= wx_spline_point_list
.First();
1679 wxPoint
*point
= (wxPoint
*)node
->Data();
1682 node
= wx_spline_point_list
.First();
1686 wxSpline::wxSpline(wxList
*list
)
1691 wxSpline::~wxSpline(void)
1695 void wxSpline::DeletePoints(void)
1697 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1699 wxPoint
*point
= (wxPoint
*)node
->Data();
1707 #endif // wxUSE_SPLINES