1 //////////////////////////////////////////////////////////////////////////////
2 // Name:        svgctrl.cpp
3 // Purpose:     svg control widget
4 // Author:      Alex Thuering
5 // Created:     2005/05/07
6 // RCS-ID:      $Id: svgctrl.cpp,v 1.20 2016/05/07 10:18:27 ntalex Exp $
7 // Copyright:   (c) 2005 Alex Thuering
8 // Licence:     wxWindows licence
9 //////////////////////////////////////////////////////////////////////////////
10 
11 #include "svgctrl.h"
12 #include <SVGSVGElement.h>
13 #include <wx/wx.h>
14 
IMPLEMENT_ABSTRACT_CLASS(wxSVGCtrlBase,wxControl)15 IMPLEMENT_ABSTRACT_CLASS(wxSVGCtrlBase, wxControl)
16 
17 BEGIN_EVENT_TABLE(wxSVGCtrlBase, wxControl)
18 	EVT_PAINT(wxSVGCtrlBase::OnPaint)
19 	EVT_SIZE(wxSVGCtrlBase::OnResize)
20 	EVT_ERASE_BACKGROUND(wxSVGCtrlBase::OnEraseBackground)
21 END_EVENT_TABLE()
22 
23 wxSVGCtrlBase::wxSVGCtrlBase() {
24 	Init();
25 }
26 
wxSVGCtrlBase(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxValidator & validator,const wxString & name)27 wxSVGCtrlBase::wxSVGCtrlBase(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style,
28 		const wxValidator& validator, const wxString& name) {
29 	Init();
30 	Create(parent, id, pos, size, style, validator, name);
31 }
32 
Init()33 void wxSVGCtrlBase::Init() {
34 	m_doc = NULL;
35 	m_docDelete = false;
36 	m_repaint = false;
37 	m_fitToFrame = true;
38 }
39 
~wxSVGCtrlBase()40 wxSVGCtrlBase::~wxSVGCtrlBase() {
41 	Clear();
42 }
43 
Clear()44 void wxSVGCtrlBase::Clear() {
45 	if (m_doc && m_docDelete)
46 		delete m_doc;
47 	m_doc = NULL;
48 	m_docDelete = false;
49 }
50 
SetSVG(wxSVGDocument * doc)51 void wxSVGCtrlBase::SetSVG(wxSVGDocument* doc) {
52 	Clear();
53 	m_doc = doc;
54 }
55 
Load(const wxString & filename)56 bool wxSVGCtrlBase::Load(const wxString& filename) {
57 	if (!m_doc) {
58 		m_doc = new wxSVGDocument;
59 		m_docDelete = true;
60 	}
61 
62 	if (!m_doc->Load(filename)) {
63 		return false;
64 	}
65 	Refresh();
66 	return true;
67 }
68 
Refresh(bool eraseBackground,const wxRect * rect)69 void wxSVGCtrlBase::Refresh(bool eraseBackground, const wxRect* rect) {
70 	if (rect && m_repaintRect.width > 0 && m_repaintRect.height > 0) {
71 		int x2 = wxMax(m_repaintRect.x+m_repaintRect.width, rect->x+rect->width);
72 		int y2 = wxMax(m_repaintRect.y+m_repaintRect.height, rect->y+rect->height);
73 		m_repaintRect.x = wxMin(m_repaintRect.x, rect->x);
74 		m_repaintRect.y = wxMin(m_repaintRect.y, rect->y);
75 		m_repaintRect.width = x2 - m_repaintRect.x;
76 		m_repaintRect.height = y2 - m_repaintRect.y;
77 	} else
78 		m_repaintRect = rect && !m_repaint ? *rect : wxRect();
79 	m_repaint = true;
80 	wxControl::Refresh(eraseBackground, rect);
81 }
82 
Refresh(const wxSVGRect * rect)83 void wxSVGCtrlBase::Refresh(const wxSVGRect* rect) {
84 	if (!rect || rect->IsEmpty())
85 		Refresh(true, NULL);
86 	else {
87 		wxRect winRect((int) (rect->GetX() * GetScaleX()), (int) (rect->GetY() * GetScaleY()),
88 				(int) (rect->GetWidth() * GetScaleX()), (int) (rect->GetHeight() * GetScaleY()));
89 		RefreshRect(winRect);
90 	}
91 }
92 
OnPaint(wxPaintEvent & event)93 void wxSVGCtrlBase::OnPaint(wxPaintEvent& event) {
94 	if (!m_doc)
95 		m_buffer = wxBitmap();
96 	else if (m_repaint)
97 		RepaintBuffer();
98 	wxPaintDC dc(this);
99 
100 #ifdef __WXMSW__
101 	int w = GetClientSize().GetWidth();
102 	int h = GetClientSize().GetHeight();
103 	dc.SetPen(*wxTRANSPARENT_PEN);
104 	dc.DrawRectangle(m_buffer.GetWidth(), 0, w - m_buffer.GetWidth(), h);
105 	dc.DrawRectangle(0, m_buffer.GetHeight(), m_buffer.GetWidth(), h - m_buffer.GetHeight());
106 #endif
107 	if (m_buffer.IsOk())
108 		dc.DrawBitmap(m_buffer, 0, 0);
109 }
110 
RepaintBuffer()111 void wxSVGCtrlBase::RepaintBuffer() {
112 	int w = -1, h = -1;
113 	if (m_fitToFrame)
114 		GetClientSize(&w, &h);
115 
116 	//wxDateTime time = wxDateTime::UNow();
117 
118 	if (m_repaintRect.width > 0 && m_repaintRect.height > 0
119 			&& (m_repaintRect.width < 2 * m_buffer.GetWidth() / 3
120 					|| m_repaintRect.height < 2 * m_buffer.GetHeight() / 3)) {
121 		m_repaintRect.x = wxMax(m_repaintRect.x, 0);
122 		m_repaintRect.y = wxMax(m_repaintRect.y, 0);
123 		wxSVGRect rect(m_repaintRect.x / GetScaleX(), m_repaintRect.y / GetScaleY(),
124 				m_repaintRect.width / GetScaleX(), m_repaintRect.height / GetScaleY());
125 		wxBitmap bitmap = m_doc->Render(w, h, &rect);
126 		wxMemoryDC dc;
127 		dc.SelectObject(m_buffer);
128 		dc.DrawBitmap(bitmap, m_repaintRect.x, m_repaintRect.y);
129 	} else
130 		m_buffer = wxBitmap(m_doc->Render(w, h));
131 
132 	m_repaintRect = wxRect();
133 
134 	//wxLogError(wxDateTime::UNow().Subtract(time).Format(wxT("draw buffer %l ms")));
135 }
136 
GetScale() const137 double wxSVGCtrlBase::GetScale() const {
138 	if (m_doc)
139 		return m_doc->GetScale();
140 	return 1;
141 }
142 
GetScaleX() const143 double wxSVGCtrlBase::GetScaleX() const {
144 	if (m_doc)
145 		return m_doc->GetScaleX();
146 	return 1;
147 }
148 
GetScaleY() const149 double wxSVGCtrlBase::GetScaleY() const {
150 	if (m_doc)
151 		return m_doc->GetScaleY();
152 	return 1;
153 }
154 
MoveElement(wxSVGElement * elem,double Xposition,double Yposition)155 void wxSVGCtrlBase::MoveElement(wxSVGElement* elem, double Xposition, double Yposition) {
156 	if (elem->GetDtd() == wxSVG_RECT_ELEMENT) {
157 		double stroke_width = 0;
158   		if (((wxSVGRectElement*)elem)->GetStroke().GetPaintType() != wxSVG_PAINTTYPE_NONE)
159   			stroke_width = ((wxSVGRectElement*)elem)->GetStrokeWidth();
160 		wxSVGMatrix CTM = ((wxSVGRectElement*)elem)->GetCTM();
161 		double denom = CTM.GetB()*CTM.GetC() - CTM.GetA()*CTM.GetD();
162 		double x = (CTM.GetC()*(Yposition-CTM.GetF()) - CTM.GetD()*(Xposition-CTM.GetE())) / denom;
163 		double y = (CTM.GetB()*(Xposition-CTM.GetE()) - CTM.GetA()*(Yposition-CTM.GetF())) / denom;
164 		wxSVGLength Xvalue(x + stroke_width / 2);
165 		wxSVGLength Yvalue(y + stroke_width / 2);
166 		((wxSVGRectElement*)elem)->SetX(Xvalue);
167 		((wxSVGRectElement*)elem)->SetY(Yvalue);
168 	} else {
169 		wxSVGTransformable* element = wxSVGTransformable::GetSVGTransformable(*elem);
170         wxSVGMatrix CTM = element->GetCTM();
171 		wxSVGTransformList transforms = element->GetTransform().GetBaseVal();
172 		wxSVGMatrix matrix = transforms[(int)transforms.Count()-1].GetMatrix();
173 		wxSVGRect bbox = element->GetResultBBox(wxSVG_COORDINATES_VIEWPORT);
174 		wxSVGPoint LeftUp = wxSVGPoint(bbox.GetX(), bbox.GetY());
175 		wxSVGMatrix new_matrix = wxSVGMatrix();
176 		new_matrix = new_matrix.Translate(Xposition - LeftUp.GetX(), Yposition - LeftUp.GetY());
177 		new_matrix = matrix.Multiply(CTM.Inverse().Multiply(new_matrix.Multiply(CTM)));
178 		transforms[transforms.Count()-1].SetMatrix(new_matrix);
179 		element->SetTransform(transforms);
180 	}
181 }
182 
IMPLEMENT_ABSTRACT_CLASS(wxSVGCtrl,wxSVGCtrlBase)183 IMPLEMENT_ABSTRACT_CLASS(wxSVGCtrl, wxSVGCtrlBase)
184 wxSVGCtrl::wxSVGCtrl() {
185 	// nothing to do
186 }
187 
wxSVGCtrl(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxString & name)188 wxSVGCtrl::wxSVGCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style,
189 		const wxString& name) {
190  	Create( parent,  id,  pos, size, style, wxDefaultValidator, name);
191 }
192 
GetScreenCTM() const193 wxSVGMatrix wxSVGCtrlBase::GetScreenCTM() const {
194 	if (m_doc && m_doc->GetRootElement())
195 		return m_doc->GetRootElement()->GetScreenCTM();
196 	return wxSVGMatrix();
197 }
198