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
;
197 ExtSelectClipRgn((HDC
) m_hDC
, (HRGN
) region
.GetHRGN(), RGN_AND
);
200 void wxDC::DoClipping(WXHDC dc
)
202 if (m_clipping
&& dc
)
204 IntersectClipRect((HDC
) dc
, XLOG2DEV(m_clipX1
), YLOG2DEV(m_clipY1
),
205 XLOG2DEV(m_clipX2
), YLOG2DEV(m_clipY2
));
209 void wxDC::DestroyClippingRegion(void)
211 if (m_clipping
&& m_hDC
)
213 // TODO: this should restore the previous clipping region,
214 // so that OnPaint processing works correctly, and the update clipping region
215 // doesn't get destroyed after the first DestroyClippingRegion.
216 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
217 SelectClipRgn((HDC
) m_hDC
, rgn
);
223 bool wxDC::CanDrawBitmap(void) const
228 bool wxDC::CanGetTextExtent(void) const
230 // What sort of display is it?
231 int technology
= ::GetDeviceCaps((HDC
) m_hDC
, TECHNOLOGY
);
235 if (technology
!= DT_RASDISPLAY
&& technology
!= DT_RASPRINTER
)
242 void wxDC::SetPalette(const wxPalette
& palette
)
244 // Set the old object temporarily, in case the assignment deletes an object
245 // that's not yet selected out.
248 ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_oldPalette
, TRUE
);
252 m_palette
= m_palette
;
256 // Setting a NULL colourmap is a way of restoring
257 // the original colourmap
260 ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_oldPalette
, TRUE
);
267 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
269 HPALETTE oldPal
= ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
271 m_oldPalette
= (WXHPALETTE
) oldPal
;
273 ::RealizePalette((HDC
) m_hDC
);
277 void wxDC::Clear(void)
281 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
282 else if (m_selectedBitmap
.Ok())
284 rect
.left
= 0; rect
.top
= 0;
285 rect
.right
= m_selectedBitmap
.GetWidth();
286 rect
.bottom
= m_selectedBitmap
.GetHeight();
288 (void) ::SetMapMode((HDC
) m_hDC
, MM_TEXT
);
290 DWORD colour
= GetBkColor((HDC
) m_hDC
);
291 HBRUSH brush
= CreateSolidBrush(colour
);
292 FillRect((HDC
) m_hDC
, &rect
, brush
);
295 ::SetMapMode((HDC
) m_hDC
, MM_ANISOTROPIC
);
296 ::SetViewportExtEx((HDC
) m_hDC
, VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
297 ::SetWindowExtEx((HDC
) m_hDC
, m_windowExtX
, m_windowExtY
, NULL
);
298 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
299 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
302 void wxDC::FloodFill(long x
, long y
, const wxColour
& col
, int style
)
304 (void)ExtFloodFill((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
306 style
==wxFLOOD_SURFACE
?
307 FLOODFILLSURFACE
:FLOODFILLBORDER
310 CalcBoundingBox(x
, y
);
313 bool wxDC::GetPixel(long x
, long y
, wxColour
*col
) const
315 // added by steve 29.12.94 (copied from DrawPoint)
316 // returns TRUE for pixels in the color of the current pen
317 // and FALSE for all other pixels colors
318 // if col is non-NULL return the color of the pixel
320 // get the color of the pixel
321 COLORREF pixelcolor
= ::GetPixel((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
));
322 // get the color of the pen
323 COLORREF pencolor
= 0x00ffffff;
326 pencolor
= m_pen
.GetColour().GetPixel() ;
329 // return the color of the pixel
331 col
->Set(GetRValue(pixelcolor
),GetGValue(pixelcolor
),GetBValue(pixelcolor
));
333 // check, if color of the pixels is the same as the color
334 // of the current pen
335 return(pixelcolor
==pencolor
);
338 void wxDC::CrossHair(long x
, long y
)
340 // We suppose that our screen is 2000x2000 max.
346 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
347 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
), YLOG2DEV(y
));
349 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
350 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y2
));
352 CalcBoundingBox(x1
, y1
);
353 CalcBoundingBox(x2
, y2
);
356 void wxDC::DrawLine(long x1
, long y1
, long x2
, long y2
)
358 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
359 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
), YLOG2DEV(y2
));
361 /* MATTHEW: [6] New normalization */
362 #if WX_STANDARD_GRAPHICS
363 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
) + 1, YLOG2DEV(y2
));
366 CalcBoundingBox(x1
, y1
);
367 CalcBoundingBox(x2
, y2
);
370 void wxDC::DrawArc(long x1
,long y1
,long x2
,long y2
, long xc
, long yc
)
374 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
375 if (x1
==x2
&& x2
==y2
)
377 DrawEllipse(xc
,yc
,(double)(radius
*2.0),(double)(radius
*2)) ;
381 long xx1
= XLOG2DEV(x1
) ;
382 long yy1
= YLOG2DEV(y1
) ;
383 long xx2
= XLOG2DEV(x2
) ;
384 long yy2
= YLOG2DEV(y2
) ;
385 long xxc
= XLOG2DEV(xc
) ;
386 long yyc
= YLOG2DEV(yc
) ;
387 long ray
= (long) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
))) ;
389 (void)MoveToEx((HDC
) m_hDC
, (int) xx1
, (int) yy1
, NULL
);
390 long xxx1
= (long) (xxc
-ray
);
391 long yyy1
= (long) (yyc
-ray
);
392 long xxx2
= (long) (xxc
+ray
);
393 long yyy2
= (long) (yyc
+ray
);
394 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
396 // Have to add 1 to bottom-right corner of rectangle
397 // to make semi-circles look right (crooked line otherwise).
398 // Unfortunately this is not a reliable method, depends
399 // on the size of shape.
400 // TODO: figure out why this happens!
401 Pie((HDC
) m_hDC
,xxx1
,yyy1
,xxx2
+1,yyy2
+1,
405 Arc((HDC
) m_hDC
,xxx1
,yyy1
,xxx2
,yyy2
,
408 CalcBoundingBox((xc
-radius
), (yc
-radius
));
409 CalcBoundingBox((xc
+radius
), (yc
+radius
));
412 void wxDC::DrawPoint(long x
, long y
)
414 COLORREF color
= 0x00ffffff;
417 color
= m_pen
.GetColour().GetPixel() ;
420 SetPixel((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), color
);
422 CalcBoundingBox(x
, y
);
425 void wxDC::DrawPolygon(int n
, wxPoint points
[], long xoffset
, long yoffset
,int fillStyle
)
427 // Do things less efficiently if we have offsets
428 if (xoffset
!= 0 || yoffset
!= 0)
430 POINT
*cpoints
= new POINT
[n
];
432 for (i
= 0; i
< n
; i
++)
434 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
435 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
437 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
439 int prev
= SetPolyFillMode((HDC
) m_hDC
,fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
) ;
440 (void)Polygon((HDC
) m_hDC
, cpoints
, n
);
441 SetPolyFillMode((HDC
) m_hDC
,prev
) ;
447 for (i
= 0; i
< n
; i
++)
448 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
450 int prev
= SetPolyFillMode((HDC
) m_hDC
,fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
) ;
451 (void)Polygon((HDC
) m_hDC
, (POINT
*) points
, n
);
452 SetPolyFillMode((HDC
) m_hDC
,prev
) ;
456 void wxDC::DrawLines(int n
, wxPoint points
[], long xoffset
, long yoffset
)
458 // Do things less efficiently if we have offsets
459 if (xoffset
!= 0 || yoffset
!= 0)
461 POINT
*cpoints
= new POINT
[n
];
463 for (i
= 0; i
< n
; i
++)
465 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
466 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
468 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
470 (void)Polyline((HDC
) m_hDC
, cpoints
, n
);
476 for (i
= 0; i
< n
; i
++)
477 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
479 (void)Polyline((HDC
) m_hDC
, (POINT
*) points
, n
);
483 void wxDC::DrawRectangle(long x
, long y
, long width
, long height
)
486 long y2
= y
+ height
;
488 /* MATTHEW: [6] new normalization */
489 #if WX_STANDARD_GRAPHICS
490 bool do_brush
, do_pen
;
492 do_brush
= m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
;
493 do_pen
= m_pen
.Ok() && m_pen
.GetStyle() != wxTRANSPARENT
;
496 HPEN orig_pen
= NULL
;
498 if (do_pen
|| !m_pen
.Ok())
499 orig_pen
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
) ::GetStockObject(NULL_PEN
));
501 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
502 XLOG2DEV(x2
) + 1, YLOG2DEV(y2
) + 1);
504 if (do_pen
|| !m_pen
.Ok())
505 ::SelectObject((HDC
) m_hDC
, orig_pen
);
508 HBRUSH orig_brush
= NULL
;
510 if (do_brush
|| !m_brush
.Ok())
511 orig_brush
= (HBRUSH
) ::SelectObject((HDC
) m_hDC
, (HBRUSH
) ::GetStockObject(NULL_BRUSH
));
513 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
514 XLOG2DEV(x2
), YLOG2DEV(y2
));
516 if (do_brush
|| !m_brush
.Ok())
517 ::SelectObject((HDC
) m_hDC
, orig_brush
);
520 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
523 CalcBoundingBox(x
, y
);
524 CalcBoundingBox(x2
, y2
);
527 void wxDC::DrawRoundedRectangle(long x
, long y
, long width
, long height
, double radius
)
529 // Now, a negative radius value is interpreted to mean
530 // 'the proportion of the smallest X or Y dimension'
534 double smallest
= 0.0;
539 radius
= (- radius
* smallest
);
543 long y2
= (y
+height
);
545 (void)RoundRect((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
546 YLOG2DEV(y2
), 2*XLOG2DEV(radius
), 2*YLOG2DEV(radius
));
548 CalcBoundingBox(x
, y
);
549 CalcBoundingBox(x2
, y2
);
552 void wxDC::DrawEllipse(long x
, long y
, long width
, long height
)
555 long y2
= (y
+height
);
557 (void)Ellipse((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
559 CalcBoundingBox(x
, y
);
560 CalcBoundingBox(x2
, y2
);
563 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
564 void wxDC::DrawEllipticArc(long x
,long y
,long w
,long h
,double sa
,double ea
)
569 const double deg2rad
= 3.14159265359 / 180.0;
570 int rx1
= XLOG2DEV(x
+w
/2);
571 int ry1
= YLOG2DEV(y
+h
/2);
574 rx1
+= (int)(100.0 * abs(w
) * cos(sa
* deg2rad
));
575 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
* deg2rad
));
576 rx2
+= (int)(100.0 * abs(w
) * cos(ea
* deg2rad
));
577 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
* deg2rad
));
579 // draw pie with NULL_PEN first and then outline otherwise a line is
580 // drawn from the start and end points to the centre
581 HPEN orig_pen
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
) ::GetStockObject(NULL_PEN
));
584 (void)Pie((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
589 (void)Pie((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
590 rx1
, ry1
-1, rx2
, ry2
-1);
592 ::SelectObject((HDC
) m_hDC
, orig_pen
);
593 (void)Arc((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
596 CalcBoundingBox(x
, y
);
597 CalcBoundingBox(x2
, y2
);
600 void wxDC::DrawIcon(const wxIcon
& icon
, long x
, long y
)
602 ::DrawIcon((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON());
603 CalcBoundingBox(x
, y
);
604 CalcBoundingBox(x
+icon
.GetWidth(), y
+icon
.GetHeight());
607 void wxDC::DrawBitmap( const wxBitmap
&bmp
, long x
, long y
, bool useMask
)
612 // If we're not drawing transparently, and not drawing to a printer,
613 // optimize this function to use Windows functions.
614 if (!useMask
&& !IsKindOf(CLASSINFO(wxPrinterDC
)))
616 HDC cdc
= (HDC
)m_hDC
;
617 HDC memdc
= ::CreateCompatibleDC( cdc
);
618 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
619 ::SelectObject( memdc
, hbitmap
);
620 ::BitBlt( cdc
, x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), memdc
, 0, 0, SRCCOPY
);
621 ::SelectObject( memdc
, 0 );
626 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API level
628 memDC
.SelectObject(bmp
);
630 /* Not sure if we need this. The mask should leave the
631 * masked areas as per the original background of this DC.
634 // There might be transparent areas, so make these
635 // the same colour as this DC
636 memDC.SetBackground(* GetBackground());
640 Blit(x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), & memDC
, 0, 0, wxCOPY
, useMask
);
642 memDC
.SelectObject(wxNullBitmap
);
646 void wxDC::SetFont(const wxFont
& the_font
)
648 // Set the old object temporarily, in case the assignment deletes an object
649 // that's not yet selected out.
652 ::SelectObject((HDC
) m_hDC
, (HFONT
) m_oldFont
);
661 ::SelectObject((HDC
) m_hDC
, (HFONT
) m_oldFont
);
665 if (m_font
.Ok() && m_font
.GetResourceHandle())
667 HFONT f
= (HFONT
) ::SelectObject((HDC
) m_hDC
, (HFONT
) m_font
.GetResourceHandle());
670 wxDebugMsg("::SelectObject failed in wxDC::SetFont.");
673 m_oldFont
= (WXHFONT
) f
;
677 void wxDC::SetPen(const wxPen
& pen
)
679 // Set the old object temporarily, in case the assignment deletes an object
680 // that's not yet selected out.
683 ::SelectObject((HDC
) m_hDC
, (HPEN
) m_oldPen
);
692 ::SelectObject((HDC
) m_hDC
, (HPEN
) m_oldPen
);
698 if (m_pen
.GetResourceHandle())
700 HPEN p
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
)m_pen
.GetResourceHandle()) ;
702 m_oldPen
= (WXHPEN
) p
;
707 void wxDC::SetBrush(const wxBrush
& brush
)
709 // Set the old object temporarily, in case the assignment deletes an object
710 // that's not yet selected out.
713 ::SelectObject((HDC
) m_hDC
, (HBRUSH
) m_oldBrush
);
722 ::SelectObject((HDC
) m_hDC
, (HBRUSH
) m_oldBrush
);
728 if (m_brush
.GetResourceHandle())
731 b
= (HBRUSH
) ::SelectObject((HDC
) m_hDC
, (HBRUSH
)m_brush
.GetResourceHandle()) ;
733 m_oldBrush
= (WXHBRUSH
) b
;
738 void wxDC::DrawText(const wxString
& text
, long x
, long y
, bool use16bit
)
740 // Should be unnecessary: SetFont should have done this already.
742 if (m_font
.Ok() && m_font
.GetResourceHandle())
744 HFONT f
= (HFONT
) ::SelectObject((HDC
) m_hDC
, (HFONT
) m_font
.GetResourceHandle());
746 m_oldFont
= (WXHFONT
) f
;
750 if (m_textForegroundColour
.Ok())
751 SetTextColor((HDC
) m_hDC
, m_textForegroundColour
.GetPixel() ) ;
753 DWORD old_background
= 0;
754 if (m_textBackgroundColour
.Ok())
756 old_background
= SetBkColor((HDC
) m_hDC
, m_textBackgroundColour
.GetPixel() ) ;
759 if (m_backgroundMode
== wxTRANSPARENT
)
760 SetBkMode((HDC
) m_hDC
, TRANSPARENT
);
762 SetBkMode((HDC
) m_hDC
, OPAQUE
);
764 (void)TextOut((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), (char *) (const char *)text
, strlen((const char *)text
));
766 if (m_textBackgroundColour
.Ok())
767 (void)SetBkColor((HDC
) m_hDC
, old_background
);
769 CalcBoundingBox(x
, y
);
772 GetTextExtent(text
, &w
, &h
);
773 CalcBoundingBox((x
+ w
), (y
+ h
));
776 void wxDC::SetBackground(const wxBrush
& brush
)
778 m_backgroundBrush
= brush
;
780 if (!m_backgroundBrush
.Ok())
785 bool customColours
= TRUE
;
786 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
787 // change background colours from the control-panel specified colours.
788 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
789 customColours
= FALSE
;
793 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
795 m_canvas
->m_backgroundTransparent
= TRUE
;
799 m_canvas
->SetBackgroundColour(m_backgroundBrush
.GetColour());
800 m_canvas
->m_backgroundTransparent
= FALSE
;
804 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel() ;
806 (void)SetBkColor((HDC
) m_hDC
, new_color
);
810 void wxDC::SetBackgroundMode(int mode
)
812 m_backgroundMode
= mode
;
814 if (m_backgroundMode
== wxTRANSPARENT
)
815 ::SetBkMode((HDC
) m_hDC
, TRANSPARENT
);
817 ::SetBkMode((HDC
) m_hDC
, OPAQUE
);
820 void wxDC::SetLogicalFunction(int function
)
822 m_logicalFunction
= function
;
824 SetRop((WXHDC
) m_hDC
);
827 void wxDC::SetRop(WXHDC dc
)
829 if (!dc
|| m_logicalFunction
< 0)
833 // These may be wrong
834 switch (m_logicalFunction
)
836 // case wxXOR: c_rop = R2_XORPEN; break;
837 case wxXOR
: c_rop
= R2_NOTXORPEN
; break;
838 case wxINVERT
: c_rop
= R2_NOT
; break;
839 case wxOR_REVERSE
: c_rop
= R2_MERGEPENNOT
; break;
840 case wxAND_REVERSE
: c_rop
= R2_MASKPENNOT
; break;
841 case wxCLEAR
: c_rop
= R2_WHITE
; break;
842 case wxSET
: c_rop
= R2_BLACK
; break;
843 case wxSRC_INVERT
: c_rop
= R2_NOTCOPYPEN
; break;
844 case wxOR_INVERT
: c_rop
= R2_MERGENOTPEN
; break;
845 case wxAND
: c_rop
= R2_MASKPEN
; break;
846 case wxOR
: c_rop
= R2_MERGEPEN
; break;
847 case wxAND_INVERT
: c_rop
= R2_MASKNOTPEN
; break;
852 c_rop
= R2_COPYPEN
; break;
854 SetROP2((HDC
) dc
, c_rop
);
857 bool wxDC::StartDoc(const wxString
& message
)
859 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
863 docinfo
.cbSize
= sizeof(DOCINFO
);
864 docinfo
.lpszDocName
= (const char *)message
;
866 if (m_filename
.IsEmpty())
867 docinfo
.lpszOutput
= NULL
;
869 docinfo
.lpszOutput
= (const char *)m_filename
;
871 #if defined(__WIN95__)
872 docinfo
.lpszDatatype
= NULL
;
881 ::StartDoc((HDC
) m_hDC
, &docinfo
);
884 ::StartDocW((HDC
) m_hDC
, &docinfo
);
886 ::StartDocA((HDC
) m_hDC
, &docinfo
);
892 DWORD lastError
= GetLastError();
893 wxDebugMsg("wxDC::StartDoc failed with error: %d\n", lastError
);
898 void wxDC::EndDoc(void)
900 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
902 if (m_hDC
) ::EndDoc((HDC
) m_hDC
);
905 void wxDC::StartPage(void)
907 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
910 ::StartPage((HDC
) m_hDC
);
913 void wxDC::EndPage(void)
915 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
918 ::EndPage((HDC
) m_hDC
);
921 long wxDC::GetCharHeight(void) const
923 TEXTMETRIC lpTextMetric
;
925 GetTextMetrics((HDC
) m_hDC
, &lpTextMetric
);
927 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
930 long wxDC::GetCharWidth(void) const
932 TEXTMETRIC lpTextMetric
;
934 GetTextMetrics((HDC
) m_hDC
, &lpTextMetric
);
936 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
939 void wxDC::GetTextExtent(const wxString
& string
, long *x
, long *y
,
940 long *descent
, long *externalLeading
, wxFont
*theFont
, bool use16bit
) const
942 wxFont
*fontToUse
= (wxFont
*) theFont
;
944 fontToUse
= (wxFont
*) &m_font
;
949 GetTextExtentPoint((HDC
) m_hDC
, (char *)(const char *) string
, strlen((char *)(const char *) string
), &sizeRect
);
950 GetTextMetrics((HDC
) m_hDC
, &tm
);
952 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
953 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
954 if (descent
) *descent
= tm
.tmDescent
;
955 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
958 void wxDC::SetMapMode(int mode
)
960 m_mappingMode
= mode
;
963 int pixel_height
= 0;
967 pixel_width
= GetDeviceCaps((HDC
) m_hDC
, HORZRES
);
968 pixel_height
= GetDeviceCaps((HDC
) m_hDC
, VERTRES
);
969 mm_width
= GetDeviceCaps((HDC
) m_hDC
, HORZSIZE
);
970 mm_height
= GetDeviceCaps((HDC
) m_hDC
, VERTSIZE
);
972 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
977 double mm2pixelsX
= pixel_width
/mm_width
;
978 double mm2pixelsY
= pixel_height
/mm_height
;
984 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
985 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
990 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
991 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
996 m_logicalScaleX
= mm2pixelsX
;
997 m_logicalScaleY
= mm2pixelsY
;
1002 m_logicalScaleX
= (mm2pixelsX
/10.0);
1003 m_logicalScaleY
= (mm2pixelsY
/10.0);
1009 m_logicalScaleX
= 1.0;
1010 m_logicalScaleY
= 1.0;
1015 if (::GetMapMode((HDC
) m_hDC
) != MM_ANISOTROPIC
)
1016 ::SetMapMode((HDC
) m_hDC
, MM_ANISOTROPIC
);
1018 SetViewportExtEx((HDC
) m_hDC
, VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1019 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1020 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1021 ::SetWindowExtEx((HDC
) m_hDC
, m_windowExtX
, m_windowExtY
, NULL
);
1022 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1023 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1026 void wxDC::SetUserScale(double x
, double y
)
1031 SetMapMode(m_mappingMode
);
1034 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1036 m_signX
= xLeftRight
? 1 : -1;
1037 m_signY
= yBottomUp
? -1 : 1;
1039 SetMapMode(m_mappingMode
);
1042 void wxDC::SetSystemScale(double x
, double y
)
1047 SetMapMode(m_mappingMode
);
1050 void wxDC::SetLogicalOrigin(long x
, long y
)
1052 m_logicalOriginX
= x
;
1053 m_logicalOriginY
= y
;
1055 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1058 void wxDC::SetDeviceOrigin(long x
, long y
)
1060 m_deviceOriginX
= x
;
1061 m_deviceOriginY
= y
;
1063 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1066 long wxDC::DeviceToLogicalX(long x
) const
1068 return (long) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
) - m_logicalOriginX
) ;
1071 long wxDC::DeviceToLogicalXRel(long x
) const
1073 return (long) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
)) ;
1076 long wxDC::DeviceToLogicalY(long y
) const
1078 return (long) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
) - m_logicalOriginY
) ;
1081 long wxDC::DeviceToLogicalYRel(long y
) const
1083 return (long) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
)) ;
1086 long wxDC::LogicalToDeviceX(long x
) const
1088 return (long) (floor((x
) - m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
+ m_deviceOriginX
) ;
1091 long wxDC::LogicalToDeviceXRel(long x
) const
1093 return (long) (floor(x
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
) ;
1096 long wxDC::LogicalToDeviceY(long y
) const
1098 return (long) (floor((y
) - m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
+ m_deviceOriginY
);
1101 long wxDC::LogicalToDeviceYRel(long y
) const
1103 return (long) (floor(y
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
) ;
1106 // This group of functions may not do any conversion
1107 // if m_scaleGDI is TRUE, since the HDC does the
1108 // conversion automatically.
1110 long wxDC::ImplDeviceToLogicalX(long x
) const
1112 // return (m_scaleGDI ? x : DeviceToLogicalX(x));
1116 long wxDC::ImplDeviceToLogicalY(long y
) const
1118 // return (m_scaleGDI ? y : DeviceToLogicalY(y));
1122 long wxDC::ImplDeviceToLogicalXRel(long x
) const
1124 // return (m_scaleGDI ? x : DeviceToLogicalXRel(x));
1128 long wxDC::ImplDeviceToLogicalYRel(long y
) const
1130 // return (m_scaleGDI ? y : DeviceToLogicalYRel(y));
1134 long wxDC::ImplLogicalToDeviceX(long x
) const
1136 // return (m_scaleGDI ? (floor(double(x))) : LogicalToDeviceX(x));
1140 long wxDC::ImplLogicalToDeviceY(long y
) const
1142 // return (m_scaleGDI ? (floor(double(y))) : LogicalToDeviceY(y));
1146 long wxDC::ImplLogicalToDeviceXRel(long x
) const
1148 // return (m_scaleGDI ? (floor(double(x))) : LogicalToDeviceXRel(x));
1152 long wxDC::ImplLogicalToDeviceYRel(long y
) const
1154 // return (m_scaleGDI ? (floor(double(y))) : LogicalToDeviceYRel(y));
1158 bool wxDC::Blit(long xdest
, long ydest
, long width
, long height
,
1159 wxDC
*source
, long xsrc
, long ysrc
, int rop
, bool useMask
)
1161 long xdest1
= xdest
;
1162 long ydest1
= ydest
;
1166 // Chris Breeze 18/5/98: use text foreground/background colours
1167 // when blitting from 1-bit bitmaps
1168 COLORREF old_textground
= ::GetTextColor((HDC
)m_hDC
);
1169 COLORREF old_background
= ::GetBkColor((HDC
)m_hDC
);
1170 if (m_textForegroundColour
.Ok())
1172 ::SetTextColor((HDC
) m_hDC
, m_textForegroundColour
.GetPixel() ) ;
1174 if (m_textBackgroundColour
.Ok())
1176 ::SetBkColor((HDC
) m_hDC
, m_textBackgroundColour
.GetPixel() ) ;
1179 DWORD dwRop
= rop
== wxCOPY
? SRCCOPY
:
1180 rop
== wxCLEAR
? WHITENESS
:
1181 rop
== wxSET
? BLACKNESS
:
1182 rop
== wxINVERT
? DSTINVERT
:
1183 rop
== wxAND
? MERGECOPY
:
1184 rop
== wxOR
? MERGEPAINT
:
1185 rop
== wxSRC_INVERT
? NOTSRCCOPY
:
1186 rop
== wxXOR
? SRCINVERT
:
1187 rop
== wxOR_REVERSE
? MERGEPAINT
:
1188 rop
== wxAND_REVERSE
? SRCERASE
:
1189 rop
== wxSRC_OR
? SRCPAINT
:
1190 rop
== wxSRC_AND
? SRCAND
:
1193 bool success
= TRUE
;
1194 if (useMask
&& source
->m_selectedBitmap
.Ok() && source
->m_selectedBitmap
.GetMask())
1198 // Not implemented under Win95 (or maybe a specific device?)
1199 if (MaskBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1200 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap(),
1210 HDC dc_mask
= CreateCompatibleDC((HDC
) source
->m_hDC
);
1211 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1212 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1213 dc_mask
, xsrc1
, ysrc1
, 0x00220326 /* NOTSRCAND */) != 0);
1214 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1215 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, SRCPAINT
) != 0);
1216 ::SelectObject(dc_mask
, 0);
1217 ::DeleteDC(dc_mask
);
1219 // New code from Chris Breeze, 15/7/98
1220 // Blit bitmap with mask
1222 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1224 // If we are printing source colours are screen colours
1225 // not printer colours and so we need copy the bitmap
1228 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1229 HDC dc_src
= (HDC
) source
->m_hDC
;
1231 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1232 for (int x
= 0; x
< width
; x
++)
1234 for (int y
= 0; y
< height
; y
++)
1236 COLORREF cref
= ::GetPixel(dc_mask
, x
, y
);
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((HDC
) m_hDC
, &rect
, brush
);
1243 ::DeleteObject(brush
);
1247 ::SelectObject(dc_mask
, 0);
1248 ::DeleteDC(dc_mask
);
1252 // create a temp buffer bitmap and DCs to access it and the mask
1253 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1254 HDC dc_buffer
= ::CreateCompatibleDC((HDC
) m_hDC
);
1255 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap((HDC
) m_hDC
, width
, height
);
1256 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1257 ::SelectObject(dc_buffer
, buffer_bmap
);
1259 // copy dest to buffer
1260 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1261 (HDC
) m_hDC
, xdest1
, ydest1
, SRCCOPY
);
1263 // copy src to buffer using selected raster op
1264 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1265 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, dwRop
);
1267 // set masked area in buffer to BLACK (pixel value 0)
1268 COLORREF prevBkCol
= ::SetBkColor((HDC
) m_hDC
, RGB(255, 255, 255));
1269 COLORREF prevCol
= ::SetTextColor((HDC
) m_hDC
, RGB(0, 0, 0));
1270 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1271 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1273 // set unmasked area in dest to BLACK
1274 ::SetBkColor((HDC
) m_hDC
, RGB(0, 0, 0));
1275 ::SetTextColor((HDC
) m_hDC
, RGB(255, 255, 255));
1276 ::BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1277 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1278 ::SetBkColor((HDC
) m_hDC
, prevBkCol
); // restore colours to original values
1279 ::SetTextColor((HDC
) m_hDC
, prevCol
);
1281 // OR buffer to dest
1282 success
= (::BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1283 dc_buffer
, 0, 0, SRCPAINT
) != 0);
1285 // tidy up temporary DCs and bitmap
1286 ::SelectObject(dc_mask
, 0);
1287 ::DeleteDC(dc_mask
);
1288 ::SelectObject(dc_buffer
, 0);
1289 ::DeleteDC(dc_buffer
);
1290 ::DeleteObject(buffer_bmap
);
1296 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1298 // If we are printing, source colours are screen colours
1299 // not printer colours and so we need copy the bitmap
1301 HDC dc_src
= (HDC
) source
->m_hDC
;
1303 for (int x
= 0; x
< width
; x
++)
1305 for (int y
= 0; y
< height
; y
++)
1307 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1308 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1309 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1310 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1311 ::DeleteObject(brush
);
1317 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
, (HDC
) source
->m_hDC
,
1318 xsrc1
, ysrc1
, dwRop
) != 0);
1321 ::SetTextColor((HDC
)m_hDC
, old_textground
);
1322 ::SetBkColor((HDC
)m_hDC
, old_background
);
1327 void wxDC::GetSize(int* width
, int* height
) const
1329 long w
=::GetDeviceCaps((HDC
) m_hDC
,HORZRES
);
1330 long h
=::GetDeviceCaps((HDC
) m_hDC
,VERTRES
);
1335 void wxDC::GetSizeMM(long *width
, long *height
) const
1337 long w
=::GetDeviceCaps((HDC
) m_hDC
,HORZSIZE
);
1338 long h
=::GetDeviceCaps((HDC
) m_hDC
,VERTSIZE
);
1343 void wxDC::DrawPolygon(wxList
*list
, long xoffset
, long yoffset
,int fillStyle
)
1345 int n
= list
->Number();
1346 wxPoint
*points
= new wxPoint
[n
];
1349 for(wxNode
*node
= list
->First(); node
; node
= node
->Next()) {
1350 wxPoint
*point
= (wxPoint
*)node
->Data();
1351 points
[i
].x
= point
->x
;
1352 points
[i
++].y
= point
->y
;
1354 DrawPolygon(n
, points
, xoffset
, yoffset
,fillStyle
);
1358 void wxDC::DrawLines(wxList
*list
, long xoffset
, long yoffset
)
1360 int n
= list
->Number();
1361 wxPoint
*points
= new wxPoint
[n
];
1364 for(wxNode
*node
= list
->First(); node
; node
= node
->Next()) {
1365 wxPoint
*point
= (wxPoint
*)node
->Data();
1366 points
[i
].x
= point
->x
;
1367 points
[i
++].y
= point
->y
;
1369 DrawLines(n
, points
, xoffset
, yoffset
);
1373 void wxDC::SetTextForeground(const wxColour
& colour
)
1375 m_textForegroundColour
= colour
;
1378 void wxDC::SetTextBackground(const wxColour
& colour
)
1380 m_textBackgroundColour
= colour
;
1383 // For use by wxWindows only, unless custom units are required.
1384 void wxDC::SetLogicalScale(double x
, double y
)
1386 m_logicalScaleX
= x
;
1387 m_logicalScaleY
= y
;
1390 void wxDC::CalcBoundingBox(long x
, long y
)
1392 if (x
< m_minX
) m_minX
= x
;
1393 if (y
< m_minY
) m_minY
= y
;
1394 if (x
> m_maxX
) m_maxX
= x
;
1395 if (y
> m_maxY
) m_maxY
= y
;
1398 void wxDC::GetClippingBox(long *x
,long *y
,long *w
,long *h
) const
1404 *w
= (m_clipX2
- m_clipX1
) ;
1405 *h
= (m_clipY2
- m_clipY1
) ;
1408 *x
= *y
= *w
= *h
= 0 ;
1411 #if WXWIN_COMPATIBILITY
1412 void wxDC::GetTextExtent(const wxString
& string
, float *x
, float *y
,
1413 float *descent
, float *externalLeading
,
1414 wxFont
*theFont
, bool use16bit
) const
1416 long x1
, y1
, descent1
, externalLeading1
;
1417 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1420 *descent
= descent1
;
1421 if (externalLeading
)
1422 *externalLeading
= externalLeading1
;
1426 int wxDC::GetDepth(void) const
1428 return (int) ::GetDeviceCaps((HDC
) m_hDC
,BITSPIXEL
);
1433 // Make a 3-point spline
1434 void wxDC::DrawSpline(long x1
, long y1
, long x2
, long y2
, long x3
, long y3
)
1436 wxList
*point_list
= new wxList
;
1438 wxPoint
*point1
= new wxPoint
;
1439 point1
->x
= x1
; point1
->y
= y1
;
1440 point_list
->Append((wxObject
*)point1
);
1442 wxPoint
*point2
= new wxPoint
;
1443 point2
->x
= x2
; point2
->y
= y2
;
1444 point_list
->Append((wxObject
*)point2
);
1446 wxPoint
*point3
= new wxPoint
;
1447 point3
->x
= x3
; point3
->y
= y3
;
1448 point_list
->Append((wxObject
*)point3
);
1450 DrawSpline(point_list
);
1452 for(wxNode
*node
= point_list
->First(); node
; node
= node
->Next()) {
1453 wxPoint
*p
= (wxPoint
*)node
->Data();
1459 ////#define wx_round(a) (int)((a)+.5)
1460 //#define wx_round(a) (a)
1462 class wxSpline
: public wxObject
1468 wxSpline(wxList
*list
);
1469 void DeletePoints(void);
1471 // Doesn't delete points
1475 void wxDC::DrawSpline(int n
, wxPoint points
[])
1479 for (i
=0; i
< n
; i
++)
1480 list
.Append((wxObject
*)&points
[i
]);
1481 DrawSpline((wxList
*)&list
);
1484 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1486 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1487 double a3
, double b3
, double a4
, double b4
);
1488 void wx_clear_stack(void);
1489 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1490 double *y3
, double *x4
, double *y4
);
1491 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1492 double x4
, double y4
);
1493 static bool wx_spline_add_point(double x
, double y
);
1494 static void wx_spline_draw_point_array(wxDC
*dc
);
1495 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1497 void wxDC::DrawSpline(wxList
*list
)
1499 wxSpline
spline(list
);
1501 wx_draw_open_spline(this, &spline
);
1505 wxList wx_spline_point_list
;
1507 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1510 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1511 double x1
, y1
, x2
, y2
;
1513 wxNode
*node
= spline
->points
->First();
1514 p
= (wxPoint
*)node
->Data();
1519 node
= node
->Next();
1520 p
= (wxPoint
*)node
->Data();
1524 cx1
= (double)((x1
+ x2
) / 2);
1525 cy1
= (double)((y1
+ y2
) / 2);
1526 cx2
= (double)((cx1
+ x2
) / 2);
1527 cy2
= (double)((cy1
+ y2
) / 2);
1529 wx_spline_add_point(x1
, y1
);
1531 while ((node
= node
->Next()) != NULL
)
1533 p
= (wxPoint
*)node
->Data();
1538 cx4
= (double)(x1
+ x2
) / 2;
1539 cy4
= (double)(y1
+ y2
) / 2;
1540 cx3
= (double)(x1
+ cx4
) / 2;
1541 cy3
= (double)(y1
+ cy4
) / 2;
1543 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1547 cx2
= (double)(cx1
+ x2
) / 2;
1548 cy2
= (double)(cy1
+ y2
) / 2;
1551 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1552 wx_spline_add_point(x2
, y2
);
1554 wx_spline_draw_point_array(dc
);
1558 /********************* CURVES FOR SPLINES *****************************
1560 The following spline drawing routine is from
1562 "An Algorithm for High-Speed Curve Generation"
1563 by George Merrill Chaikin,
1564 Computer Graphics and Image Processing, 3, Academic Press,
1569 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1570 Computer Graphics and Image Processing, 4, Academic Press,
1573 ***********************************************************************/
1575 #define half(z1, z2) ((z1+z2)/2.0)
1578 /* iterative version */
1580 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1583 register double xmid
, ymid
;
1584 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1587 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1589 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1590 xmid
= (double)half(x2
, x3
);
1591 ymid
= (double)half(y2
, y3
);
1592 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1593 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1594 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1595 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1597 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1598 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1599 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1600 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1606 /* utilities used by spline drawing routines */
1609 typedef struct wx_spline_stack_struct
{
1610 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1614 #define SPLINE_STACK_DEPTH 20
1615 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1616 static Stack
*wx_stack_top
;
1617 static int wx_stack_count
;
1619 void wx_clear_stack(void)
1621 wx_stack_top
= wx_spline_stack
;
1625 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1627 wx_stack_top
->x1
= x1
;
1628 wx_stack_top
->y1
= y1
;
1629 wx_stack_top
->x2
= x2
;
1630 wx_stack_top
->y2
= y2
;
1631 wx_stack_top
->x3
= x3
;
1632 wx_stack_top
->y3
= y3
;
1633 wx_stack_top
->x4
= x4
;
1634 wx_stack_top
->y4
= y4
;
1639 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1640 double *x3
, double *y3
, double *x4
, double *y4
)
1642 if (wx_stack_count
== 0)
1646 *x1
= wx_stack_top
->x1
;
1647 *y1
= wx_stack_top
->y1
;
1648 *x2
= wx_stack_top
->x2
;
1649 *y2
= wx_stack_top
->y2
;
1650 *x3
= wx_stack_top
->x3
;
1651 *y3
= wx_stack_top
->y3
;
1652 *x4
= wx_stack_top
->x4
;
1653 *y4
= wx_stack_top
->y4
;
1657 static bool wx_spline_add_point(double x
, double y
)
1659 wxPoint
*point
= new wxPoint
;
1662 wx_spline_point_list
.Append((wxObject
*)point
);
1666 static void wx_spline_draw_point_array(wxDC
*dc
)
1668 dc
->DrawLines(&wx_spline_point_list
, (double)0.0, (double)0.0);
1669 wxNode
*node
= wx_spline_point_list
.First();
1672 wxPoint
*point
= (wxPoint
*)node
->Data();
1675 node
= wx_spline_point_list
.First();
1679 wxSpline::wxSpline(wxList
*list
)
1684 wxSpline::~wxSpline(void)
1688 void wxSpline::DeletePoints(void)
1690 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1692 wxPoint
*point
= (wxPoint
*)node
->Data();
1700 #endif // wxUSE_SPLINES