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