]> git.saurik.com Git - wxWidgets.git/blame - src/common/dcsvg.cpp
invalidate the best size when adding or deleting items
[wxWidgets.git] / src / common / dcsvg.cpp
CommitLineData
cdf3a589
CE
1/////////////////////////////////////////////////////////////////////////////
2// Name: svg.cpp
3// Purpose: SVG sample
4// Author: Chris Elliott
5// Modified by:
6// RCS-ID: $Id$
7// Licence: wxWindows license
8/////////////////////////////////////////////////////////////////////////////
9
10
11// For compilers that support precompilation, includes "wx/wx.h".
12#include "wx/wxprec.h"
13
14#ifdef __BORLANDC__
15#pragma hdrstop
16#endif
17
18#ifndef WX_PRECOMP
19#include "wx/wx.h"
20#endif
3454ecd5 21
54429bb3 22#include "wx/dcsvg.h"
cdf3a589
CE
23#include "wx/image.h"
24
25#define wxSVG_DEBUG FALSE
26// or TRUE to see the calls being executed
cdf3a589 27
18cea871
RD
28#define newline wxString(wxT("\n"))
29#define space wxString(wxT(" "))
30#define semicolon wxString(wxT(";"))
31#define wx_round(a) (int)((a)+.5)
cdf3a589 32
1bb592b8 33static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
cdf3a589
CE
34
35wxString wxColStr ( wxColour c )
36{
37 unsigned char r, g, b ;
38 r = c.Red ();
39 g = c.Green ();
40 b = c. Blue ();
41
42 // possible Unicode bug here
43 wxString s = wxDecToHex(r) + wxDecToHex(g) + wxDecToHex(b) ;
44 return s ;
45}
46
47
48wxString wxBrushString ( wxColour c, int style )
49{
50 wxString s = wxT("fill:#") + wxColStr (c) + semicolon + space ;
51 switch ( style )
52 {
53 case wxSOLID :
54 s = s + wxT("fill-opacity:1.0; ");
55 break ;
56 case wxTRANSPARENT:
57 s = s + wxT("fill-opacity:0.0; ");
58 break ;
59
60 default :
61 wxASSERT_MSG(FALSE, wxT("wxSVGFileDC::Requested Brush Style not available")) ;
62
63 }
64 s = s + newline ;
65 return s ;
66}
67
68
69void wxSVGFileDC::Init (wxString f, int Width, int Height, float dpi)
70
71{
72 //set up things first wxDCBase does all this?
73 m_width = Width ;
74 m_height = Height ;
75
76 m_clipping = FALSE;
77 m_OK = TRUE;
78
79 m_mm_to_pix_x = dpi/25.4;
80 m_mm_to_pix_y = dpi/25.4;
81
82 m_signX = m_signY = 1;
83
84 m_userScaleX = m_userScaleY =
85 m_deviceOriginX = m_deviceOriginY = 0;
86
87 m_OriginX = m_OriginY = 0;
88 m_logicalOriginX = m_logicalOriginY = 0;
89 m_logicalScaleX = m_logicalScaleY = 0 ;
90 m_scaleX = m_scaleY = 1.0 ;
91
92 m_logicalFunction = wxCOPY;
93 m_backgroundMode = wxTRANSPARENT;
94 m_mappingMode = wxMM_TEXT;
95
96 m_backgroundBrush = *wxTRANSPARENT_BRUSH;
97 m_textForegroundColour = *wxBLACK;
98 m_textBackgroundColour = *wxWHITE;
99 m_colour = wxColourDisplay();
100
101 m_pen = *wxBLACK_PEN;
102 m_font = *wxNORMAL_FONT;
103 m_brush = *wxWHITE_BRUSH;
104
105 m_graphics_changed = TRUE ;
106
107 ////////////////////code here
108
109 m_outfile = new wxFileOutputStream(f) ;
110 m_OK = m_outfile->Ok ();
111 if (m_OK)
112 {
113 m_filename = f ;
114 m_sub_images = 0 ;
115 wxString s ;
116 s = wxT("<?xml version=\"1.0\" standalone=\"no\"?>") ; s = s + newline ;
85b88942 117 write(s);
cdf3a589 118 s = wxT("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\" ") + newline ;
85b88942 119 write(s);
cdf3a589 120 s = wxT("\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\"> ")+ newline ;
85b88942 121 write(s);
cdf3a589 122 s.Printf ( wxT("<svg width=\"%.2gcm\" height=\"%.2gcm\" viewBox=\"0 0 %d %d \"> \n"), float(Width)/dpi*2.54, float(Height)/dpi*2.54, Width, Height );
85b88942 123 write(s);
cdf3a589 124 s = wxT("<title>SVG Picture created as ") + wxFileNameFromPath(f) + wxT(" </title>") + newline ;
85b88942 125 write(s);
cdf3a589 126 s = wxString (wxT("<desc>Picture generated by wxSVG ")) + wxSVGVersion + wxT(" </desc>")+ newline ;
85b88942 127 write(s);
cdf3a589 128 s = wxT("<g style=\"fill:black; stroke:black; stroke-width:1\">") + newline ;
85b88942 129 write(s);
cdf3a589
CE
130
131 }
cdf3a589
CE
132}
133
134
135// constructors
136wxSVGFileDC::wxSVGFileDC (wxString f)
3454ecd5 137{
cdf3a589
CE
138 // quarter 640x480 screen display at 72 dpi
139 Init (f,320,240,72.0);
1bb592b8 140}
cdf3a589
CE
141
142wxSVGFileDC::wxSVGFileDC (wxString f, int Width, int Height)
143{
144 Init (f,Width,Height,72.0);
1bb592b8 145}
cdf3a589
CE
146
147wxSVGFileDC::wxSVGFileDC (wxString f, int Width, int Height, float dpi)
148{
149 Init (f,Width,Height,dpi);
1bb592b8 150}
cdf3a589
CE
151
152wxSVGFileDC::~wxSVGFileDC()
153{
154 wxString s = wxT("</g> \n</svg> \n") ;
85b88942 155 write(s);
cdf3a589
CE
156 delete m_outfile ;
157}
158
159
160//////////////////////////////////////////////////////////////////////////////////////////
161
162void wxSVGFileDC::DoDrawLine (wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
163{
164 if (m_graphics_changed) NewGraphics ();
165 wxString s ;
166 s.Printf ( wxT("<path d=\"M%d %d L%d %d\" /> \n"), x1,y1,x2,y2 );
167 if (m_OK)
168 {
85b88942 169 write(s);
cdf3a589 170 }
cdf3a589
CE
171 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DrawLine Call executed")) ;
172 CalcBoundingBox(x1, y1) ;
173 CalcBoundingBox(x2, y2) ;
174 return;
1bb592b8 175}
cdf3a589
CE
176
177void wxSVGFileDC::DoDrawLines(int n, wxPoint points[], wxCoord xoffset , wxCoord yoffset )
178{
179 for ( int i = 1; i < n ; i++ )
180 {
181 DoDrawLine ( points [i-1].x + xoffset, points [i-1].y + yoffset,
182 points [ i ].x + xoffset, points [ i ].y + yoffset ) ;
183 }
184}
185
186
187void wxSVGFileDC::DoDrawPoint (wxCoord x1, wxCoord y1)
188{
189 wxString s;
190 if (m_graphics_changed) NewGraphics ();
191 s = wxT("<g style = \"stroke-linecap:round;\" > ") + newline ;
85b88942 192 write(s);
cdf3a589
CE
193 DrawLine ( x1,y1,x1,y1 );
194 s = wxT("</g>");
85b88942 195 write(s);
cdf3a589
CE
196}
197
198
199void wxSVGFileDC::DoDrawCheckMark(wxCoord x1, wxCoord y1, wxCoord width, wxCoord height)
200{
201 wxDCBase::DoDrawCheckMark (x1,y1,width,height) ;
202}
203
204
205void wxSVGFileDC::DoDrawText(const wxString& text, wxCoord x1, wxCoord y1)
206{
207 DoDrawRotatedText(text, x1,y1,0.0);
208 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DrawText Call executed")) ;
209}
210
211
212void wxSVGFileDC::DoDrawRotatedText(const wxString& sText, wxCoord x, wxCoord y, double angle)
213{
214 //known bug; if the font is drawn in a scaled DC, it will not behave exactly as wxMSW
215 if (m_graphics_changed) NewGraphics ();
216 wxString s, sTmp;
217
218 // calculate bounding box
219 wxCoord w, h, desc ;
220 DoGetTextExtent(sText, &w, &h, &desc);
221
222 double rad = DegToRad(angle);
223
224 // wxT("upper left") and wxT("upper right")
225 CalcBoundingBox(x, y);
216db41f 226 CalcBoundingBox((wxCoord)(x + w*cos(rad)), (wxCoord)(y - h*sin(rad)));
cdf3a589
CE
227
228 // wxT("bottom left") and wxT("bottom right")
229 x += (wxCoord)(h*sin(rad));
230 y += (wxCoord)(h*cos(rad));
231 CalcBoundingBox(x, y);
216db41f 232 CalcBoundingBox((wxCoord)(x + h*sin(rad)), (wxCoord)(y + h*cos(rad)));
cdf3a589
CE
233
234 if (m_backgroundMode == wxSOLID)
235 {
236 // draw background first
237 // just like DoDrawRectangle except we pass the text color to it and set the border to a 1 pixel wide text background
238
239 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::Draw Rotated Text Call plotting text background")) ;
240 sTmp.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" "), x,y+desc-h, w, h );
241 s = sTmp + wxT("style=\"fill:#") + wxColStr (m_textBackgroundColour) + wxT("; ") ;
242 s = s + wxT("stroke-width:1; stroke:#") + wxColStr (m_textBackgroundColour) + wxT("; ") ;
243 sTmp.Printf ( wxT("\" transform=\"rotate( %.2g %d %d ) \">"), -angle, x,y ) ;
244 s = s + sTmp + newline ;
85b88942 245 write(s);
cdf3a589
CE
246 }
247 //now do the text itself
248 s.Printf (wxT(" <text x=\"%d\" y=\"%d\" "),x,y );
3454ecd5 249
cdf3a589
CE
250 sTmp = m_font.GetFaceName () ;
251 if (sTmp.Len () > 0) s = s + wxT("style=\"font-family:") + sTmp + wxT("; ");
252 else s = s + wxT("style=\" ") ;
253
254 wxString fontweights [3] = { wxT("normal"), wxT("lighter"), wxT("bold") };
255 s = s + wxT("font-weight:") + fontweights[m_font.GetWeight() - wxNORMAL] + semicolon + space;
3454ecd5 256
cdf3a589
CE
257 wxString fontstyles [5] = { wxT("normal"), wxT("style error"), wxT("style error"), wxT("italic"), wxT("oblique") };
258 s = s + wxT("font-style:") + fontstyles[m_font.GetStyle() - wxNORMAL] + semicolon + space;
3454ecd5 259
cdf3a589
CE
260 sTmp.Printf (wxT("font-size:%dpt; fill:#"), m_font.GetPointSize () );
261 s = s + sTmp ;
262 s = s + wxColStr (m_textForegroundColour) + wxT("; stroke:#") + wxColStr (m_textForegroundColour) + wxT("; ") ;
263 sTmp.Printf ( wxT("stroke-width:0;\" transform=\"rotate( %.2g %d %d ) \" >"), -angle, x,y ) ;
264 s = s + sTmp + sText + wxT("</text> ") + newline ;
265 if (m_OK)
266 {
85b88942 267 write(s);
cdf3a589 268 }
cdf3a589
CE
269 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DrawRotatedText Call executed")) ;
270
271}
272
273
274void wxSVGFileDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
275{
276 DoDrawRoundedRectangle(x, y, width, height, 0) ;
277}
278
279
280void wxSVGFileDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius )
281
282{
283 if (m_graphics_changed) NewGraphics ();
284 wxString s ;
285
3454ecd5 286 s.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" rx=\"%.2g\" "),
cdf3a589
CE
287 x, y, width, height, radius );
288
289 s = s + wxT(" /> ") + newline ;
85b88942 290 write(s);
cdf3a589
CE
291
292 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawRoundedRectangle Call executed")) ;
293 CalcBoundingBox(x, y) ;
294 CalcBoundingBox(x + width, y + height) ;
295
296}
297
298
299void wxSVGFileDC::DoDrawPolygon(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset,int fillStyle)
300{
301 if (m_graphics_changed) NewGraphics ();
302 wxString s, sTmp ;
303 s = wxT("<polygon style=\"") ;
304 if ( fillStyle == wxODDEVEN_RULE )
305 s = s + wxT("fill-rule:evenodd; ");
306 else
307 s = s + wxT("fill-rule:nonzero; ");
308
309 s = s + wxT("\" \npoints=\"") ;
310
311 for (int i = 0; i < n; i++)
312 {
313 sTmp.Printf ( wxT("%d,%d"), points [i].x+xoffset, points[i].y+yoffset );
314 s = s + sTmp + newline ;
315 CalcBoundingBox ( points [i].x+xoffset, points[i].y+yoffset);
316 }
317 s = s + wxT("\" /> ") ;
318 s = s + newline ;
85b88942 319 write(s);
cdf3a589
CE
320
321 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawPolygon Call executed")) ;
322}
323
324
325void wxSVGFileDC::DoDrawEllipse (wxCoord x, wxCoord y, wxCoord width, wxCoord height)
326
327{
328 if (m_graphics_changed) NewGraphics ();
329
330 int rh = height /2 ;
331 int rw = width /2 ;
332
333 wxString s;
334 s.Printf ( wxT("<ellipse cx=\"%d\" cy=\"%d\" rx=\"%d\" ry=\"%d\" "), x+rw,y+rh, rw, rh );
335 s = s + wxT(" /> ") + newline ;
336
85b88942 337 write(s);
cdf3a589
CE
338
339 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawEllipse Call executed")) ;
340 CalcBoundingBox(x, y) ;
341 CalcBoundingBox(x + width, y + height) ;
342}
343
344
345void wxSVGFileDC::DoDrawArc(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc)
346{
347 /* Draws an arc of a circle, centred on (xc, yc), with starting point
348 (x1, y1) and ending at (x2, y2). The current pen is used for the outline
349 and the current brush for filling the shape.
350
351 The arc is drawn in an anticlockwise direction from the start point to
352 the end point.
353
354 Might be better described as Pie drawing */
355
356 if (m_graphics_changed) NewGraphics ();
357 wxString s ;
358
359 // we need the radius of the circle which has two estimates
360 double r1 = sqrt ( double( (x1-xc)*(x1-xc) ) + double( (y1-yc)*(y1-yc) ) );
361 double r2 = sqrt ( double( (x2-xc)*(x2-xc) ) + double( (y2-yc)*(y2-yc) ) );
362
363 wxASSERT_MSG( (fabs ( r2-r1 ) <= 3), wxT("wxSVGFileDC::DoDrawArc Error in getting radii of circle")) ;
364 if ( fabs ( r2-r1 ) > 3 ) //pixels
365 {
366 s = wxT("<!--- wxSVGFileDC::DoDrawArc Error in getting radii of circle --> \n") ;
85b88942 367 write(s);
cdf3a589
CE
368 }
369
fb88ba48 370 double theta1 = atan2((double)(yc-y1),(double)(x1-xc));
3454ecd5 371 if ( theta1 < 0 ) theta1 = theta1 + M_PI * 2;
fb88ba48 372 double theta2 = atan2((double)(yc-y2), (double)(x2-xc));
3454ecd5
WS
373 if ( theta2 < 0 ) theta2 = theta2 + M_PI * 2;
374 if ( theta2 < theta1 ) theta2 = theta2 + M_PI *2 ;
cdf3a589
CE
375
376 int fArc ; // flag for large or small arc 0 means less than 180 degrees
3454ecd5 377 if ( fabs(theta2 - theta1) > M_PI ) fArc = 1; else fArc = 0 ;
cdf3a589
CE
378
379 int fSweep = 0 ; // flag for sweep always 0
380
381 s.Printf ( wxT("<path d=\"M%d %d A%.2g %.2g 0.0 %d %d %d %d L%d %d z "),
382 x1,y1, r1, r2, fArc, fSweep, x2, y2, xc, yc );
383
384 // the z means close the path and fill
385 s = s + wxT(" \" /> ") + newline ;
386
387
388 if (m_OK)
389 {
85b88942 390 write(s);
cdf3a589 391 }
cdf3a589
CE
392
393 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawArc Call executed")) ;
394}
395
396
397void wxSVGFileDC::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea)
398{
399 /*
400 Draws an arc of an ellipse. The current pen is used for drawing the arc
401 and the current brush is used for drawing the pie. This function is
402 currently only available for X window and PostScript device contexts.
403
404 x and y specify the x and y coordinates of the upper-left corner of the
405 rectangle that contains the ellipse.
406
407 width and height specify the width and height of the rectangle that
408 contains the ellipse.
409
410 start and end specify the start and end of the arc relative to the
411 three-o'clock position from the center of the rectangle. Angles are
412 specified in degrees (360 is a complete circle). Positive values mean
413 counter-clockwise motion. If start is equal to end, a complete ellipse
414 will be drawn. */
415
416 //known bug: SVG draws with the current pen along the radii, but this does not happen in wxMSW
417
418 if (m_graphics_changed) NewGraphics ();
419
420 wxString s ;
421 //radius
422 double rx = w / 2 ;
423 double ry = h / 2 ;
424 // center
425 double xc = x + rx ;
426 double yc = y + ry ;
427
428 double xs, ys, xe, ye ;
429 xs = xc + rx * cos (DegToRad(sa)) ;
430 xe = xc + rx * cos (DegToRad(ea)) ;
431 ys = yc - ry * sin (DegToRad(sa)) ;
432 ye = yc - ry * sin (DegToRad(ea)) ;
433
434 ///now same as circle arc...
435
436 double theta1 = atan2(ys-yc, xs-xc);
437 double theta2 = atan2(ye-yc, xe-xc);
438
439 int fArc ; // flag for large or small arc 0 means less than 180 degrees
440 if ( (theta2 - theta1) > 0 ) fArc = 1; else fArc = 0 ;
441
442 int fSweep ;
3454ecd5 443 if ( fabs(theta2 - theta1) > M_PI) fSweep = 1; else fSweep = 0 ;
cdf3a589
CE
444
445 s.Printf ( wxT("<path d=\"M%d %d A%d %d 0.0 %d %d %d %d L %d %d z "),
446 int(xs), int(ys), int(rx), int(ry),
447 fArc, fSweep, int(xe), int(ye), int(xc), int(yc) );
448
449
450 s = s + wxT(" \" /> ") + newline ;
451
452 if (m_OK)
453 {
85b88942 454 write(s);
cdf3a589 455 }
cdf3a589
CE
456
457 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawEllipticArc Call executed")) ;
458}
459
460
c94f845b 461void wxSVGFileDC::DoGetTextExtent(const wxString& string, wxCoord *w, wxCoord *h, wxCoord *descent , wxCoord *externalLeading , const wxFont *font) const
cdf3a589
CE
462
463{
464 wxScreenDC sDC ;
465
466 sDC.SetFont (m_font);
467 if ( font != NULL ) sDC.SetFont ( *font );
468 sDC.GetTextExtent(string, w, h, descent, externalLeading );
469 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::GetTextExtent Call executed")) ;
470}
471
472
473wxCoord wxSVGFileDC::GetCharHeight() const
474
475{
476 wxScreenDC sDC ;
477 sDC.SetFont (m_font);
478
479 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::GetCharHeight Call executing")) ;
480 return ( sDC.GetCharHeight() );
481
482}
483
484
485wxCoord wxSVGFileDC::GetCharWidth() const
486{
487 wxScreenDC sDC ;
488 sDC.SetFont (m_font);
489
490 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::GetCharWidth Call executing")) ;
491 return ( sDC.GetCharWidth() ) ;
492
493}
494
495
496/// Set Functions /////////////////////////////////////////////////////////////////
497void wxSVGFileDC::SetBackground( const wxBrush &brush )
498{
499
500 m_backgroundBrush = brush;
501 return;
502}
503
504
505void wxSVGFileDC::SetBackgroundMode( int mode )
506{
507 m_backgroundMode = mode;
508 return;
509}
510
511
512void wxSVGFileDC::SetBrush(const wxBrush& brush)
513
514{
515 m_brush = brush ;
516
517 m_graphics_changed = TRUE ;
518 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::SetBrush Call executed")) ;
519}
520
521
522void wxSVGFileDC::SetPen(const wxPen& pen)
523{
524 // width, color, ends, joins : currently implemented
525 // dashes, stipple : not implemented
526 m_pen = pen ;
3454ecd5 527
cdf3a589
CE
528 m_graphics_changed = TRUE ;
529 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::SetPen Call executed")) ;
530}
531
532void wxSVGFileDC::NewGraphics ()
533{
534
535 int w = m_pen.GetWidth ();
536 wxColour c = m_pen.GetColour () ;
537
538 wxString s, sBrush, sPenCap, sPenJoin, sPenStyle, sLast, sWarn;
3454ecd5
WS
539
540 sBrush = wxT("</g>\n<g style=\"") + wxBrushString ( m_brush.GetColour (), m_brush.GetStyle () )
541 + wxT(" stroke:#") + wxColStr (c) + wxT("; ") ;
542
cdf3a589
CE
543 switch ( m_pen.GetCap () )
544 {
545 case wxCAP_PROJECTING :
546 sPenCap = wxT("stroke-linecap:square; ") ;
547 break ;
548 case wxCAP_BUTT :
549 sPenCap = wxT("stroke-linecap:butt; ") ;
550 break ;
551 case wxCAP_ROUND :
552 default :
553 sPenCap = wxT("stroke-linecap:round; ") ;
554 };
555 switch ( m_pen.GetJoin () )
556 {
557 case wxJOIN_BEVEL :
558 sPenJoin = wxT("stroke-linejoin:bevel; ") ;
559 break ;
560 case wxJOIN_MITER :
561 sPenJoin = wxT("stroke-linejoin:miter; ") ;
562 break ;
563 case wxJOIN_ROUND :
564 default :
565 sPenJoin = wxT("stroke-linejoin:round; ") ;
566 };
567
568 switch ( m_pen.GetStyle () )
569 {
570 case wxSOLID :
571 sPenStyle = wxT("stroke-opacity:1.0; stroke-opacity:1.0; ") ;
572 break ;
573 case wxTRANSPARENT :
574 sPenStyle = wxT("stroke-opacity:0.0; stroke-opacity:0.0; ") ;
575 break ;
576 default :
577 wxASSERT_MSG(FALSE, wxT("wxSVGFileDC::SetPen Call called to set a Style which is not available")) ;
578 sWarn = sWarn + wxT("<!--- wxSVGFileDC::SetPen Call called to set a Style which is not available --> \n") ;
579 }
580
3454ecd5 581 sLast.Printf ( wxT("stroke-width:%d\" \n transform=\"translate(%.2g %.2g) scale(%.2g %.2g)\">"),
cdf3a589
CE
582 w, m_OriginX, m_OriginY, m_scaleX, m_scaleY );
583
584 s = sBrush + sPenCap + sPenJoin + sPenStyle + sLast + newline + sWarn;
85b88942 585 write(s);
cdf3a589
CE
586 m_graphics_changed = FALSE ;
587 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::NewGraphics Call executed")) ;
588}
589
590
591void wxSVGFileDC::SetFont(const wxFont& font)
592
593{
594 m_font = font ;
3454ecd5 595
cdf3a589
CE
596 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::SetFont Call executed")) ;
597}
598
599
600void wxSVGFileDC::ComputeScaleAndOrigin()
601{
602 m_scaleX = m_logicalScaleX * m_userScaleX;
603 m_scaleY = m_logicalScaleY * m_userScaleY;
604 m_OriginX = m_logicalOriginX * m_logicalScaleX + m_deviceOriginX ;
605 m_OriginY = m_logicalOriginY * m_logicalScaleY + m_deviceOriginY ;
606 m_graphics_changed = TRUE;
607}
608
609
781a8d7f 610int wxSVGFileDC::GetMapMode() const
cdf3a589
CE
611{
612 return m_mappingMode ;
613}
614
615
616void wxSVGFileDC::SetMapMode( int mode )
617{
618 switch (mode)
619 {
620 case wxMM_TWIPS:
621 SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
622 break;
623 case wxMM_POINTS:
624 SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
625 break;
626 case wxMM_METRIC:
627 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
628 break;
629 case wxMM_LOMETRIC:
630 SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
631 break;
632 default:
633 case wxMM_TEXT:
634 SetLogicalScale( 1.0, 1.0 );
635 break;
636 }
637 m_mappingMode = mode;
638
639 /* we don't do this mega optimisation
640 if (mode != wxMM_TEXT)
641 {
642 m_needComputeScaleX = TRUE;
643 m_needComputeScaleY = TRUE;
644 }
645 */
646}
647
648
649void wxSVGFileDC::GetUserScale(double *x, double *y) const
650{
651 *x = m_userScaleX ;
652 *y = m_userScaleY ;
653}
654
655
656void wxSVGFileDC::SetUserScale( double x, double y )
657{
658 // allow negative ? -> no
659 m_userScaleX = x;
660 m_userScaleY = y;
661 ComputeScaleAndOrigin();
662}
663
664
665void wxSVGFileDC::SetLogicalScale( double x, double y )
666{
667 // allow negative ?
668 m_logicalScaleX = x;
669 m_logicalScaleY = y;
670 ComputeScaleAndOrigin();
671}
672
673
674void wxSVGFileDC::SetLogicalOrigin( wxCoord x, wxCoord y )
675{
676 // is this still correct ?
677 m_logicalOriginX = x * m_signX;
678 m_logicalOriginY = y * m_signY;
679 ComputeScaleAndOrigin();
680}
681
682
683void wxSVGFileDC::SetDeviceOrigin( wxCoord x, wxCoord y )
684{
3454ecd5 685 // only wxPostScripDC has m_signX = -1,
cdf3a589
CE
686 m_deviceOriginX = x;
687 m_deviceOriginY = y;
688 ComputeScaleAndOrigin();
689}
690
691
692void wxSVGFileDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
693{
3454ecd5 694 // only wxPostScripDC has m_signX = -1,
cdf3a589
CE
695 m_signX = (xLeftRight ? 1 : -1);
696 m_signY = (yBottomUp ? -1 : 1);
697 ComputeScaleAndOrigin();
698}
699
700
701// export a bitmap as a raster image in png
702bool wxSVGFileDC::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
3454ecd5
WS
703 wxDC* source, wxCoord xsrc, wxCoord ysrc,
704 int logicalFunc /*= wxCOPY*/, bool useMask /*= FALSE*/,
705 wxCoord /*xsrcMask = -1*/, wxCoord /*ysrcMask = -1*/)
cdf3a589 706{
cdf3a589
CE
707 if (logicalFunc != wxCOPY)
708 {
709 wxASSERT_MSG(FALSE, wxT("wxSVGFileDC::DoBlit Call requested nonCopy mode; this is not possible")) ;
710 return FALSE ;
711 }
712 if (useMask != FALSE)
713 {
714 wxASSERT_MSG(FALSE, wxT("wxSVGFileDC::DoBlit Call requested False mask ; this is not possible")) ;
715 return FALSE ;
716 }
717 wxBitmap myBitmap (width, height) ;
718 wxMemoryDC memDC;
719 memDC.SelectObject( myBitmap );
720 memDC.Blit(0, 0, width, height, source, xsrc, ysrc);
721 memDC.SelectObject( wxNullBitmap );
722 DoDrawBitmap(myBitmap, xdest, ydest);
723 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoBlit Call executed")) ;
724 return FALSE ;
725}
726
727
728void wxSVGFileDC::DoDrawIcon(const class wxIcon & myIcon, wxCoord x, wxCoord y)
729{
730 wxBitmap myBitmap (myIcon.GetWidth(), myIcon.GetHeight() ) ;
731 wxMemoryDC memDC;
732 memDC.SelectObject( myBitmap );
733 memDC.DrawIcon(myIcon,0,0);
734 memDC.SelectObject( wxNullBitmap );
735 DoDrawBitmap(myBitmap, x, y);
736 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawIcon Call executed")) ;
737 return ;
738}
739
740
3454ecd5 741
1a55595e 742void wxSVGFileDC::DoDrawBitmap(const class wxBitmap & bmp, wxCoord x, wxCoord y , bool WXUNUSED(bTransparent) /*=0*/ )
cdf3a589
CE
743{
744 if (m_graphics_changed) NewGraphics ();
745
3454ecd5 746 wxString sTmp, s, sPNG ;
cdf3a589
CE
747 wxImage::AddHandler(new wxPNGHandler);
748
3454ecd5 749// create suitable file name
cdf3a589
CE
750 sTmp.Printf ( wxT("_image%d.png"), m_sub_images);
751 sPNG = m_filename.BeforeLast(wxT('.')) + sTmp;
752 while (wxFile::Exists(sPNG) )
753 {
754 m_sub_images ++ ;
755 sTmp.Printf ( wxT("_image%d.png"), m_sub_images);
756 sPNG = m_filename.BeforeLast(wxT('.')) + sTmp;
757 }
3454ecd5 758
cdf3a589
CE
759//create copy of bitmap (wxGTK doesn't like saving a constant bitmap)
760 wxBitmap myBitmap = bmp ;
761//save it
762 bool bPNG_OK = myBitmap.SaveFile(sPNG,wxBITMAP_TYPE_PNG);
763
764// refrence the bitmap from the SVG doc
765 int w = myBitmap.GetWidth();
766 int h = myBitmap.GetHeight();
767 sTmp.Printf ( wxT(" <image x=\"%d\" y=\"%d\" width=\"%dpx\" height=\"%dpx\" "), x,y,w,h );
768 s = s + sTmp ;
769 sTmp.Printf ( wxT(" xlink:href=\"%s\"> \n"), sPNG.c_str() );
770 s = s + sTmp + wxT("<title>Image from wxSVG</title> </image>") + newline;
3454ecd5 771
cdf3a589
CE
772 if (m_OK && bPNG_OK)
773 {
85b88942 774 write(s);
cdf3a589
CE
775 }
776 m_OK = m_outfile->Ok () && bPNG_OK;
777 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawBitmap Call executed")) ;
778
779 return ;
780}
781
782
783// ---------------------------------------------------------------------------
784// coordinates transformations
785// ---------------------------------------------------------------------------
786
787wxCoord wxSVGFileDC::DeviceToLogicalX(wxCoord x) const
788{
789 return XDEV2LOG(x);
790}
791
792
793wxCoord wxSVGFileDC::DeviceToLogicalY(wxCoord y) const
794{
795 return YDEV2LOG(y);
796}
797
798
799wxCoord wxSVGFileDC::DeviceToLogicalXRel(wxCoord x) const
800{
801 return XDEV2LOGREL(x);
802}
803
804
805wxCoord wxSVGFileDC::DeviceToLogicalYRel(wxCoord y) const
806{
807 return YDEV2LOGREL(y);
808}
809
810
811wxCoord wxSVGFileDC::LogicalToDeviceX(wxCoord x) const
812{
813 return XLOG2DEV(x);
814}
815
816
817wxCoord wxSVGFileDC::LogicalToDeviceY(wxCoord y) const
818{
819 return YLOG2DEV(y);
820}
821
822
823wxCoord wxSVGFileDC::LogicalToDeviceXRel(wxCoord x) const
824{
825 return XLOG2DEVREL(x);
826}
827
828
829wxCoord wxSVGFileDC::LogicalToDeviceYRel(wxCoord y) const
830{
831 return YLOG2DEVREL(y);
832}
833
85b88942
JS
834void wxSVGFileDC::write(const wxString &s)
835{
3454ecd5
WS
836 const wxWX2MBbuf buf = s.mb_str(wxConvUTF8);
837 m_outfile->Write(buf, strlen((const char *)buf));
838 m_OK = m_outfile->Ok();
85b88942 839}
cdf3a589
CE
840
841#ifdef __BORLANDC__
842#pragma warn .rch
843#pragma warn .ccc
844#endif