1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/dcbase.cpp
3 // Purpose: generic methods of the wxDC Class
4 // Author: Vadim Zeitlin
8 // Copyright: (c) wxWidgets team
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
33 // bool wxDCBase::sm_cacheing = false;
35 IMPLEMENT_ABSTRACT_CLASS(wxDCBase
, wxObject
)
37 // ============================================================================
39 // ============================================================================
41 #if WXWIN_COMPATIBILITY_2_6
42 void wxDCBase::BeginDrawing()
46 void wxDCBase::EndDrawing()
49 #endif // WXWIN_COMPATIBILITY_2_6
51 // ----------------------------------------------------------------------------
53 // ----------------------------------------------------------------------------
55 void wxDCBase::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
56 wxCoord width
, wxCoord height
)
58 wxCHECK_RET( Ok(), wxT("invalid window dc") );
60 wxCoord x2
= x1
+ width
,
63 // this is to yield width of 3 for width == height == 10
64 SetPen(wxPen(GetTextForeground(), (width
+ height
+ 1) / 7, wxSOLID
));
66 // we're drawing a scaled version of wx/generic/tick.xpm here
67 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
68 y3
= y1
+ height
/ 2; // y of the left tick branch
69 DoDrawLine(x1
, y3
, x3
, y2
);
70 DoDrawLine(x3
, y2
, x2
, y1
);
72 CalcBoundingBox(x1
, y1
);
73 CalcBoundingBox(x2
, y2
);
76 // ----------------------------------------------------------------------------
78 // ----------------------------------------------------------------------------
80 void wxDCBase::DrawLines(const wxList
*list
, wxCoord xoffset
, wxCoord yoffset
)
82 int n
= list
->GetCount();
83 wxPoint
*points
= new wxPoint
[n
];
86 for ( wxList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
88 wxPoint
*point
= (wxPoint
*)node
->GetData();
89 points
[i
].x
= point
->x
;
90 points
[i
].y
= point
->y
;
93 DoDrawLines(n
, points
, xoffset
, yoffset
);
99 void wxDCBase::DrawPolygon(const wxList
*list
,
100 wxCoord xoffset
, wxCoord yoffset
,
103 int n
= list
->GetCount();
104 wxPoint
*points
= new wxPoint
[n
];
107 for ( wxList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
109 wxPoint
*point
= (wxPoint
*)node
->GetData();
110 points
[i
].x
= point
->x
;
111 points
[i
].y
= point
->y
;
114 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
120 wxDCBase::DoDrawPolyPolygon(int n
,
123 wxCoord xoffset
, wxCoord yoffset
,
128 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
136 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
141 pts
= new wxPoint
[j
+n
-1];
142 for (i
= 0; i
< j
; i
++)
144 for (i
= 2; i
<= n
; i
++)
146 lastOfs
-= count
[n
-i
];
147 pts
[j
++] = pts
[lastOfs
];
151 SetPen(wxPen(*wxBLACK
, 0, wxTRANSPARENT
));
152 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
154 for (i
= j
= 0; i
< n
; i
++)
156 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
162 // ----------------------------------------------------------------------------
164 // ----------------------------------------------------------------------------
168 // TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?)
169 void wxDCBase::DrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
)
173 wxPoint
*point1
= new wxPoint
;
174 point1
->x
= x1
; point1
->y
= y1
;
175 point_list
.Append((wxObject
*)point1
);
177 wxPoint
*point2
= new wxPoint
;
178 point2
->x
= x2
; point2
->y
= y2
;
179 point_list
.Append((wxObject
*)point2
);
181 wxPoint
*point3
= new wxPoint
;
182 point3
->x
= x3
; point3
->y
= y3
;
183 point_list
.Append((wxObject
*)point3
);
185 DrawSpline(&point_list
);
187 for( wxList::compatibility_iterator node
= point_list
.GetFirst(); node
; node
= node
->GetNext() )
189 wxPoint
*p
= (wxPoint
*)node
->GetData();
194 void wxDCBase::DrawSpline(int n
, wxPoint points
[])
197 for (int i
=0; i
< n
; i
++)
199 list
.Append((wxObject
*)&points
[i
]);
205 // ----------------------------------- spline code ----------------------------------------
207 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
208 double a3
, double b3
, double a4
, double b4
);
209 void wx_clear_stack();
210 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
211 double *y3
, double *x4
, double *y4
);
212 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
213 double x4
, double y4
);
214 static bool wx_spline_add_point(double x
, double y
);
215 static void wx_spline_draw_point_array(wxDCBase
*dc
);
217 wxList wx_spline_point_list
;
219 #define half(z1, z2) ((z1+z2)/2.0)
222 /* iterative version */
224 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
227 register double xmid
, ymid
;
228 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
231 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
233 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
234 xmid
= (double)half(x2
, x3
);
235 ymid
= (double)half(y2
, y3
);
236 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
237 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
238 wx_spline_add_point( x1
, y1
);
239 wx_spline_add_point( xmid
, ymid
);
241 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
242 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
243 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
244 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
249 /* utilities used by spline drawing routines */
251 typedef struct wx_spline_stack_struct
{
252 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
255 #define SPLINE_STACK_DEPTH 20
256 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
257 static Stack
*wx_stack_top
;
258 static int wx_stack_count
;
260 void wx_clear_stack()
262 wx_stack_top
= wx_spline_stack
;
266 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
268 wx_stack_top
->x1
= x1
;
269 wx_stack_top
->y1
= y1
;
270 wx_stack_top
->x2
= x2
;
271 wx_stack_top
->y2
= y2
;
272 wx_stack_top
->x3
= x3
;
273 wx_stack_top
->y3
= y3
;
274 wx_stack_top
->x4
= x4
;
275 wx_stack_top
->y4
= y4
;
280 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
281 double *x3
, double *y3
, double *x4
, double *y4
)
283 if (wx_stack_count
== 0)
287 *x1
= wx_stack_top
->x1
;
288 *y1
= wx_stack_top
->y1
;
289 *x2
= wx_stack_top
->x2
;
290 *y2
= wx_stack_top
->y2
;
291 *x3
= wx_stack_top
->x3
;
292 *y3
= wx_stack_top
->y3
;
293 *x4
= wx_stack_top
->x4
;
294 *y4
= wx_stack_top
->y4
;
298 static bool wx_spline_add_point(double x
, double y
)
300 wxPoint
*point
= new wxPoint
;
303 wx_spline_point_list
.Append((wxObject
*)point
);
307 static void wx_spline_draw_point_array(wxDCBase
*dc
)
309 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
310 wxList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
313 wxPoint
*point
= (wxPoint
*)node
->GetData();
315 wx_spline_point_list
.Erase(node
);
316 node
= wx_spline_point_list
.GetFirst();
320 void wxDCBase::DoDrawSpline( wxList
*points
)
322 wxCHECK_RET( Ok(), wxT("invalid window dc") );
325 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
326 double x1
, y1
, x2
, y2
;
328 wxList::compatibility_iterator node
= points
->GetFirst();
329 if (node
== wxList::compatibility_iterator())
333 p
= (wxPoint
*)node
->GetData();
338 node
= node
->GetNext();
339 p
= (wxPoint
*)node
->GetData();
343 cx1
= (double)((x1
+ x2
) / 2);
344 cy1
= (double)((y1
+ y2
) / 2);
345 cx2
= (double)((cx1
+ x2
) / 2);
346 cy2
= (double)((cy1
+ y2
) / 2);
348 wx_spline_add_point(x1
, y1
);
350 while ((node
= node
->GetNext())
356 p
= (wxPoint
*)node
->GetData();
361 cx4
= (double)(x1
+ x2
) / 2;
362 cy4
= (double)(y1
+ y2
) / 2;
363 cx3
= (double)(x1
+ cx4
) / 2;
364 cy3
= (double)(y1
+ cy4
) / 2;
366 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
370 cx2
= (double)(cx1
+ x2
) / 2;
371 cy2
= (double)(cy1
+ y2
) / 2;
374 wx_spline_add_point( cx1
, cy1
);
375 wx_spline_add_point( x2
, y2
);
377 wx_spline_draw_point_array( this );
380 #endif // wxUSE_SPLINES
382 // ----------------------------------------------------------------------------
383 // Partial Text Extents
384 // ----------------------------------------------------------------------------
387 // Each element of the widths array will be the width of the string up to and
388 // including the corresponding character in text. This is the generic
389 // implementation, the port-specific classes should do this with native APIs
390 // if available and if faster. Note: pango_layout_index_to_pos is much slower
391 // than calling GetTextExtent!!
398 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
399 ~FontWidthCache() { delete []m_widths
; }
404 m_widths
= new int[FWC_SIZE
];
406 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
414 static FontWidthCache s_fontWidthCache
;
416 bool wxDCBase::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
420 const size_t len
= text
.length();
424 // reset the cache if font or horizontal scale have changed
425 if ( !s_fontWidthCache
.m_widths
||
426 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
427 (s_fontWidthCache
.m_font
!= GetFont()) )
429 s_fontWidthCache
.Reset();
430 s_fontWidthCache
.m_font
= GetFont();
431 s_fontWidthCache
.m_scaleX
= m_scaleX
;
434 // Calculate the position of each character based on the widths of
435 // the previous characters
437 for ( size_t i
= 0; i
< len
; i
++ )
439 const wxChar c
= text
[i
];
440 unsigned int c_int
= (unsigned int)c
;
442 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
444 w
= s_fontWidthCache
.m_widths
[c_int
];
448 GetTextExtent(c
, &w
, &h
);
449 if (c_int
< FWC_SIZE
)
450 s_fontWidthCache
.m_widths
[c_int
] = w
;
454 widths
[i
] = totalWidth
;
461 // ----------------------------------------------------------------------------
462 // enhanced text drawing
463 // ----------------------------------------------------------------------------
465 void wxDCBase::GetMultiLineTextExtent(const wxString
& text
,
471 wxCoord widthTextMax
= 0, widthLine
,
472 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
475 for ( const wxChar
*pc
= text
; ; pc
++ )
477 if ( *pc
== _T('\n') || *pc
== _T('\0') )
479 if ( curLine
.empty() )
481 // we can't use GetTextExtent - it will return 0 for both width
482 // and height and an empty line should count in height
485 // assume that this line has the same height as the previous
487 if ( !heightLineDefault
)
488 heightLineDefault
= heightLine
;
490 if ( !heightLineDefault
)
492 // but we don't know it yet - choose something reasonable
493 GetTextExtent(_T("W"), NULL
, &heightLineDefault
,
497 heightTextTotal
+= heightLineDefault
;
501 GetTextExtent(curLine
, &widthLine
, &heightLine
,
503 if ( widthLine
> widthTextMax
)
504 widthTextMax
= widthLine
;
505 heightTextTotal
+= heightLine
;
508 if ( *pc
== _T('\n') )
527 *y
= heightTextTotal
;
532 void wxDCBase::DrawLabel(const wxString
& text
,
533 const wxBitmap
& bitmap
,
537 wxRect
*rectBounding
)
539 // find the text position
540 wxCoord widthText
, heightText
, heightLine
;
541 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
543 wxCoord width
, height
;
546 width
= widthText
+ bitmap
.GetWidth();
547 height
= bitmap
.GetHeight();
556 if ( alignment
& wxALIGN_RIGHT
)
558 x
= rect
.GetRight() - width
;
560 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
562 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
564 else // alignment & wxALIGN_LEFT
569 if ( alignment
& wxALIGN_BOTTOM
)
571 y
= rect
.GetBottom() - height
;
573 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
575 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
577 else // alignment & wxALIGN_TOP
582 // draw the bitmap first
588 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
590 wxCoord offset
= bitmap
.GetWidth() + 4;
594 y
+= (height
- heightText
) / 2;
597 // we will draw the underscore under the accel char later
598 wxCoord startUnderscore
= 0,
602 // split the string into lines and draw each of them separately
604 for ( const wxChar
*pc
= text
; ; pc
++ )
606 if ( *pc
== _T('\n') || *pc
== _T('\0') )
608 int xRealStart
= x
; // init it here to avoid compielr warnings
610 if ( !curLine
.empty() )
612 // NB: can't test for !(alignment & wxALIGN_LEFT) because
614 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
617 GetTextExtent(curLine
, &widthLine
, NULL
);
619 if ( alignment
& wxALIGN_RIGHT
)
621 xRealStart
+= width
- widthLine
;
623 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
625 xRealStart
+= (width
- widthLine
) / 2;
628 //else: left aligned, nothing to do
630 DrawText(curLine
, xRealStart
, y
);
635 // do we have underscore in this line? we can check yUnderscore
636 // because it is set below to just y + heightLine if we do
637 if ( y
== yUnderscore
)
639 // adjust the horz positions to account for the shift
640 startUnderscore
+= xRealStart
;
641 endUnderscore
+= xRealStart
;
644 if ( *pc
== _T('\0') )
649 else // not end of line
651 if ( pc
- text
.c_str() == indexAccel
)
653 // remeber to draw underscore here
654 GetTextExtent(curLine
, &startUnderscore
, NULL
);
656 GetTextExtent(curLine
, &endUnderscore
, NULL
);
658 yUnderscore
= y
+ heightLine
;
667 // draw the underscore if found
668 if ( startUnderscore
!= endUnderscore
)
670 // it should be of the same colour as text
671 SetPen(wxPen(GetTextForeground(), 0, wxSOLID
));
675 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
678 // return bounding rect if requested
681 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
684 CalcBoundingBox(x0
, y0
);
685 CalcBoundingBox(x0
+ width0
, y0
+ height
);
689 void wxDCBase::DoGradientFillLinear(const wxRect
& rect
,
690 const wxColour
& initialColour
,
691 const wxColour
& destColour
,
692 wxDirection nDirection
)
695 wxPen oldPen
= m_pen
;
697 wxUint8 nR1
= destColour
.Red();
698 wxUint8 nG1
= destColour
.Green();
699 wxUint8 nB1
= destColour
.Blue();
700 wxUint8 nR2
= initialColour
.Red();
701 wxUint8 nG2
= initialColour
.Green();
702 wxUint8 nB2
= initialColour
.Blue();
705 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
707 wxInt32 x
= rect
.GetWidth();
708 wxInt32 w
= x
; // width of area to shade
709 wxInt32 xDelta
= w
/256; // height of one shade bend
717 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
719 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
722 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
724 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
727 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
729 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
731 SetPen(wxPen(wxColour(nR
, nG
, nB
), 1, wxSOLID
));
732 if(nDirection
== wxEAST
)
733 DrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
734 xDelta
, rect
.GetHeight());
735 else //nDirection == wxWEST
736 DrawRectangle(rect
.GetRight()-x
-xDelta
, rect
.GetTop(),
737 xDelta
, rect
.GetHeight());
740 else // nDirection == wxNORTH || nDirection == wxSOUTH
742 wxInt32 y
= rect
.GetHeight();
743 wxInt32 w
= y
; // height of area to shade
744 wxInt32 yDelta
= w
/255; // height of one shade bend
752 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
754 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
757 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
759 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
762 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
764 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
766 SetPen(wxPen(wxColour(nR
, nG
, nB
), 1, wxSOLID
));
767 if(nDirection
== wxNORTH
)
768 DrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
769 rect
.GetWidth(), yDelta
);
770 else //nDirection == wxSOUTH
771 DrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
,
772 rect
.GetWidth(), yDelta
);
779 void wxDCBase::DoGradientFillConcentric(const wxRect
& rect
,
780 const wxColour
& initialColour
,
781 const wxColour
& destColour
,
782 const wxPoint
& circleCenter
)
784 //save the old pen color
785 wxColour oldPenColour
= m_pen
.GetColour();
787 wxUint8 nR1
= destColour
.Red();
788 wxUint8 nG1
= destColour
.Green();
789 wxUint8 nB1
= destColour
.Blue();
790 wxUint8 nR2
= initialColour
.Red();
791 wxUint8 nG2
= initialColour
.Green();
792 wxUint8 nB2
= initialColour
.Blue();
797 wxInt32 cx
= rect
.GetWidth() / 2;
798 wxInt32 cy
= rect
.GetHeight() / 2;
806 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
807 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
809 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
811 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
813 //get color difference
814 wxInt32 nGradient
= ((nRadius
-
816 pow((double)(x
- cx
- nCircleOffX
), 2) +
817 pow((double)(y
- cy
- nCircleOffY
), 2)
825 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
826 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
827 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
830 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
831 DrawPoint(wxPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop()));
834 //return old pen color
835 m_pen
.SetColour(oldPenColour
);
839 Notes for wxWidgets DrawEllipticArcRot(...)
841 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
842 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
845 All methods are generic, so they can be implemented in wxDCBase.
846 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
847 methods like (WinCE) wxDC::DoDrawArc(...).
849 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
850 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
851 parts) or every column (in steep parts) only one pixel is calculated.
852 Trigonometric calculation (sin, cos, tan, atan) is only done if the
853 starting angle is not equal to the ending angle. The calculation of the
854 pixels is done using simple arithmetic only and should perform not too
855 bad even on devices without floating point processor. I didn't test this yet.
857 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
858 For instance: an ellipse rotated 180 degrees is drawn
859 slightly different from the original.
861 The points are then moved to an array and used to draw a polyline and/or polygon
862 (with center added, the pie).
863 The result looks quite similar to the native ellipse, only e few pixels differ.
865 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
866 slower as DrawEllipse(...), which calls the native API.
867 An rotated ellipse outside the clipping region takes nearly the same time,
868 while an native ellipse outside takes nearly no time to draw.
870 If you draw an arc with this new method, you will see the starting and ending angles
871 are calculated properly.
872 If you use DrawEllipticArc(...), you will see they are only correct for circles
873 and not properly calculated for ellipses.
876 p.lenhard@t-online.de
880 void wxDCBase::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
,
881 wxCoord w
, wxCoord h
,
882 double sa
, double ea
, double angle
)
886 CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea
);
887 Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) );
889 // Add center (for polygon/pie)
890 list
.Append( (wxObject
*) new wxPoint( x
+w
/2, y
+h
/2 ) );
892 // copy list into array and delete list elements
893 int n
= list
.GetCount();
894 wxPoint
*points
= new wxPoint
[n
];
897 for ( node
= list
.GetFirst(); node
; node
= node
->GetNext(), i
++ )
899 wxPoint
*point
= (wxPoint
*)node
->GetData();
900 points
[i
].x
= point
->x
;
901 points
[i
].y
= point
->y
;
905 // first draw the pie without pen, if necessary
906 if( GetBrush() != *wxTRANSPARENT_BRUSH
)
908 wxPen
tempPen( GetPen() );
909 SetPen( *wxTRANSPARENT_PEN
);
910 DoDrawPolygon( n
, points
, 0, 0 );
914 // then draw the arc without brush, if necessary
915 if( GetPen() != *wxTRANSPARENT_PEN
)
918 DoDrawLines( n
-1, points
, 0, 0 );
923 } // DrawEllipticArcRot
925 void wxDCBase::Rotate( wxList
* points
, double angle
, wxPoint center
)
930 double dSinA
= -sin(angle
*2.0*pi
/360.0);
931 double dCosA
= cos(angle
*2.0*pi
/360.0);
932 for ( wxNode
* node
= points
->GetFirst(); node
; node
= node
->GetNext() )
934 wxPoint
* point
= (wxPoint
*)node
->GetData();
936 // transform coordinates, if necessary
937 if( center
.x
) point
->x
-= center
.x
;
938 if( center
.y
) point
->y
-= center
.y
;
940 // calculate rotation, rounding simply by implicit cast to integer
941 int xTemp
= point
->x
* dCosA
- point
->y
* dSinA
;
942 point
->y
= point
->x
* dSinA
+ point
->y
* dCosA
;
945 // back transform coordinates, if necessary
946 if( center
.x
) point
->x
+= center
.x
;
947 if( center
.y
) point
->y
+= center
.y
;
952 void wxDCBase::CalculateEllipticPoints( wxList
* points
,
953 wxCoord xStart
, wxCoord yStart
,
954 wxCoord w
, wxCoord h
,
955 double sa
, double ea
)
966 bool bUseAngles
= false;
972 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
974 if( 2*a
== w
) decrX
= 1;
976 if( 2*b
== h
) decrY
= 1;
978 wxCoord xCenter
= xStart
+ a
;
979 wxCoord yCenter
= yStart
+ b
;
980 // calculate data for start and end, if necessary
984 // normalisation of angles
985 while( sa
<0 ) sa
+= 360;
986 while( ea
<0 ) ea
+= 360;
987 while( sa
>=360 ) sa
-= 360;
988 while( ea
>=360 ) ea
-= 360;
989 // calculate quadrant numbers
990 if( sa
> 270 ) sq
= 3;
991 else if( sa
> 180 ) sq
= 2;
992 else if( sa
> 90 ) sq
= 1;
993 if( ea
> 270 ) eq
= 3;
994 else if( ea
> 180 ) eq
= 2;
995 else if( ea
> 90 ) eq
= 1;
996 sar
= sa
* pi
/ 180.0;
997 ear
= ea
* pi
/ 180.0;
998 // correct angle circle -> ellipse
999 sar
= atan( -a
/(double)b
* tan( sar
) );
1000 if ( sq
== 1 || sq
== 2 ) sar
+= pi
;
1001 ear
= atan( -a
/(double)b
* tan( ear
) );
1002 if ( eq
== 1 || eq
== 2 ) ear
+= pi
;
1003 // coordinates of points
1004 xsa
= xCenter
+ a
* cos( sar
);
1005 if( sq
== 0 || sq
== 3 ) xsa
-= decrX
;
1006 ysa
= yCenter
+ b
* sin( sar
);
1007 if( sq
== 2 || sq
== 3 ) ysa
-= decrY
;
1008 xea
= xCenter
+ a
* cos( ear
);
1009 if( eq
== 0 || eq
== 3 ) xea
-= decrX
;
1010 yea
= yCenter
+ b
* sin( ear
);
1011 if( eq
== 2 || eq
== 3 ) yea
-= decrY
;
1013 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
1015 double c2
= 2.0 / w
;
1024 // Lists for quadrant 1 to 4
1025 wxList pointsarray
[4];
1026 // Calculate points for first quadrant and set in all quadrants
1027 for( x
= 0; x
<= a
; ++x
)
1032 bool bNewPoint
= false;
1033 while( y2
> c1
- c2
* x2
&& y
> 0 )
1039 // old y now to big: set point with old y, old x
1040 if( bNewPoint
&& x
>1)
1043 // remove points on the same line
1044 pointsarray
[0].Insert( (wxObject
*) new wxPoint( xCenter
+ x1
- decrX
, yCenter
- y_old
) );
1045 pointsarray
[1].Append( (wxObject
*) new wxPoint( xCenter
- x1
, yCenter
- y_old
) );
1046 pointsarray
[2].Insert( (wxObject
*) new wxPoint( xCenter
- x1
, yCenter
+ y_old
- decrY
) );
1047 pointsarray
[3].Append( (wxObject
*) new wxPoint( xCenter
+ x1
- decrX
, yCenter
+ y_old
- decrY
) );
1049 } // calculate point
1051 // Starting and/or ending points for the quadrants, first quadrant gets both.
1052 pointsarray
[0].Insert( (wxObject
*) new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1053 pointsarray
[0].Append( (wxObject
*) new wxPoint( xCenter
, yCenter
- b
) );
1054 pointsarray
[1].Append( (wxObject
*) new wxPoint( xCenter
- a
, yCenter
) );
1055 pointsarray
[2].Append( (wxObject
*) new wxPoint( xCenter
, yCenter
+ b
- decrY
) );
1056 pointsarray
[3].Append( (wxObject
*) new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1058 // copy quadrants in original list
1061 // Copy the right part of the points in the lists
1062 // and delete the wxPoints, because they do not leave this method.
1063 points
->Append( (wxObject
*) new wxPoint( xsa
, ysa
) );
1065 bool bStarted
= false;
1066 bool bReady
= false;
1067 bool bForceTurn
= ( sq
== eq
&& sa
> ea
);
1070 for( wxNode
*node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1072 // once: go to starting point in start quadrant
1075 ( (wxPoint
*) node
->GetData() )->x
< xsa
+1 && q
<= 1
1077 ( (wxPoint
*) node
->GetData() )->x
> xsa
-1 && q
>= 2
1084 // copy point, if not at ending point
1087 if( q
!= eq
|| bForceTurn
1089 ( (wxPoint
*) node
->GetData() )->x
> xea
+1 && q
<= 1
1091 ( (wxPoint
*) node
->GetData() )->x
< xea
-1 && q
>= 2
1095 wxPoint
* pPoint
= new wxPoint( *((wxPoint
*) node
->GetData() ) );
1096 points
->Append( (wxObject
*) pPoint
);
1098 else if( q
== eq
&& !bForceTurn
|| ( (wxPoint
*) node
->GetData() )->x
== xea
)
1108 } // while not bReady
1109 points
->Append( (wxObject
*) new wxPoint( xea
, yea
) );
1112 for( q
= 0; q
< 4; ++q
)
1114 for( wxNode
*node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1116 wxPoint
*p
= (wxPoint
*)node
->GetData();
1124 // copy whole ellipse, wxPoints will be deleted outside
1125 for( node
= pointsarray
[0].GetFirst(); node
; node
= node
->GetNext() )
1127 wxObject
*p
= node
->GetData();
1128 points
->Append( p
);
1130 for( node
= pointsarray
[1].GetFirst(); node
; node
= node
->GetNext() )
1132 wxObject
*p
= node
->GetData();
1133 points
->Append( p
);
1135 for( node
= pointsarray
[2].GetFirst(); node
; node
= node
->GetNext() )
1137 wxObject
*p
= node
->GetData();
1138 points
->Append( p
);
1140 for( node
= pointsarray
[3].GetFirst(); node
; node
= node
->GetNext() )
1142 wxObject
*p
= node
->GetData();
1143 points
->Append( p
);
1146 } // CalculateEllipticPoints
1151 // temporary home for wxOverlay
1154 #include "wx/dcclient.h"
1155 #include "wx/dcmemory.h"
1157 #if defined(wxMAC_USE_CORE_GRAPHICS) && wxMAC_USE_CORE_GRAPHICS
1159 #include "wx/mac/private.h"
1160 #include "wx/toplevel.h"
1169 // clears the overlay without restoring the former state
1170 // to be done eg when the window content has been changed and repainted
1173 // returns true if it has been setup
1176 void Init( wxWindowDC
* dc
, int x
, int y
, int width
, int height
);
1178 void BeginDrawing( wxWindowDC
* dc
);
1180 void EndDrawing( wxWindowDC
* dc
);
1182 void Clear( wxWindowDC
* dc
);
1185 OSStatus
CreateOverlayWindow();
1187 void MacGetBounds( Rect
*bounds
);
1189 WindowRef m_overlayWindow
;
1190 WindowRef m_overlayParentWindow
;
1191 CGContextRef m_overlayContext
;
1192 // we store the window in case we would have to issue a Refresh()
1193 wxWindow
* m_window
;
1195 EventHandlerRef m_overlayParentHandler
;
1196 EventHandlerRef m_overlayHandler
;
1198 static pascal OSStatus
OverlayParentWindowEventHandlerProc( EventHandlerCallRef inCallRef
, EventRef inEvent
, void* inUserData
);
1199 static pascal OSStatus
OverlayWindowEventHandlerProc( EventHandlerCallRef inCallRef
, EventRef inEvent
, void* inUserData
);
1207 wxOverlayImpl::wxOverlayImpl()
1210 m_overlayContext
= NULL
;
1211 m_overlayWindow
= NULL
;
1214 wxOverlayImpl::~wxOverlayImpl()
1219 bool wxOverlayImpl::IsOk()
1221 return m_overlayContext
!= NULL
;
1224 pascal OSStatus
wxOverlayImpl::OverlayWindowEventHandlerProc( EventHandlerCallRef
WXUNUSED(inCallRef
), EventRef inEvent
, void* inUserData
)
1226 OSStatus err
= noErr
;
1227 wxOverlayImpl
* self
= (wxOverlayImpl
*) inUserData
;
1229 wxMacCarbonEvent
cEvent(inEvent
) ;
1230 switch( cEvent
.GetClass() )
1232 case kEventClassWindow
:
1233 switch( cEvent
.GetKind() )
1235 case kEventWindowBoundsChanged
:
1244 // as we didn't interfere with the event itself, always return a notHandled
1245 return eventNotHandledErr
;
1248 pascal OSStatus
wxOverlayImpl::OverlayParentWindowEventHandlerProc( EventHandlerCallRef inCallRef
, EventRef inEvent
, void* inUserData
)
1250 OSStatus err
= eventNotHandledErr
;
1251 wxOverlayImpl
* self
= (wxOverlayImpl
*) inUserData
;
1253 wxMacCarbonEvent
cEvent(inEvent
) ;
1254 switch( cEvent
.GetClass() )
1256 case kEventClassWindow
:
1257 switch( cEvent
.GetKind() )
1259 case kEventWindowBoundsChanging
:
1260 case kEventWindowBoundsChanged
:
1262 err
= CallNextEventHandler(inCallRef
,inEvent
);
1264 self
->MacGetBounds(&bounds
);
1265 SetWindowBounds(self
->m_overlayWindow
,kWindowContentRgn
,&bounds
);
1278 void wxOverlayImpl::MacGetBounds( Rect
*bounds
)
1280 wxPoint
origin(0,0);
1281 origin
= m_window
->ClientToScreen( origin
);
1282 bounds
->top
= origin
.y
;
1283 bounds
->left
= origin
.x
;
1284 bounds
->bottom
= origin
.y
+m_y
+m_height
;
1285 bounds
->right
= origin
.x
+m_x
+m_width
;
1288 OSStatus
wxOverlayImpl::CreateOverlayWindow()
1292 WindowAttributes overlayAttributes
= kWindowHideOnSuspendAttribute
| kWindowIgnoreClicksAttribute
;
1294 static EventHandlerUPP overlayWindowEventHandlerUPP
= NULL
;
1295 static EventHandlerUPP overlayParentWindowEventHandlerUPP
= NULL
;
1296 const EventTypeSpec windowEvents
[] =
1298 { kEventClassWindow
, kEventWindowBoundsChanged
},
1301 const EventTypeSpec parentWindowEvents
[] =
1303 { kEventClassWindow
, kEventWindowBoundsChanged
},
1304 { kEventClassWindow
, kEventWindowBoundsChanging
},
1307 if ( overlayWindowEventHandlerUPP
== NULL
)
1308 overlayWindowEventHandlerUPP
= NewEventHandlerUPP( OverlayWindowEventHandlerProc
);
1309 if ( overlayParentWindowEventHandlerUPP
== NULL
)
1311 overlayParentWindowEventHandlerUPP
= NewEventHandlerUPP( OverlayParentWindowEventHandlerProc
);
1313 m_overlayParentWindow
=(WindowRef
) m_window
->MacGetTopLevelWindowRef();
1316 MacGetBounds(&bounds
);
1317 err
= CreateNewWindow( kOverlayWindowClass
, overlayAttributes
, &bounds
, &m_overlayWindow
);
1320 SetWindowGroup( m_overlayWindow
, GetWindowGroup(m_overlayParentWindow
) ); // Put them in the same group so that their window layers are consistent
1321 err
= InstallWindowEventHandler( m_overlayWindow
, overlayWindowEventHandlerUPP
, GetEventTypeCount(windowEvents
), windowEvents
, this, &m_overlayHandler
);
1323 err
= InstallWindowEventHandler( m_overlayParentWindow
, overlayParentWindowEventHandlerUPP
, GetEventTypeCount(parentWindowEvents
), parentWindowEvents
, this, &m_overlayParentHandler
);
1328 void wxOverlayImpl::Init( wxWindowDC
* dc
, int x
, int y
, int width
, int height
)
1330 wxASSERT_MSG( !IsOk() , _("You cannot Init an overlay twice") );
1332 m_window
= dc
->GetWindow();
1338 OSStatus err
= CreateOverlayWindow();
1339 wxASSERT_MSG( err
== noErr
, _("Couldn't create the overlay window") );
1340 ShowWindow(m_overlayWindow
);
1342 err
= QDBeginCGContext(GetWindowPort(m_overlayWindow
), &m_overlayContext
);
1343 CGContextTranslateCTM( m_overlayContext
, 0, m_height
+m_y
);
1344 CGContextScaleCTM( m_overlayContext
, 1, -1 );
1345 wxASSERT_MSG( err
== noErr
, _("Couldn't init the context on the overlay window") );
1348 void wxOverlayImpl::BeginDrawing( wxWindowDC
* dc
)
1350 delete dc
->m_graphicContext
;
1351 dc
->m_graphicContext
= new wxMacCGContext( m_overlayContext
);
1352 // we are right now startin at 0,0 not at the wxWindow's origin, so most of the calculations
1353 // int dc are already corect
1354 // just to make sure :
1355 dc
->m_macLocalOrigin
.x
= 0 ;
1356 dc
->m_macLocalOrigin
.y
= 0 ;
1357 wxSize size
= m_window
->GetSize() ;
1358 dc
->SetClippingRegion( 0 , 0 , size
.x
, size
.y
) ;
1361 void wxOverlayImpl::EndDrawing( wxWindowDC
* dc
)
1365 void wxOverlayImpl::Clear(wxWindowDC
* dc
)
1367 wxASSERT_MSG( IsOk() , _("You cannot Clear an overlay that is not inited") );
1368 delete dc
->m_graphicContext
;
1369 dc
->m_graphicContext
= NULL
;
1374 void wxOverlayImpl::Reset()
1376 if ( m_overlayContext
)
1378 OSStatus err
= QDEndCGContext(GetWindowPort(m_overlayWindow
), &m_overlayContext
);
1379 wxASSERT_MSG( err
== noErr
, _("Couldn't end the context on the overlay window") );
1381 m_overlayContext
= NULL
;
1384 // todo : don't dispose, only hide and reposition on next run
1385 if (m_overlayWindow
)
1387 RemoveEventHandler( m_overlayParentHandler
) ;
1388 m_overlayParentHandler
= NULL
;
1389 RemoveEventHandler( m_overlayHandler
) ;
1390 m_overlayHandler
= NULL
;
1391 DisposeWindow(m_overlayWindow
);
1392 m_overlayWindow
= NULL
;
1409 // clears the overlay without restoring the former state
1410 // to be done eg when the window content has been changed and repainted
1413 // returns true if it has been setup
1416 void Init( wxWindowDC
* dc
, int x
, int y
, int width
, int height
);
1418 void BeginDrawing( wxWindowDC
* dc
);
1420 void EndDrawing( wxWindowDC
* dc
);
1422 void Clear( wxWindowDC
* dc
);
1425 wxBitmap m_bmpSaved
;
1430 wxWindow
* m_window
;
1433 wxOverlayImpl::wxOverlayImpl()
1436 m_x
= m_y
= m_width
= m_height
= 0 ;
1439 wxOverlayImpl::~wxOverlayImpl()
1443 bool wxOverlayImpl::IsOk()
1445 return m_bmpSaved
.Ok() ;
1448 void wxOverlayImpl::Init( wxWindowDC
* dc
, int x
, int y
, int width
, int height
)
1450 #if defined(__WXGTK__)
1451 m_window
= dc
->m_owner
;
1453 m_window
= dc
->GetWindow();
1456 m_bmpSaved
.Create( width
, height
);
1457 dcMem
.SelectObject( m_bmpSaved
);
1462 #if defined(__WXGTK__) && !defined(__WX_DC_BLIT_FIXED__)
1463 wxPoint pt
= dc
->GetDeviceOrigin();
1466 #endif // broken wxGTK wxDC::Blit
1467 dcMem
.Blit(0, 0, m_width
, m_height
,
1469 dcMem
.SelectObject( wxNullBitmap
);
1472 void wxOverlayImpl::Clear(wxWindowDC
* dc
)
1475 dcMem
.SelectObject( m_bmpSaved
);
1476 dc
->Blit( m_x
, m_y
, m_width
, m_height
, &dcMem
, 0 , 0 );
1477 dcMem
.SelectObject( wxNullBitmap
);
1480 void wxOverlayImpl::Reset()
1482 m_bmpSaved
= wxBitmap();
1485 void wxOverlayImpl::BeginDrawing(wxWindowDC
* WXUNUSED(dc
))
1489 void wxOverlayImpl::EndDrawing(wxWindowDC
* WXUNUSED(dc
))
1497 wxOverlay::wxOverlay()
1499 m_impl
= new wxOverlayImpl();
1500 m_inDrawing
= false;
1503 wxOverlay::~wxOverlay()
1508 bool wxOverlay::IsOk()
1510 return m_impl
->IsOk();
1513 void wxOverlay::Init( wxWindowDC
* dc
, int x
, int y
, int width
, int height
)
1515 m_impl
->Init(dc
, x
, y
, width
, height
);
1518 void wxOverlay::BeginDrawing( wxWindowDC
* dc
)
1520 m_impl
->BeginDrawing(dc
);
1521 m_inDrawing
= true ;
1524 void wxOverlay::EndDrawing( wxWindowDC
* dc
)
1526 m_impl
->EndDrawing(dc
);
1527 m_inDrawing
= false ;
1530 void wxOverlay::Clear( wxWindowDC
* dc
)
1535 void wxOverlay::Reset()
1537 wxASSERT_MSG(m_inDrawing
==false,wxT("cannot reset overlay during drawing"));
1543 wxDCOverlay::wxDCOverlay(wxOverlay
&overlay
, wxWindowDC
*dc
, int x
, int y
, int width
, int height
) :
1546 Init(dc
, x
, y
, width
, height
);
1549 wxDCOverlay::wxDCOverlay(wxOverlay
&overlay
, wxWindowDC
*dc
) :
1554 dc
->GetSize(&width
,&height
);
1555 Init(dc
, 0, 0, width
, height
);
1558 wxDCOverlay::~wxDCOverlay()
1560 m_overlay
.EndDrawing(m_dc
);
1563 void wxDCOverlay::Init(wxWindowDC
*dc
, int x
, int y
, int width
, int height
)
1566 if ( !m_overlay
.IsOk() )
1568 m_overlay
.Init(dc
,x
,y
,width
,height
);
1570 m_overlay
.BeginDrawing(dc
);
1573 void wxDCOverlay::Clear()
1575 m_overlay
.Clear(m_dc
);