]>
Commit | Line | Data |
---|---|---|
50581042 SC |
1 | ///////////////////////////////////////////////////////////////////////////// |
2 | // Name: src/common/graphcmn.cpp | |
3 | // Purpose: graphics context methods common to all platforms | |
4 | // Author: Stefan Csomor | |
5 | // Modified by: | |
6 | // Created: | |
7 | // RCS-ID: $Id$ | |
8 | // Copyright: (c) Stefan Csomor | |
9 | // Licence: wxWindows licence | |
10 | ///////////////////////////////////////////////////////////////////////////// | |
11 | ||
50581042 SC |
12 | // For compilers that support precompilation, includes "wx.h". |
13 | #include "wx/wxprec.h" | |
14 | ||
15 | #if defined(__BORLANDC__) | |
16 | #pragma hdrstop | |
17 | #endif | |
18 | ||
9fd707a5 PC |
19 | #if wxUSE_GRAPHICS_CONTEXT |
20 | ||
50581042 SC |
21 | #include "wx/graphics.h" |
22 | ||
539872ae SC |
23 | #ifndef WX_PRECOMP |
24 | #include "wx/icon.h" | |
25 | #include "wx/bitmap.h" | |
26 | #include "wx/dcmemory.h" | |
9fd707a5 | 27 | #include "wx/region.h" |
539872ae SC |
28 | #endif |
29 | ||
2f34cf60 RD |
30 | #if !defined(wxMAC_USE_CORE_GRAPHICS_BLEND_MODES) |
31 | #define wxMAC_USE_CORE_GRAPHICS_BLEND_MODES 0 | |
32 | #endif | |
33 | ||
d94228a2 SC |
34 | //----------------------------------------------------------------------------- |
35 | // constants | |
36 | //----------------------------------------------------------------------------- | |
37 | ||
9fd707a5 | 38 | static const double RAD2DEG = 180.0 / M_PI; |
d94228a2 SC |
39 | |
40 | //----------------------------------------------------------------------------- | |
41 | // Local functions | |
42 | //----------------------------------------------------------------------------- | |
43 | ||
d94228a2 SC |
44 | static inline double DegToRad(double deg) |
45 | { | |
46 | return (deg * M_PI) / 180.0; | |
47 | } | |
d94228a2 | 48 | |
9fd707a5 | 49 | //----------------------------------------------------------------------------- |
d94228a2 | 50 | |
facbe363 SC |
51 | IMPLEMENT_DYNAMIC_CLASS(wxGraphicsObject, wxObject) |
52 | ||
53 | IMPLEMENT_ABSTRACT_CLASS(wxGraphicsRenderer, wxObject) | |
54 | ||
55 | IMPLEMENT_ABSTRACT_CLASS(wxGraphicsMatrix, wxGraphicsObject) | |
56 | ||
57 | IMPLEMENT_ABSTRACT_CLASS(wxGraphicsPath, wxGraphicsObject) | |
58 | ||
59 | IMPLEMENT_ABSTRACT_CLASS(wxGraphicsPen, wxGraphicsObject) | |
60 | ||
61 | IMPLEMENT_ABSTRACT_CLASS(wxGraphicsBrush, wxGraphicsObject) | |
62 | ||
63 | IMPLEMENT_ABSTRACT_CLASS(wxGraphicsFont, wxGraphicsObject) | |
8ddf8e82 | 64 | |
50581042 SC |
65 | wxPoint2DDouble wxGraphicsPath::GetCurrentPoint() |
66 | { | |
a2d6d210 | 67 | wxDouble x,y; |
50581042 SC |
68 | GetCurrentPoint(x,y); |
69 | return wxPoint2DDouble(x,y); | |
70 | } | |
71 | ||
72 | void wxGraphicsPath::MoveToPoint( const wxPoint2DDouble& p) | |
73 | { | |
74 | MoveToPoint( p.m_x , p.m_y); | |
75 | } | |
76 | ||
77 | void wxGraphicsPath::AddLineToPoint( const wxPoint2DDouble& p) | |
78 | { | |
79 | AddLineToPoint( p.m_x , p.m_y); | |
80 | } | |
81 | ||
82 | void wxGraphicsPath::AddCurveToPoint( const wxPoint2DDouble& c1, const wxPoint2DDouble& c2, const wxPoint2DDouble& e) | |
83 | { | |
84 | AddCurveToPoint(c1.m_x, c1.m_y, c2.m_x, c2.m_y, e.m_x, e.m_y); | |
85 | } | |
86 | ||
87 | void wxGraphicsPath::AddArc( const wxPoint2DDouble& c, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise) | |
88 | { | |
89 | AddArc(c.m_x, c.m_y, r, startAngle, endAngle, clockwise); | |
90 | } | |
91 | ||
facbe363 SC |
92 | wxRect2DDouble wxGraphicsPath::GetBox() |
93 | { | |
94 | wxDouble x,y,w,h; | |
95 | GetBox(&x,&y,&w,&h); | |
96 | return wxRect2DDouble( x,y,w,h ); | |
97 | } | |
98 | ||
50581042 SC |
99 | // |
100 | // Emulations | |
101 | // | |
102 | ||
103 | void wxGraphicsPath::AddQuadCurveToPoint( wxDouble cx, wxDouble cy, wxDouble x, wxDouble y ) | |
104 | { | |
105 | // calculate using degree elevation to a cubic bezier | |
a2d6d210 VZ |
106 | wxPoint2DDouble c1; |
107 | wxPoint2DDouble c2; | |
50581042 | 108 | |
a2d6d210 | 109 | wxPoint2DDouble start = GetCurrentPoint(); |
50581042 SC |
110 | wxPoint2DDouble end(x,y); |
111 | wxPoint2DDouble c(cx,cy); | |
5ce3abfb | 112 | c1 = wxDouble(1/3.0) * start + wxDouble(2/3.0) * c; |
a2d6d210 | 113 | c2 = wxDouble(2/3.0) * c + wxDouble(1/3.0) * end; |
50581042 SC |
114 | AddCurveToPoint(c1.m_x,c1.m_y,c2.m_x,c2.m_y,x,y); |
115 | } | |
116 | ||
117 | void wxGraphicsPath::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) | |
118 | { | |
119 | MoveToPoint(x,y); | |
120 | AddLineToPoint(x,y+h); | |
121 | AddLineToPoint(x+w,y+h); | |
122 | AddLineToPoint(x+w,y); | |
123 | CloseSubpath(); | |
124 | } | |
125 | ||
126 | void wxGraphicsPath::AddCircle( wxDouble x, wxDouble y, wxDouble r ) | |
127 | { | |
128 | MoveToPoint(x+r,y); | |
129 | AddArc( x,y,r,0,2*M_PI,false); | |
130 | CloseSubpath(); | |
131 | } | |
132 | ||
59720690 SC |
133 | void wxGraphicsPath::AddEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h) |
134 | { | |
135 | wxDouble rw = w/2; | |
136 | wxDouble rh = h/2; | |
137 | wxDouble xc = x + rw; | |
138 | wxDouble yc = y + rh; | |
139 | wxGraphicsMatrix* m = GetRenderer()->CreateMatrix(); | |
140 | m->Translate(xc,yc); | |
141 | m->Scale(rw/rh,1.0); | |
142 | wxGraphicsPath* p = GetRenderer()->CreatePath(); | |
143 | p->AddCircle(0,0,rh); | |
144 | p->Transform(m); | |
145 | AddPath(p); | |
146 | delete p; | |
147 | delete m; | |
148 | } | |
149 | ||
150 | void wxGraphicsPath::AddRoundedRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h, wxDouble radius) | |
151 | { | |
152 | if ( radius == 0 ) | |
153 | AddRectangle(x,y,w,h); | |
154 | else | |
155 | { | |
156 | MoveToPoint( x + w, y + h / 2); | |
157 | AddArcToPoint(x + w, y + h, x + w / 2, y + h, radius); | |
158 | AddArcToPoint(x, y + h, x, y + h / 2, radius); | |
159 | AddArcToPoint(x, y , x + w / 2, y, radius); | |
160 | AddArcToPoint(x + w, y, x + w, y + h / 2, radius); | |
161 | CloseSubpath(); | |
162 | } | |
163 | } | |
164 | ||
d94228a2 SC |
165 | // draws a an arc to two tangents connecting (current) to (x1,y1) and (x1,y1) to (x2,y2), also a straight line from (current) to (x1,y1) |
166 | void wxGraphicsPath::AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) | |
167 | { | |
168 | wxPoint2DDouble current = GetCurrentPoint(); | |
169 | wxPoint2DDouble p1(x1,y1); | |
170 | wxPoint2DDouble p2(x2,y2); | |
171 | ||
a2d6d210 | 172 | wxPoint2DDouble v1 = current - p1; |
d94228a2 | 173 | v1.Normalize(); |
a2d6d210 | 174 | wxPoint2DDouble v2 = p2 - p1; |
d94228a2 SC |
175 | v2.Normalize(); |
176 | ||
177 | wxDouble alpha = v1.GetVectorAngle() - v2.GetVectorAngle(); | |
178 | ||
179 | if ( alpha < 0 ) | |
a2d6d210 | 180 | alpha = 360 + alpha; |
d94228a2 SC |
181 | // TODO obtuse angles |
182 | ||
183 | alpha = DegToRad(alpha); | |
184 | ||
a2d6d210 | 185 | wxDouble dist = r / sin(alpha/2) * cos(alpha/2); |
d94228a2 | 186 | // calculate tangential points |
a2d6d210 VZ |
187 | wxPoint2DDouble t1 = dist*v1 + p1; |
188 | wxPoint2DDouble t2 = dist*v2 + p1; | |
d94228a2 | 189 | |
a2d6d210 | 190 | wxPoint2DDouble nv1 = v1; |
d94228a2 SC |
191 | nv1.SetVectorAngle(v1.GetVectorAngle()-90); |
192 | wxPoint2DDouble c = t1 + r*nv1; | |
193 | ||
a2d6d210 VZ |
194 | wxDouble a1 = v1.GetVectorAngle()+90; |
195 | wxDouble a2 = v2.GetVectorAngle()-90; | |
d94228a2 SC |
196 | |
197 | AddLineToPoint(t1); | |
198 | AddArc(c.m_x,c.m_y,r,DegToRad(a1),DegToRad(a2),true); | |
199 | AddLineToPoint(p2); | |
200 | } | |
201 | ||
50581042 SC |
202 | //----------------------------------------------------------------------------- |
203 | // wxGraphicsContext Convenience Methods | |
204 | //----------------------------------------------------------------------------- | |
205 | ||
8ddf8e82 SC |
206 | IMPLEMENT_ABSTRACT_CLASS(wxGraphicsContext, wxObject) |
207 | ||
facbe363 SC |
208 | |
209 | wxGraphicsContext::wxGraphicsContext(wxGraphicsRenderer* renderer) : wxGraphicsObject(renderer) | |
210 | { | |
211 | m_pen = NULL; | |
212 | m_releasePen = false; | |
213 | m_brush = NULL; | |
214 | m_releaseBrush = false; | |
215 | m_font = NULL; | |
216 | m_releaseFont = false; | |
217 | } | |
218 | ||
219 | wxGraphicsContext::~wxGraphicsContext() | |
220 | { | |
221 | wxASSERT_MSG( m_pen == NULL , wxT("No pen should be selected during destruction") ); | |
222 | wxASSERT_MSG( m_brush == NULL , wxT("No pen should be selected during destruction") ); | |
223 | } | |
224 | ||
225 | // sets the pen | |
226 | void wxGraphicsContext::SetPen( wxGraphicsPen* pen , bool release ) | |
227 | { | |
228 | if ( m_releasePen ) | |
229 | delete m_pen; | |
230 | m_pen = pen; | |
231 | m_releasePen = release; | |
232 | } | |
233 | ||
234 | void wxGraphicsContext::SetPen( const wxPen& pen ) | |
235 | { | |
236 | if ( pen.GetStyle() == wxTRANSPARENT ) | |
237 | SetPen( NULL ); | |
238 | else | |
239 | SetPen( CreatePen( pen ) ); | |
240 | } | |
241 | ||
242 | // sets the brush for filling | |
243 | void wxGraphicsContext::SetBrush( wxGraphicsBrush* brush , bool release ) | |
244 | { | |
245 | if ( m_releaseBrush ) | |
246 | delete m_brush; | |
247 | m_brush = brush; | |
248 | m_releaseBrush = release; | |
249 | } | |
250 | ||
251 | void wxGraphicsContext::SetBrush( const wxBrush& brush ) | |
252 | { | |
253 | if ( brush.GetStyle() == wxTRANSPARENT ) | |
254 | SetBrush( NULL ); | |
255 | else | |
256 | SetBrush( CreateBrush( brush ) ); | |
257 | } | |
258 | ||
259 | // sets the brush for filling | |
260 | void wxGraphicsContext::SetFont( wxGraphicsFont* font , bool release ) | |
261 | { | |
262 | if ( m_releaseFont ) | |
263 | delete m_font; | |
264 | m_font = font; | |
265 | m_releaseFont = release; | |
266 | } | |
267 | ||
268 | void wxGraphicsContext::SetFont( const wxFont& font, const wxColour& colour ) | |
269 | { | |
270 | SetFont( CreateFont( font, colour ) ); | |
271 | } | |
272 | ||
50581042 SC |
273 | void wxGraphicsContext::DrawPath( const wxGraphicsPath *path, int fillStyle ) |
274 | { | |
275 | FillPath( path , fillStyle ); | |
276 | StrokePath( path ); | |
277 | } | |
278 | ||
279 | void wxGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle ) | |
280 | { | |
a2d6d210 | 281 | Translate(x,y); |
50581042 SC |
282 | Rotate( -angle ); |
283 | DrawText( str , 0, 0 ); | |
284 | Rotate( angle ); | |
a2d6d210 | 285 | Translate(-x,-y); |
50581042 SC |
286 | } |
287 | ||
288 | void wxGraphicsContext::StrokeLine( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2) | |
289 | { | |
290 | wxGraphicsPath* path = CreatePath(); | |
a2d6d210 | 291 | path->MoveToPoint(x1, y1); |
50581042 SC |
292 | path->AddLineToPoint( x2, y2 ); |
293 | StrokePath( path ); | |
294 | delete path; | |
295 | } | |
296 | ||
297 | void wxGraphicsContext::DrawRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h) | |
298 | { | |
299 | wxGraphicsPath* path = CreatePath(); | |
300 | path->AddRectangle( x , y , w , h ); | |
301 | DrawPath( path ); | |
302 | delete path; | |
303 | } | |
304 | ||
305 | void wxGraphicsContext::DrawEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h) | |
306 | { | |
307 | wxGraphicsPath* path = CreatePath(); | |
59720690 SC |
308 | path->AddEllipse(x,y,w,h); |
309 | DrawPath(path); | |
50581042 SC |
310 | delete path; |
311 | } | |
312 | ||
313 | void wxGraphicsContext::DrawRoundedRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h, wxDouble radius) | |
314 | { | |
315 | wxGraphicsPath* path = CreatePath(); | |
59720690 SC |
316 | path->AddRoundedRectangle(x,y,w,h,radius); |
317 | DrawPath(path); | |
50581042 SC |
318 | delete path; |
319 | } | |
320 | ||
321 | void wxGraphicsContext::StrokeLines( size_t n, const wxPoint2DDouble *points) | |
322 | { | |
323 | wxASSERT(n > 1); | |
324 | wxGraphicsPath* path = CreatePath(); | |
a2d6d210 VZ |
325 | path->MoveToPoint(points[0].m_x, points[0].m_y); |
326 | for ( size_t i = 1; i < n; ++i) | |
50581042 SC |
327 | path->AddLineToPoint( points[i].m_x, points[i].m_y ); |
328 | StrokePath( path ); | |
329 | delete path; | |
330 | } | |
331 | ||
332 | void wxGraphicsContext::DrawLines( size_t n, const wxPoint2DDouble *points, int fillStyle) | |
333 | { | |
334 | wxASSERT(n > 1); | |
335 | wxGraphicsPath* path = CreatePath(); | |
a2d6d210 VZ |
336 | path->MoveToPoint(points[0].m_x, points[0].m_y); |
337 | for ( size_t i = 1; i < n; ++i) | |
50581042 SC |
338 | path->AddLineToPoint( points[i].m_x, points[i].m_y ); |
339 | DrawPath( path , fillStyle); | |
340 | delete path; | |
341 | } | |
342 | ||
343 | void wxGraphicsContext::StrokeLines( size_t n, const wxPoint2DDouble *beginPoints, const wxPoint2DDouble *endPoints) | |
344 | { | |
345 | wxASSERT(n > 0); | |
346 | wxGraphicsPath* path = CreatePath(); | |
a2d6d210 | 347 | for ( size_t i = 0; i < n; ++i) |
50581042 | 348 | { |
a2d6d210 | 349 | path->MoveToPoint(beginPoints[i].m_x, beginPoints[i].m_y); |
50581042 SC |
350 | path->AddLineToPoint( endPoints[i].m_x, endPoints[i].m_y ); |
351 | } | |
352 | StrokePath( path ); | |
353 | delete path; | |
354 | } | |
355 | ||
facbe363 SC |
356 | // create a 'native' matrix corresponding to these values |
357 | wxGraphicsMatrix* wxGraphicsContext::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d, | |
358 | wxDouble tx, wxDouble ty) | |
50581042 | 359 | { |
facbe363 | 360 | return GetRenderer()->CreateMatrix(a,b,c,d,tx,ty); |
50581042 SC |
361 | } |
362 | ||
06b9edb7 SC |
363 | wxGraphicsPath * wxGraphicsContext::CreatePath() |
364 | { | |
365 | return GetRenderer()->CreatePath(); | |
366 | } | |
367 | ||
368 | wxGraphicsPen* wxGraphicsContext::CreatePen(const wxPen& pen) | |
369 | { | |
370 | return GetRenderer()->CreatePen(pen); | |
371 | } | |
372 | ||
373 | wxGraphicsBrush* wxGraphicsContext::CreateBrush(const wxBrush& brush ) | |
374 | { | |
375 | return GetRenderer()->CreateBrush(brush); | |
376 | } | |
377 | ||
378 | // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 | |
379 | wxGraphicsBrush* wxGraphicsContext::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, | |
380 | const wxColour&c1, const wxColour&c2) | |
381 | { | |
382 | return GetRenderer()->CreateLinearGradientBrush(x1,y1,x2,y2,c1,c2); | |
383 | } | |
384 | ||
385 | // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) | |
386 | // with radius r and color cColor | |
387 | wxGraphicsBrush* wxGraphicsContext::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, | |
388 | const wxColour &oColor, const wxColour &cColor) | |
389 | { | |
390 | return GetRenderer()->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor); | |
391 | } | |
392 | ||
393 | // sets the font | |
394 | wxGraphicsFont* wxGraphicsContext::CreateFont( const wxFont &font , const wxColour &col ) | |
395 | { | |
396 | return GetRenderer()->CreateFont(font,col); | |
397 | } | |
398 | ||
399 | wxGraphicsContext* wxGraphicsContext::Create( const wxWindowDC& dc) | |
400 | { | |
401 | return wxGraphicsRenderer::GetDefaultRenderer()->CreateContext(dc); | |
402 | } | |
403 | ||
404 | wxGraphicsContext* wxGraphicsContext::CreateFromNative( void * context ) | |
405 | { | |
406 | return wxGraphicsRenderer::GetDefaultRenderer()->CreateContextFromNativeContext(context); | |
407 | } | |
408 | ||
409 | wxGraphicsContext* wxGraphicsContext::CreateFromNativeWindow( void * window ) | |
410 | { | |
411 | return wxGraphicsRenderer::GetDefaultRenderer()->CreateContextFromNativeWindow(window); | |
412 | } | |
413 | ||
414 | wxGraphicsContext* wxGraphicsContext::Create( wxWindow* window ) | |
415 | { | |
416 | return wxGraphicsRenderer::GetDefaultRenderer()->CreateContext(window); | |
417 | } | |
418 | ||
9fd707a5 | 419 | #endif // wxUSE_GRAPHICS_CONTEXT |