1 /////////////////////////////////////////////////////////////////////////////
4 // Author: David Webster
8 // Copyright: (c) David Webster
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
16 #include "wx/window.h"
19 #include "wx/dialog.h"
21 #include "wx/bitmap.h"
22 #include "wx/dcmemory.h"
27 #include "wx/dcprint.h"
32 #include "wx/os2/private.h"
34 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
36 // ---------------------------------------------------------------------------
38 // ---------------------------------------------------------------------------
40 static const int VIEWPORT_EXTENT
= 1000;
42 static const int MM_POINTS
= 9;
43 static const int MM_METRIC
= 10;
45 // usually this is defined in math.h
47 static const double M_PI
= 3.14159265358979323846;
50 // ---------------------------------------------------------------------------
52 // ---------------------------------------------------------------------------
54 // convert degrees to radians
55 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
57 // ===========================================================================
59 // ===========================================================================
61 // ---------------------------------------------------------------------------
63 // ---------------------------------------------------------------------------
85 // This will select current objects out of the DC,
86 // which is what you have to do before deleting the
88 void wxDC::SelectOldObjects(WXHDC dc
)
94 // ::SelectObject((HDC) dc, (HBITMAP) m_oldBitmap);
95 if (m_vSelectedBitmap
.Ok())
97 m_vSelectedBitmap
.SetSelectedInto(NULL
);
103 // ::SelectObject((HDC) dc, (HPEN) m_oldPen);
108 // ::SelectObject((HDC) dc, (HBRUSH) m_oldBrush);
113 // ::SelectObject((HDC) dc, (HFONT) m_oldFont);
118 // ::SelectPalette((HDC) dc, (HPALETTE) m_oldPalette, TRUE);
123 m_brush
= wxNullBrush
;
125 m_palette
= wxNullPalette
;
127 m_backgroundBrush
= wxNullBrush
;
128 m_vSelectedBitmap
= wxNullBitmap
;
131 // ---------------------------------------------------------------------------
133 // ---------------------------------------------------------------------------
135 #define DO_SET_CLIPPING_BOX() \
139 GetClipBox(GetHdc(), &rect); \
141 m_clipX1 = (wxCoord) XDEV2LOG(rect.left); \
142 m_clipY1 = (wxCoord) YDEV2LOG(rect.top); \
143 m_clipX2 = (wxCoord) XDEV2LOG(rect.right); \
144 m_clipY2 = (wxCoord) YDEV2LOG(rect.bottom); \
147 void wxDC::DoSetClippingRegion( wxCoord x
, wxCoord y
148 ,wxCoord width
, wxCoord height
154 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
159 void wxDC::DestroyClippingRegion(void)
164 // ---------------------------------------------------------------------------
165 // query capabilities
166 // ---------------------------------------------------------------------------
168 bool wxDC::CanDrawBitmap() const
173 bool wxDC::CanGetTextExtent() const
175 // What sort of display is it?
176 int technology
= 0; // TODO: ::GetDeviceCaps(GetHdc(), TECHNOLOGY);
178 // TODO: return (technology == DT_RASDISPLAY) || (technology == DT_RASPRINTER);
182 int wxDC::GetDepth() const
188 // ---------------------------------------------------------------------------
190 // ---------------------------------------------------------------------------
197 void wxDC::DoFloodFill( wxCoord x
206 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
212 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
217 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
222 void wxDC::DoDrawArc( wxCoord x1
, wxCoord y1
223 ,wxCoord x2
, wxCoord y2
224 ,wxCoord xc
, wxCoord yc
230 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
231 wxCoord width
, wxCoord height
)
236 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
241 void wxDC::DoDrawPolygon(int n
, wxPoint points
[]
242 ,wxCoord xoffset
, wxCoord yoffset
249 void wxDC::DoDrawLines( int n
, wxPoint points
[]
250 ,wxCoord xoffset
, wxCoord yoffset
256 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
261 void wxDC::DoDrawRoundedRectangle( wxCoord x
, wxCoord y
262 ,wxCoord width
, wxCoord height
269 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
274 void wxDC::DoDrawEllipticArc( wxCoord x
285 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
290 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
291 ,wxCoord x
, wxCoord y
298 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
303 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
308 void wxDC::DoDrawRotatedText(const wxString
& text
,
309 wxCoord x
, wxCoord y
,
316 DoDrawText(text, x, y);
321 wxFillLogFont(&lf, &m_font);
323 // GDI wants the angle in tenth of degree
324 long angle10 = (long)(angle * 10);
325 lf.lfEscapement = angle10;
326 lf. lfOrientation = angle10;
328 HFONT hfont = ::CreateFontIndirect(&lf);
331 wxLogLastError("CreateFont");
335 HFONT hfontOld = ::SelectObject(GetHdc(), hfont);
337 DrawAnyText(text, x, y);
339 (void)::SelectObject(GetHdc(), hfontOld);
342 // call the bounding box by adding all four vertices of the rectangle
343 // containing the text to it (simpler and probably not slower than
344 // determining which of them is really topmost/leftmost/...)
346 GetTextExtent(text, &w, &h);
348 double rad = DegToRad(angle);
350 // "upper left" and "upper right"
351 CalcBoundingBox(x, y);
352 CalcBoundingBox(x + w*cos(rad), y - h*sin(rad));
353 CalcBoundingBox(x + h*sin(rad), y + h*cos(rad));
355 // "bottom left" and "bottom right"
356 x += (wxCoord)(h*sin(rad));
357 y += (wxCoord)(h*cos(rad));
358 CalcBoundingBox(x, y);
359 CalcBoundingBox(x + h*sin(rad), y + h*cos(rad));
364 // ---------------------------------------------------------------------------
366 // ---------------------------------------------------------------------------
368 void wxDC::SetPalette(const wxPalette
& palette
)
378 // Set the old object temporarily, in case the assignment deletes an object
379 // that's not yet selected out.
383 // ::SelectObject(GetHdc(), (HFONT) m_hOldFont);
392 // ::SelectObject(GetHdc(), (HFONT) m_hOldFont);
396 if (m_font
.Ok() && m_font
.GetResourceHandle())
398 HFONT hFont
= (HFONT
)0; //::SelectObject(GetHdc(), (HFONT) m_font.GetResourceHandle());
399 if (hFont
== (HFONT
) NULL
)
401 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
404 m_hOldFont
= (WXHFONT
) hFont
;
408 void wxDC::SetPen(const wxPen
& pen
)
412 void wxDC::SetBrush(const wxBrush
& brush
)
417 void wxDC::SetBackground(const wxBrush
& brush
)
422 void wxDC::SetBackgroundMode(int mode
)
427 void wxDC::SetLogicalFunction(int function
)
432 void wxDC::SetRop(WXHDC dc
)
434 if (!dc
|| m_logicalFunction
< 0)
438 // These may be wrong
439 switch (m_logicalFunction
)
441 // TODO: Figure this stuff out
442 // case wxXOR: c_rop = R2_XORPEN; break;
443 // case wxXOR: c_rop = R2_NOTXORPEN; break;
444 // case wxINVERT: c_rop = R2_NOT; break;
445 // case wxOR_REVERSE: c_rop = R2_MERGEPENNOT; break;
446 // case wxAND_REVERSE: c_rop = R2_MASKPENNOT; break;
447 // case wxCLEAR: c_rop = R2_WHITE; break;
448 // case wxSET: c_rop = R2_BLACK; break;
449 // case wxSRC_INVERT: c_rop = R2_NOTCOPYPEN; break;
450 // case wxOR_INVERT: c_rop = R2_MERGENOTPEN; break;
451 // case wxAND: c_rop = R2_MASKPEN; break;
452 // case wxOR: c_rop = R2_MERGEPEN; break;
453 // case wxAND_INVERT: c_rop = R2_MASKNOTPEN; break;
458 // c_rop = R2_COPYPEN;
461 // SetROP2((HDC) dc, c_rop);
464 bool wxDC::StartDoc(const wxString
& message
)
466 // We might be previewing, so return TRUE to let it continue.
474 void wxDC::StartPage()
482 // ---------------------------------------------------------------------------
484 // ---------------------------------------------------------------------------
486 wxCoord
wxDC::GetCharHeight() const
492 wxCoord
wxDC::GetCharWidth() const
498 void wxDC::DoGetTextExtent( const wxString
& string
502 ,wxCoord
* externalLeading
509 void wxDC::SetMapMode( int mode
)
514 void wxDC::SetUserScale(double x
, double y
)
519 SetMapMode(m_mappingMode
);
522 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
524 m_signX
= xLeftRight
? 1 : -1;
525 m_signY
= yBottomUp
? -1 : 1;
527 SetMapMode(m_mappingMode
);
530 void wxDC::SetSystemScale(double x
, double y
)
535 SetMapMode(m_mappingMode
);
538 void wxDC::SetLogicalOrigin( wxCoord x
, wxCoord y
)
543 void wxDC::SetDeviceOrigin( wxCoord x
, wxCoord y
)
548 // ---------------------------------------------------------------------------
549 // coordinates transformations
550 // ---------------------------------------------------------------------------
552 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
554 return (wxCoord
) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
) - m_logicalOriginX
);
557 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
559 return (wxCoord
) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
));
562 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
564 return (wxCoord
) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
) - m_logicalOriginY
);
567 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
569 return (wxCoord
) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
));
572 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
574 return (wxCoord
) ((x
- m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
+ m_deviceOriginX
);
577 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
579 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
);
582 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
584 return (wxCoord
) ((y
- m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
+ m_deviceOriginY
);
587 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
589 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
);
592 // ---------------------------------------------------------------------------
594 // ---------------------------------------------------------------------------
596 bool wxDC::DoBlit( wxCoord xdest
611 void wxDC::DoGetSize( int* width
, int* height
) const
616 void wxDC::DoGetSizeMM( int* width
, int* height
) const
621 wxSize
wxDC::GetPPI() const
626 return (wxSize(x
,y
));
629 void wxDC::SetLogicalScale( double x
, double y
)
634 #if WXWIN_COMPATIBILITY
635 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
636 float *descent
, float *externalLeading
,
637 wxFont
*theFont
, bool use16bit
) const
639 wxCoord x1
, y1
, descent1
, externalLeading1
;
640 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
645 *externalLeading
= externalLeading1
;
649 // ---------------------------------------------------------------------------
650 // spline drawing code
651 // ---------------------------------------------------------------------------
655 class wxSpline
: public wxObject
661 wxSpline(wxList
*list
);
664 // Doesn't delete points
668 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
670 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
671 double a3
, double b3
, double a4
, double b4
);
672 void wx_clear_stack();
673 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
674 double *y3
, double *x4
, double *y4
);
675 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
676 double x4
, double y4
);
677 static bool wx_spline_add_point(double x
, double y
);
678 static void wx_spline_draw_point_array(wxDC
*dc
);
679 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
681 void wxDC::DoDrawSpline(wxList
*list
)
683 wxSpline
spline(list
);
685 wx_draw_open_spline(this, &spline
);
688 wxList wx_spline_point_list
;
690 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
693 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
694 double x1
, y1
, x2
, y2
;
696 wxNode
*node
= spline
->points
->First();
697 p
= (wxPoint
*)node
->Data();
703 p
= (wxPoint
*)node
->Data();
707 cx1
= (double)((x1
+ x2
) / 2);
708 cy1
= (double)((y1
+ y2
) / 2);
709 cx2
= (double)((cx1
+ x2
) / 2);
710 cy2
= (double)((cy1
+ y2
) / 2);
712 wx_spline_add_point(x1
, y1
);
714 while ((node
= node
->Next()) != NULL
)
716 p
= (wxPoint
*)node
->Data();
721 cx4
= (double)(x1
+ x2
) / 2;
722 cy4
= (double)(y1
+ y2
) / 2;
723 cx3
= (double)(x1
+ cx4
) / 2;
724 cy3
= (double)(y1
+ cy4
) / 2;
726 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
730 cx2
= (double)(cx1
+ x2
) / 2;
731 cy2
= (double)(cy1
+ y2
) / 2;
734 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
735 wx_spline_add_point(x2
, y2
);
737 wx_spline_draw_point_array(dc
);
741 /********************* CURVES FOR SPLINES *****************************
743 The following spline drawing routine is from
745 "An Algorithm for High-Speed Curve Generation"
746 by George Merrill Chaikin,
747 Computer Graphics and Image Processing, 3, Academic Press,
752 "On Chaikin's Algorithm" by R. F. Riesenfeld,
753 Computer Graphics and Image Processing, 4, Academic Press,
756 ***********************************************************************/
758 #define half(z1, z2) ((z1+z2)/2.0)
761 /* iterative version */
763 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
766 register double xmid
, ymid
;
767 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
770 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
772 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
773 xmid
= (double)half(x2
, x3
);
774 ymid
= (double)half(y2
, y3
);
775 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
776 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
777 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
778 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
780 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
781 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
782 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
783 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
789 /* utilities used by spline drawing routines */
792 typedef struct wx_spline_stack_struct
{
793 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
797 #define SPLINE_STACK_DEPTH 20
798 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
799 static Stack
*wx_stack_top
;
800 static int wx_stack_count
;
802 void wx_clear_stack()
804 wx_stack_top
= wx_spline_stack
;
808 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
810 wx_stack_top
->x1
= x1
;
811 wx_stack_top
->y1
= y1
;
812 wx_stack_top
->x2
= x2
;
813 wx_stack_top
->y2
= y2
;
814 wx_stack_top
->x3
= x3
;
815 wx_stack_top
->y3
= y3
;
816 wx_stack_top
->x4
= x4
;
817 wx_stack_top
->y4
= y4
;
822 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
823 double *x3
, double *y3
, double *x4
, double *y4
)
825 if (wx_stack_count
== 0)
829 *x1
= wx_stack_top
->x1
;
830 *y1
= wx_stack_top
->y1
;
831 *x2
= wx_stack_top
->x2
;
832 *y2
= wx_stack_top
->y2
;
833 *x3
= wx_stack_top
->x3
;
834 *y3
= wx_stack_top
->y3
;
835 *x4
= wx_stack_top
->x4
;
836 *y4
= wx_stack_top
->y4
;
840 static bool wx_spline_add_point(double x
, double y
)
842 wxPoint
*point
= new wxPoint
;
845 wx_spline_point_list
.Append((wxObject
*)point
);
849 static void wx_spline_draw_point_array(wxDC
*dc
)
851 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
852 wxNode
*node
= wx_spline_point_list
.First();
855 wxPoint
*point
= (wxPoint
*)node
->Data();
858 node
= wx_spline_point_list
.First();
862 wxSpline::wxSpline(wxList
*list
)
867 wxSpline::~wxSpline()
871 void wxSpline::DeletePoints()
873 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
875 wxPoint
*point
= (wxPoint
*)node
->Data();
883 #endif // wxUSE_SPLINES