1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
21 #pragma implementation "dc.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
33 #include "wx/window.h"
36 #include "wx/dialog.h"
38 #include "wx/bitmap.h"
39 #include "wx/dcmemory.h"
44 #include "wx/dcprint.h"
49 #if wxUSE_COMMON_DIALOGS
50 #if wxUSE_NORLANDER_HEADERS
60 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
62 // ---------------------------------------------------------------------------
64 // ---------------------------------------------------------------------------
66 static const int VIEWPORT_EXTENT
= 1000;
68 static const int MM_POINTS
= 9;
69 static const int MM_METRIC
= 10;
71 // usually this is defined in math.h
73 static const double M_PI
= 3.14159265358979323846;
76 // ---------------------------------------------------------------------------
78 // ---------------------------------------------------------------------------
80 // convert degrees to radians
81 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
83 // ===========================================================================
85 // ===========================================================================
87 // ---------------------------------------------------------------------------
89 // ---------------------------------------------------------------------------
91 // Default constructor
105 m_windowExtX
= VIEWPORT_EXTENT
;
106 m_windowExtY
= VIEWPORT_EXTENT
;
115 SelectOldObjects(m_hDC
);
117 if ( m_canvas
== NULL
)
118 ::DeleteDC(GetHdc());
120 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), GetHdc());
126 // This will select current objects out of the DC,
127 // which is what you have to do before deleting the
129 void wxDC::SelectOldObjects(WXHDC dc
)
135 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
136 if (m_selectedBitmap
.Ok())
138 m_selectedBitmap
.SetSelectedInto(NULL
);
144 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
149 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
154 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
159 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, TRUE
);
164 m_brush
= wxNullBrush
;
166 m_palette
= wxNullPalette
;
168 m_backgroundBrush
= wxNullBrush
;
169 m_selectedBitmap
= wxNullBitmap
;
172 // ---------------------------------------------------------------------------
174 // ---------------------------------------------------------------------------
176 void wxDC::DoSetClippingRegion(wxCoord cx
, wxCoord cy
, wxCoord cw
, wxCoord ch
)
181 m_clipX2
= (int)(cx
+ cw
);
182 m_clipY2
= (int)(cy
+ ch
);
184 DoClipping((WXHDC
) m_hDC
);
187 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
189 wxCHECK_RET( region
.GetHRGN(), wxT("invalid clipping region") );
191 wxRect box
= region
.GetBox();
196 m_clipX2
= box
.x
+ box
.width
;
197 m_clipY2
= box
.y
+ box
.height
;
200 SelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN());
202 ExtSelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN(), RGN_AND
);
206 void wxDC::DoClipping(WXHDC dc
)
208 if (m_clipping
&& dc
)
210 IntersectClipRect((HDC
) dc
, XLOG2DEV(m_clipX1
), YLOG2DEV(m_clipY1
),
211 XLOG2DEV(m_clipX2
), YLOG2DEV(m_clipY2
));
215 void wxDC::DestroyClippingRegion()
217 if (m_clipping
&& m_hDC
)
219 // TODO: this should restore the previous clipping region,
220 // so that OnPaint processing works correctly, and the update clipping region
221 // doesn't get destroyed after the first DestroyClippingRegion.
222 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
223 SelectClipRgn(GetHdc(), rgn
);
229 // ---------------------------------------------------------------------------
230 // query capabilities
231 // ---------------------------------------------------------------------------
233 bool wxDC::CanDrawBitmap() const
238 bool wxDC::CanGetTextExtent() const
240 // What sort of display is it?
241 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
243 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
246 int wxDC::GetDepth() const
248 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
251 // ---------------------------------------------------------------------------
253 // ---------------------------------------------------------------------------
260 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
264 wxCHECK_RET( m_selectedBitmap
.Ok(), wxT("this DC can't be cleared") );
266 rect
.left
= 0; rect
.top
= 0;
267 rect
.right
= m_selectedBitmap
.GetWidth();
268 rect
.bottom
= m_selectedBitmap
.GetHeight();
271 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
273 DWORD colour
= GetBkColor(GetHdc());
274 HBRUSH brush
= CreateSolidBrush(colour
);
275 FillRect(GetHdc(), &rect
, brush
);
278 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
279 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
280 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
281 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
282 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
285 void wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
287 (void)ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
289 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
292 CalcBoundingBox(x
, y
);
295 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
297 // added by steve 29.12.94 (copied from DrawPoint)
298 // returns TRUE for pixels in the color of the current pen
299 // and FALSE for all other pixels colors
300 // if col is non-NULL return the color of the pixel
302 // get the color of the pixel
303 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
304 // get the color of the pen
305 COLORREF pencolor
= 0x00ffffff;
308 pencolor
= m_pen
.GetColour().GetPixel();
311 // return the color of the pixel
313 col
->Set(GetRValue(pixelcolor
),GetGValue(pixelcolor
),GetBValue(pixelcolor
));
315 // check, if color of the pixels is the same as the color
316 // of the current pen
317 return(pixelcolor
==pencolor
);
320 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
322 wxCoord x1
= x
-VIEWPORT_EXTENT
;
323 wxCoord y1
= y
-VIEWPORT_EXTENT
;
324 wxCoord x2
= x
+VIEWPORT_EXTENT
;
325 wxCoord y2
= y
+VIEWPORT_EXTENT
;
327 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
328 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
));
330 (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
331 (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
));
333 CalcBoundingBox(x1
, y1
);
334 CalcBoundingBox(x2
, y2
);
337 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
339 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
340 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
));
342 /* MATTHEW: [6] New normalization */
343 #if WX_STANDARD_GRAPHICS
344 (void)LineTo(GetHdc(), XLOG2DEV(x2
) + 1, YLOG2DEV(y2
));
347 CalcBoundingBox(x1
, y1
);
348 CalcBoundingBox(x2
, y2
);
351 void wxDC::DoDrawArc(wxCoord x1
,wxCoord y1
,wxCoord x2
,wxCoord y2
, wxCoord xc
, wxCoord yc
)
355 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
356 if (x1
==x2
&& x2
==y2
)
358 DrawEllipse(xc
,yc
,(wxCoord
)(radius
*2.0),(wxCoord
)(radius
*2.0));
362 wxCoord xx1
= XLOG2DEV(x1
);
363 wxCoord yy1
= YLOG2DEV(y1
);
364 wxCoord xx2
= XLOG2DEV(x2
);
365 wxCoord yy2
= YLOG2DEV(y2
);
366 wxCoord xxc
= XLOG2DEV(xc
);
367 wxCoord yyc
= YLOG2DEV(yc
);
368 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
370 (void)MoveToEx(GetHdc(), (int) xx1
, (int) yy1
, NULL
);
371 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
372 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
373 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
374 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
375 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
377 // Have to add 1 to bottom-right corner of rectangle
378 // to make semi-circles look right (crooked line otherwise).
379 // Unfortunately this is not a reliable method, depends
380 // on the size of shape.
381 // TODO: figure out why this happens!
382 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1,
386 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
,
389 CalcBoundingBox((wxCoord
)(xc
-radius
), (wxCoord
)(yc
-radius
));
390 CalcBoundingBox((wxCoord
)(xc
+radius
), (wxCoord
)(yc
+radius
));
393 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
395 COLORREF color
= 0x00ffffff;
398 color
= m_pen
.GetColour().GetPixel();
401 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
403 CalcBoundingBox(x
, y
);
406 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
408 // Do things less efficiently if we have offsets
409 if (xoffset
!= 0 || yoffset
!= 0)
411 POINT
*cpoints
= new POINT
[n
];
413 for (i
= 0; i
< n
; i
++)
415 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
416 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
418 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
420 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
421 (void)Polygon(GetHdc(), cpoints
, n
);
422 SetPolyFillMode(GetHdc(),prev
);
428 for (i
= 0; i
< n
; i
++)
429 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
431 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
432 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
433 SetPolyFillMode(GetHdc(),prev
);
437 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
439 // Do things less efficiently if we have offsets
440 if (xoffset
!= 0 || yoffset
!= 0)
442 POINT
*cpoints
= new POINT
[n
];
444 for (i
= 0; i
< n
; i
++)
446 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
447 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
449 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
451 (void)Polyline(GetHdc(), cpoints
, n
);
457 for (i
= 0; i
< n
; i
++)
458 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
460 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
464 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
466 wxCoord x2
= x
+ width
;
467 wxCoord y2
= y
+ height
;
469 /* MATTHEW: [6] new normalization */
470 #if WX_STANDARD_GRAPHICS
471 bool do_brush
, do_pen
;
473 do_brush
= m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
;
474 do_pen
= m_pen
.Ok() && m_pen
.GetStyle() != wxTRANSPARENT
;
477 HPEN orig_pen
= NULL
;
479 if (do_pen
|| !m_pen
.Ok())
480 orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
482 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
483 XLOG2DEV(x2
) + 1, YLOG2DEV(y2
) + 1);
485 if (do_pen
|| !m_pen
.Ok())
486 ::SelectObject(GetHdc() , orig_pen
);
489 HBRUSH orig_brush
= NULL
;
491 if (do_brush
|| !m_brush
.Ok())
492 orig_brush
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
) ::GetStockObject(NULL_BRUSH
));
494 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
495 XLOG2DEV(x2
), YLOG2DEV(y2
));
497 if (do_brush
|| !m_brush
.Ok())
498 ::SelectObject(GetHdc(), orig_brush
);
501 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
504 CalcBoundingBox(x
, y
);
505 CalcBoundingBox(x2
, y2
);
508 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
510 // Now, a negative radius value is interpreted to mean
511 // 'the proportion of the smallest X or Y dimension'
515 double smallest
= 0.0;
520 radius
= (- radius
* smallest
);
523 wxCoord x2
= (x
+width
);
524 wxCoord y2
= (y
+height
);
526 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
527 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
529 CalcBoundingBox(x
, y
);
530 CalcBoundingBox(x2
, y2
);
533 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
535 wxCoord x2
= (x
+width
);
536 wxCoord y2
= (y
+height
);
538 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
540 CalcBoundingBox(x
, y
);
541 CalcBoundingBox(x2
, y2
);
544 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
545 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
550 int rx1
= XLOG2DEV(x
+w
/2);
551 int ry1
= YLOG2DEV(y
+h
/2);
558 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
559 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
560 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
561 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
563 // draw pie with NULL_PEN first and then outline otherwise a line is
564 // drawn from the start and end points to the centre
565 HPEN orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
568 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
573 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
574 rx1
, ry1
-1, rx2
, ry2
-1);
576 ::SelectObject(GetHdc(), orig_pen
);
577 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
580 CalcBoundingBox(x
, y
);
581 CalcBoundingBox(x2
, y2
);
584 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
586 #if defined(__WIN32__) && !defined(__SC__) && !defined(__TWIN32__)
587 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON(),
588 icon
.GetWidth(), icon
.GetHeight(), 0, 0, DI_NORMAL
);
590 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON());
593 CalcBoundingBox(x
, y
);
594 CalcBoundingBox(x
+icon
.GetWidth(), y
+icon
.GetHeight());
597 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
602 bool needsPixelCopy
= FALSE
;
603 bool isPrinter
= FALSE
;
604 if (IsKindOf(CLASSINFO(wxPrinterDC
)) )
607 if ( ::GetDeviceCaps((HDC
) m_hDC
, RASTERCAPS
) & RC_STRETCHDIB
)
612 needsPixelCopy
= TRUE
;
615 // If we're not drawing transparently, and not drawing to a printer,
616 // optimize this function to use Windows functions.
617 if (!useMask
&& !needsPixelCopy
)
621 BITMAPINFO
*info
= (BITMAPINFO
*) malloc( sizeof( BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
) ) ;
622 int iBitsSize
= ((bmp
.GetWidth() + 3 ) & ~3 ) * bmp
.GetHeight() ;
624 void* bits
= malloc( iBitsSize
) ;
626 memset( info
, 0 , sizeof( BITMAPINFOHEADER
) ) ;
628 info
->bmiHeader
.biSize
= sizeof( BITMAPINFOHEADER
) ;
629 info
->bmiHeader
.biWidth
= bmp
.GetWidth() ;
630 info
->bmiHeader
.biHeight
= bmp
.GetHeight() ;
631 info
->bmiHeader
.biPlanes
= 1 ;
632 info
->bmiHeader
.biBitCount
= 8 ;
633 info
->bmiHeader
.biCompression
= BI_RGB
;
635 HDC display
= GetDC( NULL
) ;
636 if ( GetDIBits( display
, (HBITMAP
) bmp
.GetHBITMAP( ) , 0 , bmp
.GetHeight() , bits
, info
, DIB_RGB_COLORS
) )
638 StretchDIBits( (HDC
) m_hDC
,
639 x
, y
, bmp
.GetWidth(), bmp
.GetHeight() ,
640 0 , 0 ,bmp
.GetWidth(), bmp
.GetHeight() ,
641 bits
, info
, DIB_RGB_COLORS
, SRCCOPY
) ;
643 ReleaseDC( NULL
, display
) ;
650 HDC memdc
= ::CreateCompatibleDC( cdc
);
651 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
653 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
655 COLORREF old_textground
= ::GetTextColor(GetHdc());
656 COLORREF old_background
= ::GetBkColor(GetHdc());
657 if (m_textForegroundColour
.Ok())
659 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
661 if (m_textBackgroundColour
.Ok())
663 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
666 ::SelectObject( memdc
, hbitmap
);
667 ::BitBlt( cdc
, x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), memdc
, 0, 0, SRCCOPY
);
670 ::SetTextColor(GetHdc(), old_textground
);
671 ::SetBkColor(GetHdc(), old_background
);
676 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API level
678 memDC
.SelectObject(bmp
);
680 /* Not sure if we need this. The mask should leave the
681 * masked areas as per the original background of this DC.
684 // There might be transparent areas, so make these
685 // the same colour as this DC
686 memDC.SetBackground(* GetBackground());
690 Blit(x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), & memDC
, 0, 0, wxCOPY
, useMask
);
692 memDC
.SelectObject(wxNullBitmap
);
696 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
698 DrawAnyText(text
, x
, y
);
700 // update the bounding box
701 CalcBoundingBox(x
, y
);
704 GetTextExtent(text
, &w
, &h
);
705 CalcBoundingBox(x
+ w
, y
+ h
);
708 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
710 // prepare for drawing the text
711 if ( m_textForegroundColour
.Ok() )
712 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
714 DWORD old_background
= 0;
715 if ( m_textBackgroundColour
.Ok() )
717 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
720 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
723 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
724 text
.c_str(), text
.length()) == 0 )
726 wxLogLastError("TextOut");
729 // restore the old parameters (text foreground colour may be left because
730 // it never is set to anything else, but background should remain
731 // transparent even if we just drew an opaque string)
732 if ( m_textBackgroundColour
.Ok() )
733 (void)SetBkColor(GetHdc(), old_background
);
735 SetBkMode(GetHdc(), TRANSPARENT
);
738 void wxDC::DoDrawRotatedText(const wxString
& text
,
739 wxCoord x
, wxCoord y
,
742 // we test that we have some font because otherwise we should still use the
743 // "else" part below to avoid that DrawRotatedText(angle = 180) and
744 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
745 // font for drawing rotated fonts unfortunately)
746 if ( (angle
== 0.0) && m_font
.Ok() )
748 DoDrawText(text
, x
, y
);
752 // NB: don't take DEFAULT_GUI_FONT because it's not TrueType and so
753 // can't have non zero orientation/escapement
754 wxFont font
= m_font
.Ok() ? m_font
: *wxNORMAL_FONT
;
755 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
757 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
759 wxLogLastError("GetObject(hfont)");
762 // GDI wants the angle in tenth of degree
763 long angle10
= (long)(angle
* 10);
764 lf
.lfEscapement
= angle10
;
765 lf
. lfOrientation
= angle10
;
767 hfont
= ::CreateFontIndirect(&lf
);
770 wxLogLastError("CreateFont");
774 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
776 DrawAnyText(text
, x
, y
);
778 (void)::SelectObject(GetHdc(), hfontOld
);
781 // call the bounding box by adding all four vertices of the rectangle
782 // containing the text to it (simpler and probably not slower than
783 // determining which of them is really topmost/leftmost/...)
785 GetTextExtent(text
, &w
, &h
);
787 double rad
= DegToRad(angle
);
789 // "upper left" and "upper right"
790 CalcBoundingBox(x
, y
);
791 CalcBoundingBox(x
+ w
*cos(rad
), y
- h
*sin(rad
));
793 // "bottom left" and "bottom right"
794 x
+= (wxCoord
)(h
*sin(rad
));
795 y
+= (wxCoord
)(h
*cos(rad
));
796 CalcBoundingBox(x
, y
);
797 CalcBoundingBox(x
+ h
*sin(rad
), y
+ h
*cos(rad
));
801 // ---------------------------------------------------------------------------
803 // ---------------------------------------------------------------------------
805 void wxDC::SetPalette(const wxPalette
& palette
)
807 // Set the old object temporarily, in case the assignment deletes an object
808 // that's not yet selected out.
811 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
819 // Setting a NULL colourmap is a way of restoring
820 // the original colourmap
823 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
830 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
832 HPALETTE oldPal
= ::SelectPalette(GetHdc(), (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
834 m_oldPalette
= (WXHPALETTE
) oldPal
;
836 ::RealizePalette(GetHdc());
840 void wxDC::SetFont(const wxFont
& the_font
)
842 // Set the old object temporarily, in case the assignment deletes an object
843 // that's not yet selected out.
846 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
855 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
859 if (m_font
.Ok() && m_font
.GetResourceHandle())
861 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
862 if (f
== (HFONT
) NULL
)
864 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
867 m_oldFont
= (WXHFONT
) f
;
871 void wxDC::SetPen(const wxPen
& pen
)
873 // Set the old object temporarily, in case the assignment deletes an object
874 // that's not yet selected out.
877 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
886 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
892 if (m_pen
.GetResourceHandle())
894 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
896 m_oldPen
= (WXHPEN
) p
;
901 void wxDC::SetBrush(const wxBrush
& brush
)
903 // Set the old object temporarily, in case the assignment deletes an object
904 // that's not yet selected out.
907 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
916 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
922 if (m_brush
.GetResourceHandle())
925 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
927 m_oldBrush
= (WXHBRUSH
) b
;
932 void wxDC::SetBackground(const wxBrush
& brush
)
934 m_backgroundBrush
= brush
;
936 if (!m_backgroundBrush
.Ok())
941 bool customColours
= TRUE
;
942 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
943 // change background colours from the control-panel specified colours.
944 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
945 customColours
= FALSE
;
949 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
951 m_canvas
->SetTransparent(TRUE
);
955 // New behaviour, 10/2/99: setting the background brush of a DC
956 // doesn't affect the window background colour. However,
957 // I'm leaving in the transparency setting because it's needed by
958 // various controls (e.g. wxStaticText) to determine whether to draw
959 // transparently or not. TODO: maybe this should be a new function
960 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
962 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
963 m_canvas
->SetTransparent(FALSE
);
967 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
969 (void)SetBkColor(GetHdc(), new_color
);
973 void wxDC::SetBackgroundMode(int mode
)
975 m_backgroundMode
= mode
;
977 // SetBackgroundColour now only refers to text background
978 // and m_backgroundMode is used there
981 if (m_backgroundMode == wxTRANSPARENT)
982 ::SetBkMode(GetHdc(), TRANSPARENT);
984 ::SetBkMode(GetHdc(), OPAQUE);
988 void wxDC::SetLogicalFunction(int function
)
990 m_logicalFunction
= function
;
992 SetRop((WXHDC
) m_hDC
);
995 void wxDC::SetRop(WXHDC dc
)
997 if (!dc
|| m_logicalFunction
< 0)
1001 // These may be wrong
1002 switch (m_logicalFunction
)
1004 // case wxXOR: c_rop = R2_XORPEN; break;
1005 case wxXOR
: c_rop
= R2_NOTXORPEN
; break;
1006 case wxINVERT
: c_rop
= R2_NOT
; break;
1007 case wxOR_REVERSE
: c_rop
= R2_MERGEPENNOT
; break;
1008 case wxAND_REVERSE
: c_rop
= R2_MASKPENNOT
; break;
1009 case wxCLEAR
: c_rop
= R2_WHITE
; break;
1010 case wxSET
: c_rop
= R2_BLACK
; break;
1011 case wxSRC_INVERT
: c_rop
= R2_NOTCOPYPEN
; break;
1012 case wxOR_INVERT
: c_rop
= R2_MERGENOTPEN
; break;
1013 case wxAND
: c_rop
= R2_MASKPEN
; break;
1014 case wxOR
: c_rop
= R2_MERGEPEN
; break;
1015 case wxAND_INVERT
: c_rop
= R2_MASKNOTPEN
; break;
1020 c_rop
= R2_COPYPEN
; break;
1022 SetROP2((HDC
) dc
, c_rop
);
1025 bool wxDC::StartDoc(const wxString
& message
)
1027 // We might be previewing, so return TRUE to let it continue.
1035 void wxDC::StartPage()
1039 void wxDC::EndPage()
1043 // ---------------------------------------------------------------------------
1045 // ---------------------------------------------------------------------------
1047 wxCoord
wxDC::GetCharHeight() const
1049 TEXTMETRIC lpTextMetric
;
1051 GetTextMetrics(GetHdc(), &lpTextMetric
);
1053 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
1056 wxCoord
wxDC::GetCharWidth() const
1058 TEXTMETRIC lpTextMetric
;
1060 GetTextMetrics(GetHdc(), &lpTextMetric
);
1062 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
1065 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1066 wxCoord
*descent
, wxCoord
*externalLeading
,
1067 wxFont
*theFont
) const
1069 wxFont
*fontToUse
= (wxFont
*) theFont
;
1071 fontToUse
= (wxFont
*) &m_font
;
1076 GetTextExtentPoint(GetHdc(), WXSTRINGCAST string
, wxStrlen(WXSTRINGCAST string
), &sizeRect
);
1077 GetTextMetrics(GetHdc(), &tm
);
1079 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
1080 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
1081 if (descent
) *descent
= tm
.tmDescent
;
1082 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
1085 void wxDC::SetMapMode(int mode
)
1087 m_mappingMode
= mode
;
1089 int pixel_width
= 0;
1090 int pixel_height
= 0;
1094 pixel_width
= GetDeviceCaps(GetHdc(), HORZRES
);
1095 pixel_height
= GetDeviceCaps(GetHdc(), VERTRES
);
1096 mm_width
= GetDeviceCaps(GetHdc(), HORZSIZE
);
1097 mm_height
= GetDeviceCaps(GetHdc(), VERTSIZE
);
1099 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
1104 double mm2pixelsX
= pixel_width
/mm_width
;
1105 double mm2pixelsY
= pixel_height
/mm_height
;
1111 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
1112 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
1117 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
1118 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
1123 m_logicalScaleX
= mm2pixelsX
;
1124 m_logicalScaleY
= mm2pixelsY
;
1129 m_logicalScaleX
= (mm2pixelsX
/10.0);
1130 m_logicalScaleY
= (mm2pixelsY
/10.0);
1136 m_logicalScaleX
= 1.0;
1137 m_logicalScaleY
= 1.0;
1142 if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC
)
1143 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1145 SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1146 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1147 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1148 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
1149 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1150 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1153 void wxDC::SetUserScale(double x
, double y
)
1158 SetMapMode(m_mappingMode
);
1161 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1163 m_signX
= xLeftRight
? 1 : -1;
1164 m_signY
= yBottomUp
? -1 : 1;
1166 SetMapMode(m_mappingMode
);
1169 void wxDC::SetSystemScale(double x
, double y
)
1174 SetMapMode(m_mappingMode
);
1177 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1179 m_logicalOriginX
= x
;
1180 m_logicalOriginY
= y
;
1182 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1185 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1187 m_deviceOriginX
= x
;
1188 m_deviceOriginY
= y
;
1190 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1193 // ---------------------------------------------------------------------------
1194 // coordinates transformations
1195 // ---------------------------------------------------------------------------
1197 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1199 return (wxCoord
) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
) - m_logicalOriginX
);
1202 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1204 return (wxCoord
) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
));
1207 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1209 return (wxCoord
) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
) - m_logicalOriginY
);
1212 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1214 return (wxCoord
) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
));
1217 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1219 return (wxCoord
) ((x
- m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
+ m_deviceOriginX
);
1222 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1224 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
);
1227 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1229 return (wxCoord
) ((y
- m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
+ m_deviceOriginY
);
1232 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1234 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
);
1237 // ---------------------------------------------------------------------------
1239 // ---------------------------------------------------------------------------
1240 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
1241 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
, int rop
, bool useMask
)
1243 wxCoord xdest1
= xdest
;
1244 wxCoord ydest1
= ydest
;
1245 wxCoord xsrc1
= xsrc
;
1246 wxCoord ysrc1
= ysrc
;
1248 COLORREF old_textground
= ::GetTextColor(GetHdc());
1249 COLORREF old_background
= ::GetBkColor(GetHdc());
1250 if (m_textForegroundColour
.Ok())
1252 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1254 if (m_textBackgroundColour
.Ok())
1256 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1259 DWORD dwRop
= rop
== wxCOPY
? SRCCOPY
:
1260 rop
== wxCLEAR
? WHITENESS
:
1261 rop
== wxSET
? BLACKNESS
:
1262 rop
== wxINVERT
? DSTINVERT
:
1263 rop
== wxAND
? MERGECOPY
:
1264 rop
== wxOR
? MERGEPAINT
:
1265 rop
== wxSRC_INVERT
? NOTSRCCOPY
:
1266 rop
== wxXOR
? SRCINVERT
:
1267 rop
== wxOR_REVERSE
? MERGEPAINT
:
1268 rop
== wxAND_REVERSE
? SRCERASE
:
1269 rop
== wxSRC_OR
? SRCPAINT
:
1270 rop
== wxSRC_AND
? SRCAND
:
1273 bool success
= TRUE
;
1274 if (useMask
&& source
->m_selectedBitmap
.Ok() && source
->m_selectedBitmap
.GetMask())
1278 // Not implemented under Win95 (or maybe a specific device?)
1279 if (MaskBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1280 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap(),
1288 // New code from Chris Breeze, 15/7/98
1289 // Blit bitmap with mask
1291 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1293 // If we are printing source colours are screen colours
1294 // not printer colours and so we need copy the bitmap
1297 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1298 HDC dc_src
= (HDC
) source
->m_hDC
;
1300 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1301 for (int x
= 0; x
< width
; x
++)
1303 for (int y
= 0; y
< height
; y
++)
1305 COLORREF cref
= ::GetPixel(dc_mask
, x
, y
);
1308 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1309 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1310 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1311 ::FillRect(GetHdc(), &rect
, brush
);
1312 ::DeleteObject(brush
);
1316 ::SelectObject(dc_mask
, 0);
1317 ::DeleteDC(dc_mask
);
1321 // create a temp buffer bitmap and DCs to access it and the mask
1322 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1323 HDC dc_buffer
= ::CreateCompatibleDC(GetHdc());
1324 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1325 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1326 ::SelectObject(dc_buffer
, buffer_bmap
);
1328 // copy dest to buffer
1329 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1330 GetHdc(), xdest1
, ydest1
, SRCCOPY
);
1332 // copy src to buffer using selected raster op
1333 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1334 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, dwRop
);
1336 // set masked area in buffer to BLACK (pixel value 0)
1337 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1338 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1339 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1340 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1342 // set unmasked area in dest to BLACK
1343 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1344 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1345 ::BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1346 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1347 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1348 ::SetTextColor(GetHdc(), prevCol
);
1350 // OR buffer to dest
1351 success
= (::BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1352 dc_buffer
, 0, 0, SRCPAINT
) != 0);
1354 // tidy up temporary DCs and bitmap
1355 ::SelectObject(dc_mask
, 0);
1356 ::DeleteDC(dc_mask
);
1357 ::SelectObject(dc_buffer
, 0);
1358 ::DeleteDC(dc_buffer
);
1359 ::DeleteObject(buffer_bmap
);
1365 // If we are printing, source colours are screen colours
1366 // not printer colours and so we need copy the bitmap
1368 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1370 HDC dc_src
= (HDC
) source
->m_hDC
;
1372 for (int y
= 0; y
< height
; y
++)
1374 // This is Stefan Csomor's optimisation, where
1375 // identical adjacent pixels are drawn together.
1376 // We still need a faster way of drawing bitmaps,
1377 // perhaps converting to a DIB first and using SetDIBitsToDevice.
1378 for (int x
= 0; x
< width
; x
++)
1380 COLORREF col
= ::GetPixel(dc_src
, x
, y
) ;
1381 HBRUSH brush
= ::CreateSolidBrush( col
);
1383 rect
.left
= xdest1
+ x
;
1384 rect
.top
= ydest1
+ y
;
1385 while( (x
+ 1 < width
) && (::GetPixel(dc_src
, x
+ 1, y
) == col
) )
1389 rect
.right
= xdest1
+ x
+ 1;
1390 rect
.bottom
= rect
.top
+ 1;
1391 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1392 ::DeleteObject(brush
);
1396 HDC dc_src = (HDC) source->m_hDC;
1398 for (int x = 0; x < width; x++)
1400 for (int y = 0; y < height; y++)
1402 HBRUSH brush = ::CreateSolidBrush(::GetPixel(dc_src, x, y));
1403 rect.left = xdest1 + x; rect.right = rect.left + 1;
1404 rect.top = ydest1 + y; rect.bottom = rect.top + 1;
1405 ::FillRect(GetHdc(), &rect, brush);
1406 ::DeleteObject(brush);
1413 success
= (BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
, (HDC
) source
->m_hDC
,
1414 xsrc1
, ysrc1
, dwRop
) != 0);
1417 ::SetTextColor(GetHdc(), old_textground
);
1418 ::SetBkColor(GetHdc(), old_background
);
1423 void wxDC::DoGetSize(int *w
, int *h
) const
1425 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1426 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1429 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1431 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZSIZE
);
1432 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1435 wxSize
wxDC::GetPPI() const
1437 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1438 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1440 return wxSize(x
, y
);
1443 // For use by wxWindows only, unless custom units are required.
1444 void wxDC::SetLogicalScale(double x
, double y
)
1446 m_logicalScaleX
= x
;
1447 m_logicalScaleY
= y
;
1450 #if WXWIN_COMPATIBILITY
1451 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1452 float *descent
, float *externalLeading
,
1453 wxFont
*theFont
, bool use16bit
) const
1455 wxCoord x1
, y1
, descent1
, externalLeading1
;
1456 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1459 *descent
= descent1
;
1460 if (externalLeading
)
1461 *externalLeading
= externalLeading1
;
1465 // ---------------------------------------------------------------------------
1466 // spline drawing code
1467 // ---------------------------------------------------------------------------
1471 class wxSpline
: public wxObject
1477 wxSpline(wxList
*list
);
1478 void DeletePoints();
1480 // Doesn't delete points
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();
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::DoDrawSpline(wxList
*list
)
1499 wxSpline
spline(list
);
1501 wx_draw_open_spline(this, &spline
);
1504 wxList wx_spline_point_list
;
1506 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1509 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1510 double x1
, y1
, x2
, y2
;
1512 wxNode
*node
= spline
->points
->First();
1513 p
= (wxPoint
*)node
->Data();
1518 node
= node
->Next();
1519 p
= (wxPoint
*)node
->Data();
1523 cx1
= (double)((x1
+ x2
) / 2);
1524 cy1
= (double)((y1
+ y2
) / 2);
1525 cx2
= (double)((cx1
+ x2
) / 2);
1526 cy2
= (double)((cy1
+ y2
) / 2);
1528 wx_spline_add_point(x1
, y1
);
1530 while ((node
= node
->Next()) != NULL
)
1532 p
= (wxPoint
*)node
->Data();
1537 cx4
= (double)(x1
+ x2
) / 2;
1538 cy4
= (double)(y1
+ y2
) / 2;
1539 cx3
= (double)(x1
+ cx4
) / 2;
1540 cy3
= (double)(y1
+ cy4
) / 2;
1542 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1546 cx2
= (double)(cx1
+ x2
) / 2;
1547 cy2
= (double)(cy1
+ y2
) / 2;
1550 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1551 wx_spline_add_point(x2
, y2
);
1553 wx_spline_draw_point_array(dc
);
1557 /********************* CURVES FOR SPLINES *****************************
1559 The following spline drawing routine is from
1561 "An Algorithm for High-Speed Curve Generation"
1562 by George Merrill Chaikin,
1563 Computer Graphics and Image Processing, 3, Academic Press,
1568 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1569 Computer Graphics and Image Processing, 4, Academic Press,
1572 ***********************************************************************/
1574 #define half(z1, z2) ((z1+z2)/2.0)
1577 /* iterative version */
1579 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1582 register double xmid
, ymid
;
1583 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1586 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1588 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1589 xmid
= (double)half(x2
, x3
);
1590 ymid
= (double)half(y2
, y3
);
1591 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1592 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1593 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1594 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1596 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1597 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1598 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1599 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1605 /* utilities used by spline drawing routines */
1608 typedef struct wx_spline_stack_struct
{
1609 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1613 #define SPLINE_STACK_DEPTH 20
1614 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1615 static Stack
*wx_stack_top
;
1616 static int wx_stack_count
;
1618 void wx_clear_stack()
1620 wx_stack_top
= wx_spline_stack
;
1624 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1626 wx_stack_top
->x1
= x1
;
1627 wx_stack_top
->y1
= y1
;
1628 wx_stack_top
->x2
= x2
;
1629 wx_stack_top
->y2
= y2
;
1630 wx_stack_top
->x3
= x3
;
1631 wx_stack_top
->y3
= y3
;
1632 wx_stack_top
->x4
= x4
;
1633 wx_stack_top
->y4
= y4
;
1638 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1639 double *x3
, double *y3
, double *x4
, double *y4
)
1641 if (wx_stack_count
== 0)
1645 *x1
= wx_stack_top
->x1
;
1646 *y1
= wx_stack_top
->y1
;
1647 *x2
= wx_stack_top
->x2
;
1648 *y2
= wx_stack_top
->y2
;
1649 *x3
= wx_stack_top
->x3
;
1650 *y3
= wx_stack_top
->y3
;
1651 *x4
= wx_stack_top
->x4
;
1652 *y4
= wx_stack_top
->y4
;
1656 static bool wx_spline_add_point(double x
, double y
)
1658 wxPoint
*point
= new wxPoint
;
1661 wx_spline_point_list
.Append((wxObject
*)point
);
1665 static void wx_spline_draw_point_array(wxDC
*dc
)
1667 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
1668 wxNode
*node
= wx_spline_point_list
.First();
1671 wxPoint
*point
= (wxPoint
*)node
->Data();
1674 node
= wx_spline_point_list
.First();
1678 wxSpline::wxSpline(wxList
*list
)
1683 wxSpline::~wxSpline()
1687 void wxSpline::DeletePoints()
1689 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1691 wxPoint
*point
= (wxPoint
*)node
->Data();
1699 #endif // wxUSE_SPLINES