1 // Copyright (C) 2012-2019 The VPaint Developers.
2 // See the COPYRIGHT file at the top-level directory of this distribution
3 // and at https://github.com/dalboris/vpaint/blob/master/COPYRIGHT
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #include "Layer.h"
18 
19 #include "Background/Background.h"
20 #include "VectorAnimationComplex/VAC.h"
21 #include "XmlStreamReader.h"
22 #include "XmlStreamWriter.h"
23 
Layer(NoInit_)24 Layer::Layer(NoInit_)
25 {
26 
27 }
28 
init_(Background * background,VectorAnimationComplex::VAC * vac,const QString & layerName,bool isVisible)29 void Layer::init_(
30         Background * background,
31         VectorAnimationComplex::VAC * vac,
32         const QString & layerName,
33         bool isVisible)
34 {
35     background_ = background;
36     vac_ = vac;
37     name_ = layerName;
38     isVisible_ = isVisible;
39 
40     connect(background_, SIGNAL(changed()), this, SIGNAL(changed()));
41     connect(background_, SIGNAL(checkpoint()), this, SIGNAL(checkpoint()));
42 
43     connect(vac_, SIGNAL(changed()), this, SIGNAL(changed()));
44     connect(vac_, SIGNAL(checkpoint()), this, SIGNAL(checkpoint()));
45     connect(vac_, SIGNAL(needUpdatePicking()), this, SIGNAL(needUpdatePicking()));
46     connect(vac_, SIGNAL(selectionChanged()), this, SIGNAL(selectionChanged()));
47 }
48 
Layer(const QString & layerName)49 Layer::Layer(const QString & layerName)
50 {
51     init_(new Background(this),
52           new VectorAnimationComplex::VAC(),
53           layerName,
54           true);
55 }
56 
~Layer()57 Layer::~Layer()
58 {
59     delete vac_;
60 }
61 
clone()62 Layer * Layer::clone()
63 {
64     // Two previous attempts at implementing this resulted
65     // in bugs. The first is because I called
66     //     new Background(background())
67     // instead of
68     //     new Background(*background())
69     // And the second because new Background(this) was called
70     // in a constructor before "this" was properly initialized,
71     // that is, parent-child relationship were messed up.
72     // The conclusion is that using copy-constructor is much
73     // trickier than the "clone" idiom, which should be preferred
74     // based on this experience: it is much less bug-prone when dealing
75     // with pointer-like objects with identity.
76     //
77 
78     Layer * res = new Layer(NoInit_());
79     res->init_(new Background(*background(), res),
80                vac_->clone(),
81                name_,
82                isVisible_);
83     return res;
84 }
85 
stringType()86 QString Layer::stringType()
87 {
88     return "Layer";
89 }
90 
draw(Time time,ViewSettings & viewSettings)91 void Layer::draw(Time time, ViewSettings & viewSettings)
92 {
93     // Draw the VAC only. Drawing the background is handled by View.
94     if (isVisible()) {
95         vac()->draw(time, viewSettings);
96     }
97 }
98 
drawPick(Time time,ViewSettings & viewSettings)99 void Layer::drawPick(Time time, ViewSettings & viewSettings)
100 {
101     if (isVisible()) {
102         vac()->drawPick(time, viewSettings);
103     }
104 }
105 
setHoveredObject(Time time,int id)106 void Layer::setHoveredObject(Time time, int id)
107 {
108     vac()->setHoveredObject(time, id);
109 }
110 
setNoHoveredObject()111 void Layer::setNoHoveredObject()
112 {
113     vac()->setNoHoveredObject();
114 }
115 
select(Time time,int id)116 void Layer::select(Time time, int id)
117 {
118     vac()->select(time, id);
119 }
120 
deselect(Time time,int id)121 void Layer::deselect(Time time, int id)
122 {
123     vac()->deselect(time, id);
124 }
125 
toggle(Time time,int id)126 void Layer::toggle(Time time, int id)
127 {
128     vac()->toggle(time, id);
129 }
130 
deselectAll(Time time)131 void Layer::deselectAll(Time time)
132 {
133     vac()->deselectAll(time);
134 }
135 
deselectAll()136 void Layer::deselectAll()
137 {
138     vac()->deselectAll();
139 }
140 
invertSelection()141 void Layer::invertSelection()
142 {
143     vac()->invertSelection();
144 }
145 
read(XmlStreamReader & xml)146 void Layer::read(XmlStreamReader & xml)
147 {
148     // Name
149     name_ = "Layer";
150     if(xml.attributes().hasAttribute("name"))
151     {
152         name_ = xml.attributes().value("name").toString();
153     }
154 
155     // Visible
156     isVisible_ = true;
157     if(xml.attributes().hasAttribute("visible"))
158     {
159         QString value = xml.attributes().value("visible").toString();
160         if (value == "true")
161         {
162             isVisible_ = true;
163         }
164         else if (value == "false")
165         {
166             isVisible_ = false;
167         }
168     }
169 
170     while (xml.readNextStartElement())
171     {
172         if (xml.name() == "background")
173         {
174             background()->read(xml);
175         }
176         else if (xml.name() == "objects")
177         {
178             vac()->read(xml);
179         }
180         else
181         {
182             xml.skipCurrentElement();
183         }
184     }
185 
186     emit needUpdatePicking();
187     emit changed();
188     emit selectionChanged();
189     emit layerAttributesChanged();
190 }
191 
write(XmlStreamWriter & xml)192 void Layer::write(XmlStreamWriter & xml)
193 {
194     // Name
195     xml.writeAttribute("name", name());
196 
197     // Visible
198     xml.writeAttribute("visible", isVisible() ? "true" : "false");
199 
200     // Background
201     xml.writeStartElement("background");
202     background()->write(xml);
203     xml.writeEndElement();
204 
205     // Vector animation complex
206     xml.writeStartElement("objects");
207     vac()->write(xml);
208     xml.writeEndElement();
209 }
210 
name() const211 QString Layer::name() const
212 {
213     return name_;
214 }
215 
setName(const QString & newName)216 void Layer::setName(const QString & newName)
217 {
218     if (newName != name_)
219     {
220         name_ = newName;
221         emit layerAttributesChanged();
222     }
223 }
224 
isVisible() const225 bool Layer::isVisible() const
226 {
227     return isVisible_;
228 }
229 
setVisible(bool b)230 void Layer::setVisible(bool b)
231 {
232     if (b != isVisible_)
233     {
234         isVisible_ = b;
235         emit changed();
236         emit needUpdatePicking();
237         emit layerAttributesChanged();
238     }
239 }
240 
exportSVG_(Time t,QTextStream & out)241 void Layer::exportSVG_(Time t, QTextStream & out)
242 {
243     // This function does not export the background, because the API
244     // for Background::exportSVG() requires the canvas' size, which
245     // we don't know here.
246     //
247     // Therefore, it is the responsibility of clients to manually call
248     // background()->exportSVG beforehand if they wish.
249     //
250     // XXX We should improve this ugly design
251     //
252     vac()->exportSVG(t, out);
253 }
254