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"
28 #include "wx/dcbuffer.h" // for IMPLEMENT_DYNAMIC_CLASS
34 // bool wxDCBase::sm_cacheing = false;
36 IMPLEMENT_ABSTRACT_CLASS(wxDCBase
, wxObject
)
38 // ============================================================================
40 // ============================================================================
42 IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC
, wxMemoryDC
)
43 IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC
, wxBufferedDC
)
46 : m_colour(wxColourDisplay())
50 , m_isBBoxValid(false)
51 , m_logicalOriginX(0), m_logicalOriginY(0)
52 , m_deviceOriginX(0), m_deviceOriginY(0)
53 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
54 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
55 , m_userScaleX(1.0), m_userScaleY(1.0)
56 , m_scaleX(1.0), m_scaleY(1.0)
57 , m_signX(1), m_signY(1)
58 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
59 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
60 , m_logicalFunction(wxCOPY
)
61 , m_backgroundMode(wxTRANSPARENT
)
62 , m_mappingMode(wxMM_TEXT
)
65 , m_backgroundBrush(*wxTRANSPARENT_BRUSH
)
66 , m_textForegroundColour(*wxBLACK
)
67 , m_textBackgroundColour(*wxWHITE
)
71 , m_hasCustomPalette(false)
72 #endif // wxUSE_PALETTE
74 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
75 (double)wxGetDisplaySizeMM().GetWidth();
76 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
77 (double)wxGetDisplaySizeMM().GetHeight();
87 #if WXWIN_COMPATIBILITY_2_6
88 void wxDCBase::BeginDrawing()
92 void wxDCBase::EndDrawing()
95 #endif // WXWIN_COMPATIBILITY_2_6
97 #if WXWIN_COMPATIBILITY_2_8
98 // for compatibility with the old code when wxCoord was long everywhere
99 void wxDCBase::GetTextExtent(const wxString
& string
,
102 long *externalLeading
,
103 const wxFont
*theFont
) const
105 wxCoord x2
, y2
, descent2
, externalLeading2
;
106 DoGetTextExtent(string
, &x2
, &y2
,
107 &descent2
, &externalLeading2
,
115 if ( externalLeading
)
116 *externalLeading
= externalLeading2
;
119 void wxDCBase::GetLogicalOrigin(long *x
, long *y
) const
122 DoGetLogicalOrigin(&x2
, &y2
);
129 void wxDCBase::GetDeviceOrigin(long *x
, long *y
) const
132 DoGetDeviceOrigin(&x2
, &y2
);
139 void wxDCBase::GetClippingBox(long *x
, long *y
, long *w
, long *h
) const
142 DoGetClippingBox(&xx
, &yy
, &ww
, &hh
);
148 #endif // WXWIN_COMPATIBILITY_2_8
152 // ----------------------------------------------------------------------------
153 // coordinate conversions and transforms
154 // ----------------------------------------------------------------------------
156 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
158 return wxRound((double)(x
- m_deviceOriginX
- m_deviceLocalOriginX
) / m_scaleX
) * m_signX
+ m_logicalOriginX
;
161 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
163 return wxRound((double)(y
- m_deviceOriginY
- m_deviceLocalOriginY
) / m_scaleY
) * m_signY
+ m_logicalOriginY
;
166 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
168 return wxRound((double)(x
) / m_scaleX
);
171 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
173 return wxRound((double)(y
) / m_scaleY
);
176 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
178 return wxRound((double)(x
- m_logicalOriginX
) * m_scaleX
) * m_signX
+ m_deviceOriginX
+ m_deviceLocalOriginX
;
181 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
183 return wxRound((double)(y
- m_logicalOriginY
) * m_scaleY
) * m_signY
+ m_deviceOriginY
+ m_deviceLocalOriginY
;
186 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
188 return wxRound((double)(x
) * m_scaleX
);
191 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
193 return wxRound((double)(y
) * m_scaleY
);
196 void wxDCBase::ComputeScaleAndOrigin()
198 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
199 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
202 void wxDCBase::SetMapMode( int mode
)
207 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
210 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
213 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
216 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
220 SetLogicalScale( 1.0, 1.0 );
223 m_mappingMode
= mode
;
226 void wxDCBase::SetUserScale( double x
, double y
)
228 // allow negative ? -> no
231 ComputeScaleAndOrigin();
234 void wxDCBase::SetLogicalScale( double x
, double y
)
239 ComputeScaleAndOrigin();
242 void wxDCBase::SetLogicalOrigin( wxCoord x
, wxCoord y
)
244 m_logicalOriginX
= x
* m_signX
;
245 m_logicalOriginY
= y
* m_signY
;
246 ComputeScaleAndOrigin();
249 void wxDCBase::SetDeviceOrigin( wxCoord x
, wxCoord y
)
253 ComputeScaleAndOrigin();
256 void wxDCBase::SetDeviceLocalOrigin( wxCoord x
, wxCoord y
)
258 m_deviceLocalOriginX
= x
;
259 m_deviceLocalOriginY
= y
;
260 ComputeScaleAndOrigin();
263 void wxDCBase::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
265 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
266 m_signX
= (xLeftRight
? 1 : -1);
267 m_signY
= (yBottomUp
? -1 : 1);
268 ComputeScaleAndOrigin();
271 // ----------------------------------------------------------------------------
273 // ----------------------------------------------------------------------------
275 void wxDCBase::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
276 wxCoord width
, wxCoord height
)
278 wxCHECK_RET( Ok(), wxT("invalid window dc") );
280 wxCoord x2
= x1
+ width
,
283 // the pen width is calibrated to give 3 for width == height == 10
284 wxDCPenChanger
pen((wxDC
&)*this,
285 wxPen(GetTextForeground(), (width
+ height
+ 1)/7));
287 // we're drawing a scaled version of wx/generic/tick.xpm here
288 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
289 y3
= y1
+ height
/ 2; // y of the left tick branch
290 DoDrawLine(x1
, y3
, x3
, y2
);
291 DoDrawLine(x3
, y2
, x2
, y1
);
293 CalcBoundingBox(x1
, y1
);
294 CalcBoundingBox(x2
, y2
);
297 // ----------------------------------------------------------------------------
298 // stubs for functions not implemented in all ports
299 // ----------------------------------------------------------------------------
302 wxDCBase::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
303 wxCoord dstWidth
, wxCoord dstHeight
,
305 wxCoord xsrc
, wxCoord ysrc
,
306 wxCoord srcWidth
, wxCoord srcHeight
,
312 wxCHECK_MSG( srcWidth
&& srcHeight
&& dstWidth
&& dstHeight
, false,
313 _T("invalid blit size") );
315 // emulate the stretching by modifying the DC scale
316 double xscale
= (double)srcWidth
/dstWidth
,
317 yscale
= (double)srcHeight
/dstHeight
;
319 double xscaleOld
, yscaleOld
;
320 GetUserScale(&xscaleOld
, &yscaleOld
);
321 SetUserScale(xscaleOld
/xscale
, yscaleOld
/yscale
);
323 bool rc
= DoBlit(wxCoord(xdest
*xscale
), wxCoord(ydest
*yscale
),
324 wxCoord(dstWidth
*xscale
), wxCoord(dstHeight
*yscale
),
326 xsrc
, ysrc
, rop
, useMask
, xsrcMask
, ysrcMask
);
328 SetUserScale(xscaleOld
, yscaleOld
);
333 // ----------------------------------------------------------------------------
335 // ----------------------------------------------------------------------------
337 void wxDCBase::DrawLines(const wxList
*list
, wxCoord xoffset
, wxCoord yoffset
)
339 int n
= list
->GetCount();
340 wxPoint
*points
= new wxPoint
[n
];
343 for ( wxList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
345 wxPoint
*point
= (wxPoint
*)node
->GetData();
346 points
[i
].x
= point
->x
;
347 points
[i
].y
= point
->y
;
350 DoDrawLines(n
, points
, xoffset
, yoffset
);
356 void wxDCBase::DrawPolygon(const wxList
*list
,
357 wxCoord xoffset
, wxCoord yoffset
,
360 int n
= list
->GetCount();
361 wxPoint
*points
= new wxPoint
[n
];
364 for ( wxList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
366 wxPoint
*point
= (wxPoint
*)node
->GetData();
367 points
[i
].x
= point
->x
;
368 points
[i
].y
= point
->y
;
371 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
377 wxDCBase::DoDrawPolyPolygon(int n
,
380 wxCoord xoffset
, wxCoord yoffset
,
385 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
393 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
398 pts
= new wxPoint
[j
+n
-1];
399 for (i
= 0; i
< j
; i
++)
401 for (i
= 2; i
<= n
; i
++)
403 lastOfs
-= count
[n
-i
];
404 pts
[j
++] = pts
[lastOfs
];
408 SetPen(wxPen(*wxBLACK
, 0, wxTRANSPARENT
));
409 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
411 for (i
= j
= 0; i
< n
; i
++)
413 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
419 // ----------------------------------------------------------------------------
421 // ----------------------------------------------------------------------------
425 // TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?)
426 void wxDCBase::DrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
)
430 wxPoint
*point1
= new wxPoint
;
431 point1
->x
= x1
; point1
->y
= y1
;
432 point_list
.Append((wxObject
*)point1
);
434 wxPoint
*point2
= new wxPoint
;
435 point2
->x
= x2
; point2
->y
= y2
;
436 point_list
.Append((wxObject
*)point2
);
438 wxPoint
*point3
= new wxPoint
;
439 point3
->x
= x3
; point3
->y
= y3
;
440 point_list
.Append((wxObject
*)point3
);
442 DrawSpline(&point_list
);
444 for( wxList::compatibility_iterator node
= point_list
.GetFirst(); node
; node
= node
->GetNext() )
446 wxPoint
*p
= (wxPoint
*)node
->GetData();
451 void wxDCBase::DrawSpline(int n
, wxPoint points
[])
454 for (int i
=0; i
< n
; i
++)
456 list
.Append((wxObject
*)&points
[i
]);
462 // ----------------------------------- spline code ----------------------------------------
464 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
465 double a3
, double b3
, double a4
, double b4
);
466 void wx_clear_stack();
467 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
468 double *y3
, double *x4
, double *y4
);
469 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
470 double x4
, double y4
);
471 static bool wx_spline_add_point(double x
, double y
);
472 static void wx_spline_draw_point_array(wxDCBase
*dc
);
474 wxList wx_spline_point_list
;
476 #define half(z1, z2) ((z1+z2)/2.0)
479 /* iterative version */
481 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
484 register double xmid
, ymid
;
485 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
488 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
490 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
491 xmid
= (double)half(x2
, x3
);
492 ymid
= (double)half(y2
, y3
);
493 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
494 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
495 wx_spline_add_point( x1
, y1
);
496 wx_spline_add_point( xmid
, ymid
);
498 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
499 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
500 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
501 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
506 /* utilities used by spline drawing routines */
508 typedef struct wx_spline_stack_struct
{
509 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
512 #define SPLINE_STACK_DEPTH 20
513 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
514 static Stack
*wx_stack_top
;
515 static int wx_stack_count
;
517 void wx_clear_stack()
519 wx_stack_top
= wx_spline_stack
;
523 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
525 wx_stack_top
->x1
= x1
;
526 wx_stack_top
->y1
= y1
;
527 wx_stack_top
->x2
= x2
;
528 wx_stack_top
->y2
= y2
;
529 wx_stack_top
->x3
= x3
;
530 wx_stack_top
->y3
= y3
;
531 wx_stack_top
->x4
= x4
;
532 wx_stack_top
->y4
= y4
;
537 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
538 double *x3
, double *y3
, double *x4
, double *y4
)
540 if (wx_stack_count
== 0)
544 *x1
= wx_stack_top
->x1
;
545 *y1
= wx_stack_top
->y1
;
546 *x2
= wx_stack_top
->x2
;
547 *y2
= wx_stack_top
->y2
;
548 *x3
= wx_stack_top
->x3
;
549 *y3
= wx_stack_top
->y3
;
550 *x4
= wx_stack_top
->x4
;
551 *y4
= wx_stack_top
->y4
;
555 static bool wx_spline_add_point(double x
, double y
)
557 wxPoint
*point
= new wxPoint
;
560 wx_spline_point_list
.Append((wxObject
*)point
);
564 static void wx_spline_draw_point_array(wxDCBase
*dc
)
566 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
567 wxList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
570 wxPoint
*point
= (wxPoint
*)node
->GetData();
572 wx_spline_point_list
.Erase(node
);
573 node
= wx_spline_point_list
.GetFirst();
577 void wxDCBase::DoDrawSpline( wxList
*points
)
579 wxCHECK_RET( Ok(), wxT("invalid window dc") );
582 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
583 double x1
, y1
, x2
, y2
;
585 wxList::compatibility_iterator node
= points
->GetFirst();
590 p
= (wxPoint
*)node
->GetData();
595 node
= node
->GetNext();
596 p
= (wxPoint
*)node
->GetData();
600 cx1
= (double)((x1
+ x2
) / 2);
601 cy1
= (double)((y1
+ y2
) / 2);
602 cx2
= (double)((cx1
+ x2
) / 2);
603 cy2
= (double)((cy1
+ y2
) / 2);
605 wx_spline_add_point(x1
, y1
);
607 while ((node
= node
->GetNext())
613 p
= (wxPoint
*)node
->GetData();
618 cx4
= (double)(x1
+ x2
) / 2;
619 cy4
= (double)(y1
+ y2
) / 2;
620 cx3
= (double)(x1
+ cx4
) / 2;
621 cy3
= (double)(y1
+ cy4
) / 2;
623 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
627 cx2
= (double)(cx1
+ x2
) / 2;
628 cy2
= (double)(cy1
+ y2
) / 2;
631 wx_spline_add_point( cx1
, cy1
);
632 wx_spline_add_point( x2
, y2
);
634 wx_spline_draw_point_array( this );
637 #endif // wxUSE_SPLINES
639 // ----------------------------------------------------------------------------
640 // Partial Text Extents
641 // ----------------------------------------------------------------------------
644 // Each element of the widths array will be the width of the string up to and
645 // including the corresponding character in text. This is the generic
646 // implementation, the port-specific classes should do this with native APIs
647 // if available and if faster. Note: pango_layout_index_to_pos is much slower
648 // than calling GetTextExtent!!
655 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
656 ~FontWidthCache() { delete []m_widths
; }
661 m_widths
= new int[FWC_SIZE
];
663 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
671 static FontWidthCache s_fontWidthCache
;
673 bool wxDCBase::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
677 const size_t len
= text
.length();
681 // reset the cache if font or horizontal scale have changed
682 if ( !s_fontWidthCache
.m_widths
||
683 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
684 (s_fontWidthCache
.m_font
!= GetFont()) )
686 s_fontWidthCache
.Reset();
687 s_fontWidthCache
.m_font
= GetFont();
688 s_fontWidthCache
.m_scaleX
= m_scaleX
;
691 // Calculate the position of each character based on the widths of
692 // the previous characters
694 for ( size_t i
= 0; i
< len
; i
++ )
696 const wxChar c
= text
[i
];
697 unsigned int c_int
= (unsigned int)c
;
699 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
701 w
= s_fontWidthCache
.m_widths
[c_int
];
705 GetTextExtent(c
, &w
, &h
);
706 if (c_int
< FWC_SIZE
)
707 s_fontWidthCache
.m_widths
[c_int
] = w
;
711 widths
[i
] = totalWidth
;
718 // ----------------------------------------------------------------------------
719 // enhanced text drawing
720 // ----------------------------------------------------------------------------
722 void wxDCBase::GetMultiLineTextExtent(const wxString
& text
,
726 const wxFont
*font
) const
728 wxCoord widthTextMax
= 0, widthLine
,
729 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
732 for ( const wxChar
*pc
= text
; ; pc
++ )
734 if ( *pc
== _T('\n') || *pc
== _T('\0') )
736 if ( curLine
.empty() )
738 // we can't use GetTextExtent - it will return 0 for both width
739 // and height and an empty line should count in height
742 // assume that this line has the same height as the previous
744 if ( !heightLineDefault
)
745 heightLineDefault
= heightLine
;
747 if ( !heightLineDefault
)
749 // but we don't know it yet - choose something reasonable
750 GetTextExtent(_T("W"), NULL
, &heightLineDefault
,
754 heightTextTotal
+= heightLineDefault
;
758 GetTextExtent(curLine
, &widthLine
, &heightLine
,
760 if ( widthLine
> widthTextMax
)
761 widthTextMax
= widthLine
;
762 heightTextTotal
+= heightLine
;
765 if ( *pc
== _T('\n') )
784 *y
= heightTextTotal
;
789 void wxDCBase::DrawLabel(const wxString
& text
,
790 const wxBitmap
& bitmap
,
794 wxRect
*rectBounding
)
796 // find the text position
797 wxCoord widthText
, heightText
, heightLine
;
798 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
800 wxCoord width
, height
;
803 width
= widthText
+ bitmap
.GetWidth();
804 height
= bitmap
.GetHeight();
813 if ( alignment
& wxALIGN_RIGHT
)
815 x
= rect
.GetRight() - width
;
817 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
819 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
821 else // alignment & wxALIGN_LEFT
826 if ( alignment
& wxALIGN_BOTTOM
)
828 y
= rect
.GetBottom() - height
;
830 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
832 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
834 else // alignment & wxALIGN_TOP
839 // draw the bitmap first
845 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
847 wxCoord offset
= bitmap
.GetWidth() + 4;
851 y
+= (height
- heightText
) / 2;
854 // we will draw the underscore under the accel char later
855 wxCoord startUnderscore
= 0,
859 // split the string into lines and draw each of them separately
861 for ( wxString::const_iterator pc
= text
.begin(); ; ++pc
)
863 if ( *pc
== _T('\n') || pc
== text
.end() )
865 int xRealStart
= x
; // init it here to avoid compielr warnings
867 if ( !curLine
.empty() )
869 // NB: can't test for !(alignment & wxALIGN_LEFT) because
871 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
874 GetTextExtent(curLine
, &widthLine
, NULL
);
876 if ( alignment
& wxALIGN_RIGHT
)
878 xRealStart
+= width
- widthLine
;
880 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
882 xRealStart
+= (width
- widthLine
) / 2;
885 //else: left aligned, nothing to do
887 DrawText(curLine
, xRealStart
, y
);
892 // do we have underscore in this line? we can check yUnderscore
893 // because it is set below to just y + heightLine if we do
894 if ( y
== yUnderscore
)
896 // adjust the horz positions to account for the shift
897 startUnderscore
+= xRealStart
;
898 endUnderscore
+= xRealStart
;
901 if ( pc
== text
.end() )
906 else // not end of line
908 if ( pc
- text
.begin() == indexAccel
)
910 // remeber to draw underscore here
911 GetTextExtent(curLine
, &startUnderscore
, NULL
);
913 GetTextExtent(curLine
, &endUnderscore
, NULL
);
915 yUnderscore
= y
+ heightLine
;
924 // draw the underscore if found
925 if ( startUnderscore
!= endUnderscore
)
927 // it should be of the same colour as text
928 SetPen(wxPen(GetTextForeground(), 0, wxSOLID
));
932 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
935 // return bounding rect if requested
938 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
941 CalcBoundingBox(x0
, y0
);
942 CalcBoundingBox(x0
+ width0
, y0
+ height
);
946 void wxDCBase::DoGradientFillLinear(const wxRect
& rect
,
947 const wxColour
& initialColour
,
948 const wxColour
& destColour
,
949 wxDirection nDirection
)
952 wxPen oldPen
= m_pen
;
953 wxBrush oldBrush
= m_brush
;
955 wxUint8 nR1
= initialColour
.Red();
956 wxUint8 nG1
= initialColour
.Green();
957 wxUint8 nB1
= initialColour
.Blue();
958 wxUint8 nR2
= destColour
.Red();
959 wxUint8 nG2
= destColour
.Green();
960 wxUint8 nB2
= destColour
.Blue();
963 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
965 wxInt32 x
= rect
.GetWidth();
966 wxInt32 w
= x
; // width of area to shade
967 wxInt32 xDelta
= w
/256; // height of one shade bend
975 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
977 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
980 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
982 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
985 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
987 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
989 wxColour
colour(nR
,nG
,nB
);
990 SetPen(wxPen(colour
, 1, wxSOLID
));
991 SetBrush(wxBrush(colour
));
992 if(nDirection
== wxEAST
)
993 DrawRectangle(rect
.GetRight()-x
-xDelta
, rect
.GetTop(),
994 xDelta
, rect
.GetHeight());
995 else //nDirection == wxWEST
996 DrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
997 xDelta
, rect
.GetHeight());
1000 else // nDirection == wxNORTH || nDirection == wxSOUTH
1002 wxInt32 y
= rect
.GetHeight();
1003 wxInt32 w
= y
; // height of area to shade
1004 wxInt32 yDelta
= w
/255; // height of one shade bend
1012 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
1014 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
1017 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
1019 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
1022 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
1024 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
1026 wxColour
colour(nR
,nG
,nB
);
1027 SetPen(wxPen(colour
, 1, wxSOLID
));
1028 SetBrush(wxBrush(colour
));
1029 if(nDirection
== wxNORTH
)
1030 DrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
1031 rect
.GetWidth(), yDelta
);
1032 else //nDirection == wxSOUTH
1033 DrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
,
1034 rect
.GetWidth(), yDelta
);
1042 void wxDCBase::DoGradientFillConcentric(const wxRect
& rect
,
1043 const wxColour
& initialColour
,
1044 const wxColour
& destColour
,
1045 const wxPoint
& circleCenter
)
1047 //save the old pen color
1048 wxColour oldPenColour
= m_pen
.GetColour();
1050 wxUint8 nR1
= destColour
.Red();
1051 wxUint8 nG1
= destColour
.Green();
1052 wxUint8 nB1
= destColour
.Blue();
1053 wxUint8 nR2
= initialColour
.Red();
1054 wxUint8 nG2
= initialColour
.Green();
1055 wxUint8 nB2
= initialColour
.Blue();
1060 wxInt32 cx
= rect
.GetWidth() / 2;
1061 wxInt32 cy
= rect
.GetHeight() / 2;
1069 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
1070 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
1072 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
1074 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
1076 //get color difference
1077 wxInt32 nGradient
= ((nRadius
-
1079 pow((double)(x
- cx
- nCircleOffX
), 2) +
1080 pow((double)(y
- cy
- nCircleOffY
), 2)
1081 )) * 100) / nRadius
;
1083 //normalize Gradient
1088 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
1089 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
1090 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
1093 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
1094 DrawPoint(wxPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop()));
1097 //return old pen color
1098 m_pen
.SetColour(oldPenColour
);
1102 Notes for wxWidgets DrawEllipticArcRot(...)
1104 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
1105 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
1108 All methods are generic, so they can be implemented in wxDCBase.
1109 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
1110 methods like (WinCE) wxDC::DoDrawArc(...).
1112 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
1113 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
1114 parts) or every column (in steep parts) only one pixel is calculated.
1115 Trigonometric calculation (sin, cos, tan, atan) is only done if the
1116 starting angle is not equal to the ending angle. The calculation of the
1117 pixels is done using simple arithmetic only and should perform not too
1118 bad even on devices without floating point processor. I didn't test this yet.
1120 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
1121 For instance: an ellipse rotated 180 degrees is drawn
1122 slightly different from the original.
1124 The points are then moved to an array and used to draw a polyline and/or polygon
1125 (with center added, the pie).
1126 The result looks quite similar to the native ellipse, only e few pixels differ.
1128 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
1129 slower as DrawEllipse(...), which calls the native API.
1130 An rotated ellipse outside the clipping region takes nearly the same time,
1131 while an native ellipse outside takes nearly no time to draw.
1133 If you draw an arc with this new method, you will see the starting and ending angles
1134 are calculated properly.
1135 If you use DrawEllipticArc(...), you will see they are only correct for circles
1136 and not properly calculated for ellipses.
1139 p.lenhard@t-online.de
1143 void wxDCBase::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
,
1144 wxCoord w
, wxCoord h
,
1145 double sa
, double ea
, double angle
)
1149 CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea
);
1150 Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) );
1152 // Add center (for polygon/pie)
1153 list
.Append( (wxObject
*) new wxPoint( x
+w
/2, y
+h
/2 ) );
1155 // copy list into array and delete list elements
1156 int n
= list
.GetCount();
1157 wxPoint
*points
= new wxPoint
[n
];
1160 for ( node
= list
.GetFirst(); node
; node
= node
->GetNext(), i
++ )
1162 wxPoint
*point
= (wxPoint
*)node
->GetData();
1163 points
[i
].x
= point
->x
;
1164 points
[i
].y
= point
->y
;
1168 // first draw the pie without pen, if necessary
1169 if( GetBrush() != *wxTRANSPARENT_BRUSH
)
1171 wxPen
tempPen( GetPen() );
1172 SetPen( *wxTRANSPARENT_PEN
);
1173 DoDrawPolygon( n
, points
, 0, 0 );
1177 // then draw the arc without brush, if necessary
1178 if( GetPen() != *wxTRANSPARENT_PEN
)
1181 DoDrawLines( n
-1, points
, 0, 0 );
1186 } // DrawEllipticArcRot
1188 void wxDCBase::Rotate( wxList
* points
, double angle
, wxPoint center
)
1193 double dSinA
= -sin(angle
*2.0*pi
/360.0);
1194 double dCosA
= cos(angle
*2.0*pi
/360.0);
1195 for ( wxNode
* node
= points
->GetFirst(); node
; node
= node
->GetNext() )
1197 wxPoint
* point
= (wxPoint
*)node
->GetData();
1199 // transform coordinates, if necessary
1200 if( center
.x
) point
->x
-= center
.x
;
1201 if( center
.y
) point
->y
-= center
.y
;
1203 // calculate rotation, rounding simply by implicit cast to integer
1204 int xTemp
= point
->x
* dCosA
- point
->y
* dSinA
;
1205 point
->y
= point
->x
* dSinA
+ point
->y
* dCosA
;
1208 // back transform coordinates, if necessary
1209 if( center
.x
) point
->x
+= center
.x
;
1210 if( center
.y
) point
->y
+= center
.y
;
1215 void wxDCBase::CalculateEllipticPoints( wxList
* points
,
1216 wxCoord xStart
, wxCoord yStart
,
1217 wxCoord w
, wxCoord h
,
1218 double sa
, double ea
)
1229 bool bUseAngles
= false;
1235 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
1237 if( 2*a
== w
) decrX
= 1;
1239 if( 2*b
== h
) decrY
= 1;
1241 wxCoord xCenter
= xStart
+ a
;
1242 wxCoord yCenter
= yStart
+ b
;
1243 // calculate data for start and end, if necessary
1247 // normalisation of angles
1248 while( sa
<0 ) sa
+= 360;
1249 while( ea
<0 ) ea
+= 360;
1250 while( sa
>=360 ) sa
-= 360;
1251 while( ea
>=360 ) ea
-= 360;
1252 // calculate quadrant numbers
1253 if( sa
> 270 ) sq
= 3;
1254 else if( sa
> 180 ) sq
= 2;
1255 else if( sa
> 90 ) sq
= 1;
1256 if( ea
> 270 ) eq
= 3;
1257 else if( ea
> 180 ) eq
= 2;
1258 else if( ea
> 90 ) eq
= 1;
1259 sar
= sa
* pi
/ 180.0;
1260 ear
= ea
* pi
/ 180.0;
1261 // correct angle circle -> ellipse
1262 sar
= atan( -a
/(double)b
* tan( sar
) );
1263 if ( sq
== 1 || sq
== 2 ) sar
+= pi
;
1264 ear
= atan( -a
/(double)b
* tan( ear
) );
1265 if ( eq
== 1 || eq
== 2 ) ear
+= pi
;
1266 // coordinates of points
1267 xsa
= xCenter
+ a
* cos( sar
);
1268 if( sq
== 0 || sq
== 3 ) xsa
-= decrX
;
1269 ysa
= yCenter
+ b
* sin( sar
);
1270 if( sq
== 2 || sq
== 3 ) ysa
-= decrY
;
1271 xea
= xCenter
+ a
* cos( ear
);
1272 if( eq
== 0 || eq
== 3 ) xea
-= decrX
;
1273 yea
= yCenter
+ b
* sin( ear
);
1274 if( eq
== 2 || eq
== 3 ) yea
-= decrY
;
1276 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
1278 double c2
= 2.0 / w
;
1287 // Lists for quadrant 1 to 4
1288 wxList pointsarray
[4];
1289 // Calculate points for first quadrant and set in all quadrants
1290 for( x
= 0; x
<= a
; ++x
)
1295 bool bNewPoint
= false;
1296 while( y2
> c1
- c2
* x2
&& y
> 0 )
1302 // old y now to big: set point with old y, old x
1303 if( bNewPoint
&& x
>1)
1306 // remove points on the same line
1307 pointsarray
[0].Insert( (wxObject
*) new wxPoint( xCenter
+ x1
- decrX
, yCenter
- y_old
) );
1308 pointsarray
[1].Append( (wxObject
*) new wxPoint( xCenter
- x1
, yCenter
- y_old
) );
1309 pointsarray
[2].Insert( (wxObject
*) new wxPoint( xCenter
- x1
, yCenter
+ y_old
- decrY
) );
1310 pointsarray
[3].Append( (wxObject
*) new wxPoint( xCenter
+ x1
- decrX
, yCenter
+ y_old
- decrY
) );
1312 } // calculate point
1314 // Starting and/or ending points for the quadrants, first quadrant gets both.
1315 pointsarray
[0].Insert( (wxObject
*) new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1316 pointsarray
[0].Append( (wxObject
*) new wxPoint( xCenter
, yCenter
- b
) );
1317 pointsarray
[1].Append( (wxObject
*) new wxPoint( xCenter
- a
, yCenter
) );
1318 pointsarray
[2].Append( (wxObject
*) new wxPoint( xCenter
, yCenter
+ b
- decrY
) );
1319 pointsarray
[3].Append( (wxObject
*) new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1321 // copy quadrants in original list
1324 // Copy the right part of the points in the lists
1325 // and delete the wxPoints, because they do not leave this method.
1326 points
->Append( (wxObject
*) new wxPoint( xsa
, ysa
) );
1328 bool bStarted
= false;
1329 bool bReady
= false;
1330 bool bForceTurn
= ( sq
== eq
&& sa
> ea
);
1333 for( wxNode
*node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1335 // once: go to starting point in start quadrant
1338 ( (wxPoint
*) node
->GetData() )->x
< xsa
+1 && q
<= 1
1340 ( (wxPoint
*) node
->GetData() )->x
> xsa
-1 && q
>= 2
1347 // copy point, if not at ending point
1350 if( q
!= eq
|| bForceTurn
1352 ( (wxPoint
*) node
->GetData() )->x
> xea
+1 && q
<= 1
1354 ( (wxPoint
*) node
->GetData() )->x
< xea
-1 && q
>= 2
1358 wxPoint
* pPoint
= new wxPoint( *((wxPoint
*) node
->GetData() ) );
1359 points
->Append( (wxObject
*) pPoint
);
1361 else if( q
== eq
&& !bForceTurn
|| ( (wxPoint
*) node
->GetData() )->x
== xea
)
1371 } // while not bReady
1372 points
->Append( (wxObject
*) new wxPoint( xea
, yea
) );
1375 for( q
= 0; q
< 4; ++q
)
1377 for( wxNode
*node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1379 wxPoint
*p
= (wxPoint
*)node
->GetData();
1387 // copy whole ellipse, wxPoints will be deleted outside
1388 for( node
= pointsarray
[0].GetFirst(); node
; node
= node
->GetNext() )
1390 wxObject
*p
= node
->GetData();
1391 points
->Append( p
);
1393 for( node
= pointsarray
[1].GetFirst(); node
; node
= node
->GetNext() )
1395 wxObject
*p
= node
->GetData();
1396 points
->Append( p
);
1398 for( node
= pointsarray
[2].GetFirst(); node
; node
= node
->GetNext() )
1400 wxObject
*p
= node
->GetData();
1401 points
->Append( p
);
1403 for( node
= pointsarray
[3].GetFirst(); node
; node
= node
->GetNext() )
1405 wxObject
*p
= node
->GetData();
1406 points
->Append( p
);
1409 } // CalculateEllipticPoints
1411 #endif // __WXWINCE__