]> git.saurik.com Git - wxWidgets.git/blame - src/common/dcsvg.cpp
Implement incremental search in wxGenericListCtrl.
[wxWidgets.git] / src / common / dcsvg.cpp
CommitLineData
cdf3a589 1/////////////////////////////////////////////////////////////////////////////
80fdcdb9 2// Name: src/common/svg.cpp
cdf3a589
CE
3// Purpose: SVG sample
4// Author: Chris Elliott
5// Modified by:
6// RCS-ID: $Id$
526954c5 7// Licence: wxWindows licence
cdf3a589
CE
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
b0fc907f
VZ
18#if wxUSE_SVG
19
cdf3a589 20#ifndef WX_PRECOMP
98c38984
VZ
21 #include "wx/dcmemory.h"
22 #include "wx/dcscreen.h"
23 #include "wx/icon.h"
24 #include "wx/image.h"
cdf3a589 25#endif
3454ecd5 26
54429bb3 27#include "wx/dcsvg.h"
8e10778e 28#include "wx/wfstream.h"
ddabd45b 29#include "wx/filename.h"
cdf3a589 30
13cfc51d
FM
31// ----------------------------------------------------------
32// Global utilities
33// ----------------------------------------------------------
34
caef3ffa
VZ
35namespace
36{
37
38inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
cdf3a589 39
caef3ffa
VZ
40// This function returns a string representation of a floating point number in
41// C locale (i.e. always using "." for the decimal separator) and with the
42// fixed precision (which is 2 for some unknown reason but this is what it was
43// in this code originally).
44inline wxString NumStr(double f)
45{
46 return wxString::FromCDouble(f, 2);
47}
48
007d2de3
VZ
49// Return the colour representation as HTML-like "#rrggbb" string and also
50// returns its alpha as opacity number in 0..1 range.
51wxString Col2SVG(wxColour c, float *opacity)
403695b3 52{
007d2de3 53 if ( c.Alpha() != wxALPHA_OPAQUE )
403695b3 54 {
007d2de3
VZ
55 *opacity = c.Alpha()/255.;
56
57 // Remove the alpha before using GetAsString(wxC2S_HTML_SYNTAX) as it
58 // doesn't support colours with alpha channel.
59 c = wxColour(c.GetRGB());
403695b3 60 }
007d2de3 61 else // No alpha.
403695b3 62 {
007d2de3 63 *opacity = 1.;
403695b3 64 }
007d2de3
VZ
65
66 return c.GetAsString(wxC2S_HTML_SYNTAX);
403695b3
VZ
67}
68
007d2de3 69wxString wxPenString(wxColour c, int style = wxPENSTYLE_SOLID)
403695b3 70{
007d2de3
VZ
71 float opacity;
72 wxString s = wxT("stroke:") + Col2SVG(c, &opacity) + wxT("; ");
73
74 switch ( style )
403695b3 75 {
007d2de3
VZ
76 case wxPENSTYLE_SOLID:
77 s += wxString::Format(wxT("stroke-opacity:%s; "), NumStr(opacity));
78 break;
79 case wxPENSTYLE_TRANSPARENT:
80 s += wxT("stroke-opacity:0.0; ");
81 break;
82 default :
83 wxASSERT_MSG(false, wxT("wxSVGFileDC::Requested Pen Style not available"));
403695b3 84 }
007d2de3
VZ
85
86 return s;
87}
88
89wxString wxBrushString(wxColour c, int style = wxBRUSHSTYLE_SOLID)
90{
91 float opacity;
92 wxString s = wxT("fill:") + Col2SVG(c, &opacity) + wxT("; ");
93
94 switch ( style )
403695b3 95 {
007d2de3
VZ
96 case wxBRUSHSTYLE_SOLID:
97 s += wxString::Format(wxT("fill-opacity:%s; "), NumStr(opacity));
98 break;
99 case wxBRUSHSTYLE_TRANSPARENT:
100 s += wxT("fill-opacity:0.0; ");
101 break;
102 default :
103 wxASSERT_MSG(false, wxT("wxSVGFileDC::Requested Brush Style not available"));
403695b3 104 }
007d2de3 105
403695b3
VZ
106 return s;
107}
108
caef3ffa
VZ
109} // anonymous namespace
110
621b83d9 111// ----------------------------------------------------------
13cfc51d 112// wxSVGFileDCImpl
621b83d9
RR
113// ----------------------------------------------------------
114
888dde65 115IMPLEMENT_ABSTRACT_CLASS(wxSVGFileDCImpl, wxDC)
cdf3a589 116
13cfc51d
FM
117wxSVGFileDCImpl::wxSVGFileDCImpl( wxSVGFileDC *owner, const wxString &filename,
118 int width, int height, double dpi ) :
888dde65 119 wxDCImpl( owner )
d8416992 120 {
13cfc51d 121 Init( filename, width, height, dpi );
d8416992 122 }
cdf3a589 123
888dde65 124void wxSVGFileDCImpl::Init (const wxString &filename, int Width, int Height, double dpi)
cdf3a589 125{
13cfc51d
FM
126 m_width = Width;
127 m_height = Height;
cdf3a589 128
d8416992
RR
129 m_dpi = dpi;
130
13cfc51d 131 m_OK = true;
cdf3a589
CE
132
133 m_mm_to_pix_x = dpi/25.4;
134 m_mm_to_pix_y = dpi/25.4;
135
cdf3a589
CE
136 m_backgroundBrush = *wxTRANSPARENT_BRUSH;
137 m_textForegroundColour = *wxBLACK;
138 m_textBackgroundColour = *wxWHITE;
139 m_colour = wxColourDisplay();
140
141 m_pen = *wxBLACK_PEN;
142 m_font = *wxNORMAL_FONT;
143 m_brush = *wxWHITE_BRUSH;
144
13cfc51d 145 m_graphics_changed = true;
cdf3a589
CE
146
147 ////////////////////code here
148
13cfc51d 149 m_outfile = new wxFileOutputStream(filename);
a1b806b9 150 m_OK = m_outfile->IsOk();
cdf3a589
CE
151 if (m_OK)
152 {
13cfc51d
FM
153 m_filename = filename;
154 m_sub_images = 0;
155 wxString s;
1f4d7e44 156 s = wxT("<?xml version=\"1.0\" standalone=\"no\"?>") + wxString(wxT("\n"));
85b88942 157 write(s);
1f4d7e44 158 s = wxT("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\" ") + wxString(wxT("\n"));
85b88942 159 write(s);
1f4d7e44 160 s = wxT("\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\"> ") + wxString(wxT("\n"));
85b88942 161 write(s);
1f4d7e44 162 s = wxT("<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" ") + wxString(wxT("\n"));
85b88942 163 write(s);
caef3ffa 164 s.Printf( wxT(" width=\"%scm\" height=\"%scm\" viewBox=\"0 0 %d %d \"> \n"), NumStr(float(Width)/dpi*2.54), NumStr(float(Height)/dpi*2.54), Width, Height );
85b88942 165 write(s);
1f4d7e44 166 s = wxT("<title>SVG Picture created as ") + wxFileName(filename).GetFullName() + wxT(" </title>") + wxT("\n");
13cfc51d 167 write(s);
1f4d7e44 168 s = wxString (wxT("<desc>Picture generated by wxSVG ")) + wxSVGVersion + wxT(" </desc>")+ wxT("\n");
13cfc51d 169 write(s);
1f4d7e44 170 s = wxT("<g style=\"fill:black; stroke:black; stroke-width:1\">") + wxString(wxT("\n"));
85b88942 171 write(s);
cdf3a589 172 }
cdf3a589
CE
173}
174
888dde65 175wxSVGFileDCImpl::~wxSVGFileDCImpl()
cdf3a589 176{
13cfc51d 177 wxString s = wxT("</g> \n</svg> \n");
d8416992 178 write(s);
13cfc51d 179 delete m_outfile;
1bb592b8 180}
cdf3a589 181
888dde65 182void wxSVGFileDCImpl::DoGetSizeMM( int *width, int *height ) const
cdf3a589 183{
d8416992
RR
184 if (width)
185 *width = wxRound( (double)m_width / m_mm_to_pix_x );
13cfc51d 186
d8416992
RR
187 if (height)
188 *height = wxRound( (double)m_height / m_mm_to_pix_y );
1bb592b8 189}
13cfc51d 190
888dde65 191wxSize wxSVGFileDCImpl::GetPPI() const
cdf3a589 192{
d8416992 193 return wxSize( wxRound(m_dpi), wxRound(m_dpi) );
cdf3a589
CE
194}
195
888dde65 196void wxSVGFileDCImpl::DoDrawLine (wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
cdf3a589 197{
c9848e63 198 NewGraphicsIfNeeded();
13cfc51d 199 wxString s;
cdf3a589
CE
200 s.Printf ( wxT("<path d=\"M%d %d L%d %d\" /> \n"), x1,y1,x2,y2 );
201 if (m_OK)
202 {
85b88942 203 write(s);
cdf3a589 204 }
13cfc51d
FM
205 CalcBoundingBox(x1, y1);
206 CalcBoundingBox(x2, y2);
1bb592b8 207}
cdf3a589 208
888dde65 209void wxSVGFileDCImpl::DoDrawLines(int n, wxPoint points[], wxCoord xoffset , wxCoord yoffset )
cdf3a589 210{
13cfc51d 211 for ( int i = 1; i < n; i++ )
cdf3a589
CE
212 {
213 DoDrawLine ( points [i-1].x + xoffset, points [i-1].y + yoffset,
13cfc51d 214 points [ i ].x + xoffset, points [ i ].y + yoffset );
cdf3a589
CE
215 }
216}
217
888dde65 218void wxSVGFileDCImpl::DoDrawPoint (wxCoord x1, wxCoord y1)
cdf3a589
CE
219{
220 wxString s;
c9848e63 221 NewGraphicsIfNeeded();
1f4d7e44 222 s = wxT("<g style = \"stroke-linecap:round;\" > ") + wxString(wxT("\n"));
85b88942 223 write(s);
d8416992 224 DoDrawLine ( x1,y1,x1,y1 );
cdf3a589 225 s = wxT("</g>");
85b88942 226 write(s);
cdf3a589
CE
227}
228
888dde65 229void wxSVGFileDCImpl::DoDrawCheckMark(wxCoord x1, wxCoord y1, wxCoord width, wxCoord height)
cdf3a589 230{
13cfc51d 231 wxDCImpl::DoDrawCheckMark (x1,y1,width,height);
cdf3a589
CE
232}
233
888dde65 234void wxSVGFileDCImpl::DoDrawText(const wxString& text, wxCoord x1, wxCoord y1)
cdf3a589
CE
235{
236 DoDrawRotatedText(text, x1,y1,0.0);
cdf3a589
CE
237}
238
888dde65 239void wxSVGFileDCImpl::DoDrawRotatedText(const wxString& sText, wxCoord x, wxCoord y, double angle)
cdf3a589
CE
240{
241 //known bug; if the font is drawn in a scaled DC, it will not behave exactly as wxMSW
c9848e63 242 NewGraphicsIfNeeded();
cdf3a589
CE
243 wxString s, sTmp;
244
245 // calculate bounding box
13cfc51d 246 wxCoord w, h, desc;
cdf3a589
CE
247 DoGetTextExtent(sText, &w, &h, &desc);
248
249 double rad = DegToRad(angle);
250
251 // wxT("upper left") and wxT("upper right")
252 CalcBoundingBox(x, y);
216db41f 253 CalcBoundingBox((wxCoord)(x + w*cos(rad)), (wxCoord)(y - h*sin(rad)));
cdf3a589
CE
254
255 // wxT("bottom left") and wxT("bottom right")
216db41f 256 CalcBoundingBox((wxCoord)(x + h*sin(rad)), (wxCoord)(y + h*cos(rad)));
66815259 257 CalcBoundingBox((wxCoord)(x + h*sin(rad) + w*cos(rad)), (wxCoord)(y + h*cos(rad) - w*sin(rad)));
cdf3a589 258
04ee05f9 259 if (m_backgroundMode == wxBRUSHSTYLE_SOLID)
cdf3a589
CE
260 {
261 // draw background first
262 // just like DoDrawRectangle except we pass the text color to it and set the border to a 1 pixel wide text background
263
66815259 264 sTmp.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" "), x, y, w, h );
403695b3 265 s = sTmp + wxT("style=\"") + wxBrushString(m_textBackgroundColour);
85675f10 266 s += wxT("stroke-width:1; ") + wxPenString(m_textBackgroundColour);
403695b3 267 sTmp.Printf ( wxT("\" transform=\"rotate( %s %d %d ) \" />"), NumStr(-angle), x,y );
85675f10 268 s += sTmp + wxT("\n");
85b88942 269 write(s);
cdf3a589 270 }
66815259
VZ
271
272 // convert x,y to SVG text x,y (the coordinates of the text baseline)
273 x = (wxCoord)(x + (h-desc)*sin(rad));
274 y = (wxCoord)(y + (h-desc)*cos(rad));
275
cdf3a589
CE
276 //now do the text itself
277 s.Printf (wxT(" <text x=\"%d\" y=\"%d\" "),x,y );
3454ecd5 278
b2a1c6f5
VZ
279 sTmp = m_font.GetFaceName();
280 if (sTmp.Len() > 0) s += wxT("style=\"font-family:") + sTmp + wxT("; ");
85675f10 281 else s += wxT("style=\" ");
cdf3a589
CE
282
283 wxString fontweights [3] = { wxT("normal"), wxT("lighter"), wxT("bold") };
85675f10 284 s += wxT("font-weight:") + fontweights[m_font.GetWeight() - wxNORMAL] + wxT("; ");
3454ecd5 285
cdf3a589 286 wxString fontstyles [5] = { wxT("normal"), wxT("style error"), wxT("style error"), wxT("italic"), wxT("oblique") };
85675f10 287 s += wxT("font-style:") + fontstyles[m_font.GetStyle() - wxNORMAL] + wxT("; ");
3454ecd5 288
b2a1c6f5 289 sTmp.Printf (wxT("font-size:%dpt; "), m_font.GetPointSize() );
85675f10 290 s += sTmp;
403695b3 291 //text will be solid, unless alpha value isn't opaque in the foreground colour
85675f10 292 s += wxBrushString(m_textForegroundColour) + wxPenString(m_textForegroundColour);
caef3ffa 293 sTmp.Printf ( wxT("stroke-width:0;\" transform=\"rotate( %s %d %d ) \" >"), NumStr(-angle), x,y );
85675f10 294 s += sTmp + sText + wxT("</text> ") + wxT("\n");
cdf3a589
CE
295 if (m_OK)
296 {
85b88942 297 write(s);
cdf3a589 298 }
cdf3a589
CE
299}
300
888dde65 301void wxSVGFileDCImpl::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
cdf3a589 302{
13cfc51d 303 DoDrawRoundedRectangle(x, y, width, height, 0);
cdf3a589
CE
304}
305
888dde65 306void wxSVGFileDCImpl::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius )
cdf3a589
CE
307
308{
c9848e63 309 NewGraphicsIfNeeded();
13cfc51d 310 wxString s;
cdf3a589 311
caef3ffa
VZ
312 s.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" rx=\"%s\" "),
313 x, y, width, height, NumStr(radius) );
cdf3a589 314
85675f10 315 s += wxT(" /> \n");
85b88942 316 write(s);
cdf3a589 317
13cfc51d
FM
318 CalcBoundingBox(x, y);
319 CalcBoundingBox(x + width, y + height);
cdf3a589
CE
320}
321
89efaf2b
FM
322void wxSVGFileDCImpl::DoDrawPolygon(int n, wxPoint points[],
323 wxCoord xoffset, wxCoord yoffset,
324 wxPolygonFillMode fillStyle)
cdf3a589 325{
c9848e63 326 NewGraphicsIfNeeded();
13cfc51d
FM
327 wxString s, sTmp;
328 s = wxT("<polygon style=\"");
cdf3a589 329 if ( fillStyle == wxODDEVEN_RULE )
85675f10 330 s += wxT("fill-rule:evenodd; ");
cdf3a589 331 else
85675f10 332 s += wxT("fill-rule:nonzero; ");
cdf3a589 333
85675f10 334 s += wxT("\" \npoints=\"");
cdf3a589
CE
335
336 for (int i = 0; i < n; i++)
337 {
338 sTmp.Printf ( wxT("%d,%d"), points [i].x+xoffset, points[i].y+yoffset );
85675f10 339 s += sTmp + wxT("\n");
cdf3a589
CE
340 CalcBoundingBox ( points [i].x+xoffset, points[i].y+yoffset);
341 }
85675f10 342 s += wxT("\" /> \n");
85b88942 343 write(s);
cdf3a589
CE
344}
345
888dde65 346void wxSVGFileDCImpl::DoDrawEllipse (wxCoord x, wxCoord y, wxCoord width, wxCoord height)
cdf3a589
CE
347
348{
c9848e63 349 NewGraphicsIfNeeded();
cdf3a589 350
13cfc51d
FM
351 int rh = height /2;
352 int rw = width /2;
cdf3a589
CE
353
354 wxString s;
355 s.Printf ( wxT("<ellipse cx=\"%d\" cy=\"%d\" rx=\"%d\" ry=\"%d\" "), x+rw,y+rh, rw, rh );
85675f10 356 s += wxT(" /> \n");
cdf3a589 357
85b88942 358 write(s);
cdf3a589 359
13cfc51d
FM
360 CalcBoundingBox(x, y);
361 CalcBoundingBox(x + width, y + height);
cdf3a589
CE
362}
363
888dde65 364void wxSVGFileDCImpl::DoDrawArc(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc)
cdf3a589
CE
365{
366 /* Draws an arc of a circle, centred on (xc, yc), with starting point
367 (x1, y1) and ending at (x2, y2). The current pen is used for the outline
368 and the current brush for filling the shape.
369
370 The arc is drawn in an anticlockwise direction from the start point to
371 the end point.
372
373 Might be better described as Pie drawing */
374
c9848e63 375 NewGraphicsIfNeeded();
13cfc51d 376 wxString s;
cdf3a589
CE
377
378 // we need the radius of the circle which has two estimates
379 double r1 = sqrt ( double( (x1-xc)*(x1-xc) ) + double( (y1-yc)*(y1-yc) ) );
380 double r2 = sqrt ( double( (x2-xc)*(x2-xc) ) + double( (y2-yc)*(y2-yc) ) );
381
13cfc51d 382 wxASSERT_MSG( (fabs ( r2-r1 ) <= 3), wxT("wxSVGFileDC::DoDrawArc Error in getting radii of circle"));
cdf3a589
CE
383 if ( fabs ( r2-r1 ) > 3 ) //pixels
384 {
13cfc51d 385 s = wxT("<!--- wxSVGFileDC::DoDrawArc Error in getting radii of circle --> \n");
85b88942 386 write(s);
cdf3a589
CE
387 }
388
fb88ba48 389 double theta1 = atan2((double)(yc-y1),(double)(x1-xc));
3454ecd5 390 if ( theta1 < 0 ) theta1 = theta1 + M_PI * 2;
fb88ba48 391 double theta2 = atan2((double)(yc-y2), (double)(x2-xc));
3454ecd5 392 if ( theta2 < 0 ) theta2 = theta2 + M_PI * 2;
13cfc51d 393 if ( theta2 < theta1 ) theta2 = theta2 + M_PI *2;
cdf3a589 394
13cfc51d
FM
395 int fArc; // flag for large or small arc 0 means less than 180 degrees
396 if ( fabs(theta2 - theta1) > M_PI ) fArc = 1; else fArc = 0;
cdf3a589 397
13cfc51d 398 int fSweep = 0; // flag for sweep always 0
cdf3a589 399
caef3ffa
VZ
400 s.Printf ( wxT("<path d=\"M%d %d A%s %s 0.0 %d %d %d %d L%d %d z "),
401 x1,y1, NumStr(r1), NumStr(r2), fArc, fSweep, x2, y2, xc, yc );
cdf3a589
CE
402
403 // the z means close the path and fill
85675f10 404 s += wxT(" \" /> \n");
cdf3a589
CE
405
406
407 if (m_OK)
408 {
85b88942 409 write(s);
cdf3a589 410 }
cdf3a589
CE
411}
412
888dde65 413void wxSVGFileDCImpl::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea)
cdf3a589
CE
414{
415 /*
416 Draws an arc of an ellipse. The current pen is used for drawing the arc
417 and the current brush is used for drawing the pie. This function is
418 currently only available for X window and PostScript device contexts.
419
420 x and y specify the x and y coordinates of the upper-left corner of the
421 rectangle that contains the ellipse.
422
423 width and height specify the width and height of the rectangle that
424 contains the ellipse.
425
426 start and end specify the start and end of the arc relative to the
427 three-o'clock position from the center of the rectangle. Angles are
428 specified in degrees (360 is a complete circle). Positive values mean
429 counter-clockwise motion. If start is equal to end, a complete ellipse
430 will be drawn. */
431
432 //known bug: SVG draws with the current pen along the radii, but this does not happen in wxMSW
433
c9848e63 434 NewGraphicsIfNeeded();
cdf3a589 435
13cfc51d 436 wxString s;
cdf3a589 437 //radius
13cfc51d
FM
438 double rx = w / 2;
439 double ry = h / 2;
cdf3a589 440 // center
13cfc51d
FM
441 double xc = x + rx;
442 double yc = y + ry;
cdf3a589 443
13cfc51d
FM
444 double xs, ys, xe, ye;
445 xs = xc + rx * cos (DegToRad(sa));
446 xe = xc + rx * cos (DegToRad(ea));
447 ys = yc - ry * sin (DegToRad(sa));
448 ye = yc - ry * sin (DegToRad(ea));
cdf3a589
CE
449
450 ///now same as circle arc...
451
452 double theta1 = atan2(ys-yc, xs-xc);
453 double theta2 = atan2(ye-yc, xe-xc);
454
13cfc51d
FM
455 int fArc; // flag for large or small arc 0 means less than 180 degrees
456 if ( (theta2 - theta1) > 0 ) fArc = 1; else fArc = 0;
cdf3a589 457
13cfc51d
FM
458 int fSweep;
459 if ( fabs(theta2 - theta1) > M_PI) fSweep = 1; else fSweep = 0;
cdf3a589
CE
460
461 s.Printf ( wxT("<path d=\"M%d %d A%d %d 0.0 %d %d %d %d L %d %d z "),
462 int(xs), int(ys), int(rx), int(ry),
463 fArc, fSweep, int(xe), int(ye), int(xc), int(yc) );
464
85675f10 465 s += wxT(" \" /> \n");
cdf3a589
CE
466
467 if (m_OK)
468 {
85b88942 469 write(s);
cdf3a589 470 }
cdf3a589
CE
471}
472
888dde65 473void wxSVGFileDCImpl::DoGetTextExtent(const wxString& string, wxCoord *w, wxCoord *h, wxCoord *descent , wxCoord *externalLeading , const wxFont *font) const
cdf3a589
CE
474
475{
13cfc51d 476 wxScreenDC sDC;
cdf3a589
CE
477
478 sDC.SetFont (m_font);
479 if ( font != NULL ) sDC.SetFont ( *font );
480 sDC.GetTextExtent(string, w, h, descent, externalLeading );
cdf3a589
CE
481}
482
888dde65 483wxCoord wxSVGFileDCImpl::GetCharHeight() const
cdf3a589 484{
13cfc51d 485 wxScreenDC sDC;
cdf3a589
CE
486 sDC.SetFont (m_font);
487
b2a1c6f5 488 return sDC.GetCharHeight();
cdf3a589
CE
489
490}
491
888dde65 492wxCoord wxSVGFileDCImpl::GetCharWidth() const
cdf3a589 493{
13cfc51d 494 wxScreenDC sDC;
cdf3a589
CE
495 sDC.SetFont (m_font);
496
b2a1c6f5 497 return sDC.GetCharWidth();
cdf3a589
CE
498}
499
500
13cfc51d
FM
501// ----------------------------------------------------------
502// wxSVGFileDCImpl - set functions
503// ----------------------------------------------------------
504
888dde65 505void wxSVGFileDCImpl::SetBackground( const wxBrush &brush )
cdf3a589 506{
cdf3a589 507 m_backgroundBrush = brush;
cdf3a589
CE
508}
509
510
888dde65 511void wxSVGFileDCImpl::SetBackgroundMode( int mode )
cdf3a589
CE
512{
513 m_backgroundMode = mode;
cdf3a589
CE
514}
515
516
888dde65 517void wxSVGFileDCImpl::SetBrush(const wxBrush& brush)
cdf3a589 518{
13cfc51d 519 m_brush = brush;
cdf3a589 520
13cfc51d 521 m_graphics_changed = true;
cdf3a589
CE
522}
523
524
888dde65 525void wxSVGFileDCImpl::SetPen(const wxPen& pen)
cdf3a589
CE
526{
527 // width, color, ends, joins : currently implemented
528 // dashes, stipple : not implemented
13cfc51d 529 m_pen = pen;
3454ecd5 530
13cfc51d 531 m_graphics_changed = true;
cdf3a589
CE
532}
533
c9848e63 534void wxSVGFileDCImpl::NewGraphicsIfNeeded()
cdf3a589 535{
c9848e63
VZ
536 if ( !m_graphics_changed )
537 return;
538
539 m_graphics_changed = false;
540
cdf3a589 541 wxString s, sBrush, sPenCap, sPenJoin, sPenStyle, sLast, sWarn;
3454ecd5 542
b2a1c6f5 543 sBrush = wxT("</g>\n<g style=\"") + wxBrushString ( m_brush.GetColour(), m_brush.GetStyle() )
403695b3 544 + wxPenString(m_pen.GetColour(), m_pen.GetStyle());
3454ecd5 545
b2a1c6f5 546 switch ( m_pen.GetCap() )
cdf3a589
CE
547 {
548 case wxCAP_PROJECTING :
13cfc51d
FM
549 sPenCap = wxT("stroke-linecap:square; ");
550 break;
cdf3a589 551 case wxCAP_BUTT :
13cfc51d
FM
552 sPenCap = wxT("stroke-linecap:butt; ");
553 break;
cdf3a589
CE
554 case wxCAP_ROUND :
555 default :
13cfc51d 556 sPenCap = wxT("stroke-linecap:round; ");
b2a1c6f5
VZ
557 }
558
559 switch ( m_pen.GetJoin() )
cdf3a589
CE
560 {
561 case wxJOIN_BEVEL :
13cfc51d
FM
562 sPenJoin = wxT("stroke-linejoin:bevel; ");
563 break;
cdf3a589 564 case wxJOIN_MITER :
13cfc51d
FM
565 sPenJoin = wxT("stroke-linejoin:miter; ");
566 break;
cdf3a589
CE
567 case wxJOIN_ROUND :
568 default :
13cfc51d 569 sPenJoin = wxT("stroke-linejoin:round; ");
b2a1c6f5 570 }
cdf3a589 571
caef3ffa 572 sLast.Printf( wxT("stroke-width:%d\" \n transform=\"translate(%s %s) scale(%s %s)\">"),
403695b3 573 m_pen.GetWidth(), NumStr(m_logicalOriginX), NumStr(m_logicalOriginY), NumStr(m_scaleX), NumStr(m_scaleY) );
cdf3a589 574
1f4d7e44 575 s = sBrush + sPenCap + sPenJoin + sPenStyle + sLast + wxT("\n") + sWarn;
85b88942 576 write(s);
cdf3a589
CE
577}
578
579
888dde65 580void wxSVGFileDCImpl::SetFont(const wxFont& font)
cdf3a589
CE
581
582{
13cfc51d 583 m_font = font;
cdf3a589
CE
584}
585
cdf3a589 586// export a bitmap as a raster image in png
888dde65 587bool wxSVGFileDCImpl::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
13cfc51d 588 wxDC* source, wxCoord xsrc, wxCoord ysrc,
89efaf2b 589 wxRasterOperationMode logicalFunc /*= wxCOPY*/, bool useMask /*= false*/,
13cfc51d 590 wxCoord /*xsrcMask = -1*/, wxCoord /*ysrcMask = -1*/)
cdf3a589 591{
cdf3a589
CE
592 if (logicalFunc != wxCOPY)
593 {
13cfc51d
FM
594 wxASSERT_MSG(false, wxT("wxSVGFileDC::DoBlit Call requested nonCopy mode; this is not possible"));
595 return false;
cdf3a589 596 }
13cfc51d 597 if (useMask != false)
cdf3a589 598 {
13cfc51d
FM
599 wxASSERT_MSG(false, wxT("wxSVGFileDC::DoBlit Call requested false mask; this is not possible"));
600 return false;
cdf3a589 601 }
13cfc51d 602 wxBitmap myBitmap (width, height);
cdf3a589
CE
603 wxMemoryDC memDC;
604 memDC.SelectObject( myBitmap );
605 memDC.Blit(0, 0, width, height, source, xsrc, ysrc);
606 memDC.SelectObject( wxNullBitmap );
607 DoDrawBitmap(myBitmap, xdest, ydest);
13cfc51d 608 return false;
cdf3a589
CE
609}
610
888dde65 611void wxSVGFileDCImpl::DoDrawIcon(const class wxIcon & myIcon, wxCoord x, wxCoord y)
cdf3a589 612{
13cfc51d 613 wxBitmap myBitmap (myIcon.GetWidth(), myIcon.GetHeight() );
cdf3a589
CE
614 wxMemoryDC memDC;
615 memDC.SelectObject( myBitmap );
616 memDC.DrawIcon(myIcon,0,0);
617 memDC.SelectObject( wxNullBitmap );
618 DoDrawBitmap(myBitmap, x, y);
cdf3a589
CE
619}
620
888dde65 621void wxSVGFileDCImpl::DoDrawBitmap(const class wxBitmap & bmp, wxCoord x, wxCoord y , bool WXUNUSED(bTransparent) /*=0*/ )
cdf3a589 622{
c9848e63 623 NewGraphicsIfNeeded();
cdf3a589 624
13cfc51d 625 wxString sTmp, s, sPNG;
79d8d561
VS
626 if ( wxImage::FindHandler(wxBITMAP_TYPE_PNG) == NULL )
627 wxImage::AddHandler(new wxPNGHandler);
cdf3a589 628
3454ecd5 629// create suitable file name
cdf3a589
CE
630 sTmp.Printf ( wxT("_image%d.png"), m_sub_images);
631 sPNG = m_filename.BeforeLast(wxT('.')) + sTmp;
632 while (wxFile::Exists(sPNG) )
633 {
13cfc51d 634 m_sub_images ++;
cdf3a589
CE
635 sTmp.Printf ( wxT("_image%d.png"), m_sub_images);
636 sPNG = m_filename.BeforeLast(wxT('.')) + sTmp;
637 }
3454ecd5 638
cdf3a589 639//create copy of bitmap (wxGTK doesn't like saving a constant bitmap)
13cfc51d 640 wxBitmap myBitmap = bmp;
cdf3a589
CE
641//save it
642 bool bPNG_OK = myBitmap.SaveFile(sPNG,wxBITMAP_TYPE_PNG);
643
ddabd45b
CE
644// reference the bitmap from the SVG doc
645// only use filename & ext
646 sPNG = sPNG.AfterLast(wxFileName::GetPathSeparator());
647
13cfc51d 648// reference the bitmap from the SVG doc
cdf3a589
CE
649 int w = myBitmap.GetWidth();
650 int h = myBitmap.GetHeight();
651 sTmp.Printf ( wxT(" <image x=\"%d\" y=\"%d\" width=\"%dpx\" height=\"%dpx\" "), x,y,w,h );
85675f10 652 s += sTmp;
cdf3a589 653 sTmp.Printf ( wxT(" xlink:href=\"%s\"> \n"), sPNG.c_str() );
85675f10 654 s += sTmp + wxT("<title>Image from wxSVG</title> </image>") + wxT("\n");
3454ecd5 655
cdf3a589
CE
656 if (m_OK && bPNG_OK)
657 {
85b88942 658 write(s);
cdf3a589 659 }
a1b806b9 660 m_OK = m_outfile->IsOk() && bPNG_OK;
cdf3a589
CE
661}
662
888dde65 663void wxSVGFileDCImpl::write(const wxString &s)
621b83d9 664{
6243633c 665 const wxCharBuffer buf = s.utf8_str();
621b83d9 666 m_outfile->Write(buf, strlen((const char *)buf));
a1b806b9 667 m_OK = m_outfile->IsOk();
621b83d9 668}
cdf3a589 669
621b83d9 670
cdf3a589
CE
671#ifdef __BORLANDC__
672#pragma warn .rch
673#pragma warn .ccc
674#endif
8e10778e 675
b0fc907f
VZ
676#endif // wxUSE_SVG
677