All Classes Namespaces Functions Variables Enumerations Properties Pages
layer.cpp
1 /*
2 
3 Pencil2D - Traditional Animation Software
4 Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
5 Copyright (C) 2012-2020 Matthew Chiawen Chang
6 
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; version 2 of the License.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15 
16 */
17 #include "layer.h"
18 
19 #include <QApplication>
20 #include <QDebug>
21 #include <QSettings>
22 #include <QPainter>
23 #include <QDomElement>
24 #include "keyframe.h"
25 #include "object.h"
26 #include "timelinecells.h"
27 
28 
29 // Used to sort the selected frames list
30 bool sortAsc(int left, int right)
31 {
32  return left < right;
33 }
34 
35 Layer::Layer(Object* object, LAYER_TYPE eType) : QObject(object)
36 {
37  Q_ASSERT(eType != UNDEFINED);
38 
39  mObject = object;
40  meType = eType;
41  mName = QString(tr("Undefined Layer"));
42 
43  mId = object->getUniqueLayerID();
44 }
45 
46 Layer::~Layer()
47 {
48  for (auto it : mKeyFrames)
49  {
50  KeyFrame* pKeyFrame = it.second;
51  delete pKeyFrame;
52  }
53  mKeyFrames.clear();
54 }
55 
56 void Layer::setObject(Object* obj)
57 {
58  Q_ASSERT(obj);
59  mObject = obj;
60  setParent(mObject);
61  mId = mObject->getUniqueLayerID();
62 }
63 
64 void Layer::foreachKeyFrame(std::function<void(KeyFrame*)> action) const
65 {
66  for (auto pair : mKeyFrames)
67  {
68  action(pair.second);
69  }
70 }
71 
72 bool Layer::keyExists(int position) const
73 {
74  return (mKeyFrames.find(position) != mKeyFrames.end());
75 }
76 
77 KeyFrame* Layer::getKeyFrameAt(int position) const
78 {
79  auto it = mKeyFrames.find(position);
80  if (it == mKeyFrames.end())
81  {
82  return nullptr;
83  }
84  return it->second;
85 }
86 
87 KeyFrame* Layer::getLastKeyFrameAtPosition(int position) const
88 {
89  if (position < 1)
90  {
91  position = 1;
92  }
93  auto it = mKeyFrames.lower_bound(position);
94  if (it == mKeyFrames.end())
95  {
96  return nullptr;
97  }
98  return it->second;
99 }
100 
101 int Layer::getPreviousKeyFramePosition(int position) const
102 {
103  auto it = mKeyFrames.upper_bound(position);
104  if (it == mKeyFrames.end())
105  {
106  return firstKeyFramePosition();
107  }
108  return it->first;
109 }
110 
111 int Layer::getNextKeyFramePosition(int position) const
112 {
113  // workaround: bug with lower_bound?
114  // when position is before the first frame it == mKeyFrames.end() for some reason
115  if (position < firstKeyFramePosition())
116  {
117  return firstKeyFramePosition();
118  }
119 
120  auto it = mKeyFrames.lower_bound(position);
121  if (it == mKeyFrames.end())
122  {
123  return getMaxKeyFramePosition();
124  }
125 
126  if (it != mKeyFrames.begin())
127  {
128  --it;
129  }
130  return it->first;
131 }
132 
133 int Layer::getPreviousFrameNumber(int position, bool isAbsolute) const
134 {
135  int prevNumber;
136 
137  if (isAbsolute)
138  prevNumber = getPreviousKeyFramePosition(position);
139  else
140  prevNumber = position - 1;
141 
142  if (prevNumber >= position)
143  {
144  return -1; // There is no previous keyframe
145  }
146  return prevNumber;
147 }
148 
149 int Layer::getNextFrameNumber(int position, bool isAbsolute) const
150 {
151  int nextNumber;
152 
153  if (isAbsolute)
154  nextNumber = getNextKeyFramePosition(position);
155  else
156  nextNumber = position + 1;
157 
158  if (nextNumber <= position)
159  return -1; // There is no next keyframe
160 
161  return nextNumber;
162 }
163 
164 int Layer::firstKeyFramePosition() const
165 {
166  if (!mKeyFrames.empty())
167  {
168  return mKeyFrames.rbegin()->first; // rbegin is the lowest key frame position
169  }
170  return 0;
171 }
172 
173 int Layer::getMaxKeyFramePosition() const
174 {
175  if (!mKeyFrames.empty())
176  {
177  return mKeyFrames.begin()->first; // begin is the highest key frame position
178  }
179  return 0;
180 }
181 
182 bool Layer::addNewKeyFrameAt(int position)
183 {
184  if (position <= 0) return false;
185 
186  KeyFrame* key = createKeyFrame(position, mObject);
187  return addKeyFrame(position, key);
188 }
189 
190 bool Layer::addKeyFrame(int position, KeyFrame* pKeyFrame)
191 {
192  Q_ASSERT(position > 0);
193  auto it = mKeyFrames.find(position);
194  if (it != mKeyFrames.end())
195  {
196  return false;
197  }
198 
199  pKeyFrame->setPos(position);
200  mKeyFrames.insert(std::make_pair(position, pKeyFrame));
201 
202  return true;
203 }
204 
205 bool Layer::removeKeyFrame(int position)
206 {
207  auto frame = getKeyFrameWhichCovers(position);
208  if (frame)
209  {
210  mKeyFrames.erase(frame->pos());
211  delete frame;
212  }
213  return true;
214 }
215 
216 bool Layer::moveKeyFrameForward(int position)
217 {
218  return swapKeyFrames(position, position + 1);
219 }
220 
221 bool Layer::moveKeyFrameBackward(int position)
222 {
223  if (position != 1)
224  {
225  return swapKeyFrames(position, position - 1);
226  }
227  return true;
228 }
229 
230 bool Layer::swapKeyFrames(int position1, int position2) //Current behaviour, need to refresh the swapped cels
231 {
232  bool keyPosition1 = false;
233  bool keyPosition2 = false;
234  KeyFrame* pFirstFrame = nullptr;
235  KeyFrame* pSecondFrame = nullptr;
236 
237  if (keyExists(position1))
238  {
239  auto firstFrame = mKeyFrames.find(position1);
240  pFirstFrame = firstFrame->second;
241 
242  mKeyFrames.erase(position1);
243 
244  keyPosition1 = true;
245  }
246 
247  if (keyExists(position2))
248  {
249  auto secondFrame = mKeyFrames.find(position2);
250  pSecondFrame = secondFrame->second;
251 
252  mKeyFrames.erase(position2);
253 
254  keyPosition2 = true;
255  }
256 
257  if (keyPosition2)
258  {
259  pSecondFrame->setPos(position1);
260  mKeyFrames.insert(std::make_pair(position1, pSecondFrame));
261  }
262  else if (position1 == 1)
263  {
264  addNewKeyFrameAt(position1);
265  }
266 
267  if (keyPosition1)
268  {
269  pFirstFrame->setPos(position2);
270  mKeyFrames.insert(std::make_pair(position2, pFirstFrame));
271  }
272  else if (position2 == 1)
273  {
274  addNewKeyFrameAt(position2);
275  }
276 
277  if (pFirstFrame)
278  pFirstFrame->modification();
279 
280  if (pSecondFrame)
281  pSecondFrame->modification();
282 
283  return true;
284 }
285 
286 bool Layer::loadKey(KeyFrame* pKey)
287 {
288  auto it = mKeyFrames.find(pKey->pos());
289  if (it != mKeyFrames.end())
290  {
291  delete it->second;
292  mKeyFrames.erase(it);
293  }
294  mKeyFrames.emplace(pKey->pos(), pKey);
295  return true;
296 }
297 
298 Status Layer::save(const QString& sDataFolder, QStringList& attachedFiles, ProgressCallback progressStep)
299 {
300  DebugDetails dd;
301  dd << __FUNCTION__;
302 
303  bool ok = true;
304 
305  for (auto pair : mKeyFrames)
306  {
307  KeyFrame* keyFrame = pair.second;
308  Status st = saveKeyFrameFile(keyFrame, sDataFolder);
309  if (st.ok())
310  {
311  //qDebug() << "Layer [" << name() << "] FN=" << keyFrame->fileName();
312  if (!keyFrame->fileName().isEmpty())
313  attachedFiles.append(keyFrame->fileName());
314  }
315  else
316  {
317  ok = false;
318  dd.collect(st.details());
319  dd << QString("- Keyframe[%1] failed to save").arg(keyFrame->pos());
320  }
321  progressStep();
322  }
323  if (!ok)
324  {
325  return Status(Status::FAIL, dd);
326  }
327  return Status::OK;
328 }
329 
330 void Layer::setModified(int position, bool modified)
331 {
332  KeyFrame* key = getKeyFrameAt(position);
333  if (key)
334  {
335  key->setModified(modified);
336  }
337 }
338 
339 bool Layer::isFrameSelected(int position) const
340 {
341  KeyFrame* keyFrame = getKeyFrameWhichCovers(position);
342  if (keyFrame)
343  {
344  return mSelectedFrames_byLast.contains(keyFrame->pos());
345  }
346  return false;
347 }
348 
349 void Layer::setFrameSelected(int position, bool isSelected)
350 {
351  KeyFrame* keyFrame = getKeyFrameWhichCovers(position);
352  if (keyFrame != nullptr)
353  {
354  int startPosition = keyFrame->pos();
355 
356  if (isSelected && !mSelectedFrames_byLast.contains(startPosition))
357  {
358  // Add the selected frame to the lists
359  mSelectedFrames_byLast.insert(0, startPosition);
360  mSelectedFrames_byPosition.append(startPosition);
361 
362  // We need to keep the list of selected frames sorted
363  // in order to easily handle their movement
364  std::sort(mSelectedFrames_byPosition.begin(), mSelectedFrames_byPosition.end(), sortAsc);
365  }
366  else if (!isSelected)
367  {
368  // Remove the selected frame from the lists
369  int iLast = mSelectedFrames_byLast.indexOf(startPosition);
370  mSelectedFrames_byLast.removeAt(iLast);
371 
372  int iPos = mSelectedFrames_byPosition.indexOf(startPosition);
373  mSelectedFrames_byPosition.removeAt(iPos);
374  }
375  keyFrame->setSelected(isSelected);
376  }
377 }
378 
379 void Layer::toggleFrameSelected(int position, bool allowMultiple)
380 {
381  bool wasSelected = isFrameSelected(position);
382 
383  if (!allowMultiple)
384  {
385  deselectAll();
386  }
387 
388  setFrameSelected(position, !wasSelected);
389 }
390 
391 void Layer::extendSelectionTo(int position)
392 {
393  if (mSelectedFrames_byLast.count() > 0)
394  {
395  int lastSelected = mSelectedFrames_byLast[0];
396  int startPos;
397  int endPos;
398 
399  if (lastSelected < position)
400  {
401  startPos = lastSelected;
402  endPos = position;
403  }
404  else
405  {
406  startPos = position;
407  endPos = lastSelected;
408  }
409 
410  int i = startPos;
411  while (i <= endPos)
412  {
413  setFrameSelected(i, true);
414  i++;
415  }
416  }
417 }
418 
419 void Layer::selectAllFramesAfter(int position)
420 {
421  int startPosition = position;
422  int endPosition = getMaxKeyFramePosition();
423 
424  if (!keyExists(startPosition))
425  {
426  startPosition = getNextKeyFramePosition(startPosition);
427  }
428 
429  if (startPosition > 0 && startPosition <= endPosition)
430  {
431  deselectAll();
432  setFrameSelected(startPosition, true);
433  extendSelectionTo(endPosition);
434  }
435 }
436 
437 void Layer::deselectAll()
438 {
439  mSelectedFrames_byLast.clear();
440  mSelectedFrames_byPosition.clear();
441 
442  for (auto pair : mKeyFrames)
443  {
444  pair.second->setSelected(false);
445  }
446 }
447 
448 bool Layer::moveSelectedFrames(int offset)
449 {
450  if (offset != 0 && mSelectedFrames_byPosition.count() > 0)
451  {
452  // If we are moving to the right we start moving selected frames from the highest (right) to the lowest (left)
453  int indexInSelection = mSelectedFrames_byPosition.count() - 1;
454  int step = -1;
455 
456  if (offset < 0)
457  {
458  // If we are moving to the left we start moving selected frames from the lowest (left) to the highest (right)
459  indexInSelection = 0;
460  step = 1;
461 
462  // Check if we are not moving out of the timeline
463  if (mSelectedFrames_byPosition[0] + offset < 1) return false;
464  }
465 
466  while (indexInSelection > -1 && indexInSelection < mSelectedFrames_byPosition.count())
467  {
468  int fromPos = mSelectedFrames_byPosition[indexInSelection];
469  int toPos = fromPos + offset;
470 
471  // Get the frame to move
472  KeyFrame* selectedFrame = getKeyFrameAt(fromPos);
473 
474  if (selectedFrame != nullptr)
475  {
476  mKeyFrames.erase(fromPos);
477 
478  // Slide back every frame between fromPos to toPos
479  // to avoid having 2 frames in the same position
480  bool isBetween = true;
481  int targetPosition = fromPos;
482 
483  while (isBetween)
484  {
485  int framePosition = targetPosition - step;
486 
487  KeyFrame* frame = getKeyFrameAt(framePosition);
488 
489  if (frame != nullptr)
490  {
491  mKeyFrames.erase(framePosition);
492 
493  frame->setPos(targetPosition);
494  mKeyFrames.insert(std::make_pair(targetPosition, frame));
495  }
496 
497  targetPosition = targetPosition - step;
498  if (fromPos < toPos && (targetPosition < fromPos || targetPosition >= toPos))
499  isBetween = false;
500  if (fromPos > toPos && (targetPosition > fromPos || targetPosition <= toPos))
501  isBetween = false;
502  }
503 
504  if (fromPos == 1)
505  {
506  // If the first frame is moving, we need to create a new first frame
507  //addNewKeyFrameAt(1);
508  }
509 
510  // Update the position of the selected frame
511  selectedFrame->setPos(toPos);
512  mKeyFrames.insert(std::make_pair(toPos, selectedFrame));
513  }
514  indexInSelection = indexInSelection + step;
515  }
516 
517  // Update selection lists
518  for (int i = 0; i < mSelectedFrames_byPosition.count(); i++)
519  {
520  mSelectedFrames_byPosition[i] = mSelectedFrames_byPosition[i] + offset;
521  }
522  for (int i = 0; i < mSelectedFrames_byLast.count(); i++)
523  {
524  mSelectedFrames_byLast[i] = mSelectedFrames_byLast[i] + offset;
525  }
526  return true;
527  }
528  return false;
529 }
530 
531 bool Layer::isPaintable() const
532 {
533  return (type() == BITMAP || type() == VECTOR);
534 }
535 
536 bool Layer::keyExistsWhichCovers(int frameNumber)
537 {
538  return getKeyFrameWhichCovers(frameNumber) != nullptr;
539 }
540 
541 KeyFrame* Layer::getKeyFrameWhichCovers(int frameNumber) const
542 {
543  auto keyFrame = getLastKeyFrameAtPosition(frameNumber);
544  if (keyFrame != nullptr)
545  {
546  if (keyFrame->pos() + keyFrame->length() > frameNumber)
547  {
548  return keyFrame;
549  }
550  }
551  return nullptr;
552 }
553 
554 QDomElement Layer::createBaseDomElement(QDomDocument& doc) const
555 {
556  QDomElement layerTag = doc.createElement("layer");
557  layerTag.setAttribute("id", id());
558  layerTag.setAttribute("name", name());
559  layerTag.setAttribute("visibility", visible());
560  layerTag.setAttribute("type", type());
561  return layerTag;
562 }
563 
564 void Layer::loadBaseDomElement(const QDomElement& elem)
565 {
566  if (!elem.attribute("id").isNull())
567  {
568  int id = elem.attribute("id").toInt();
569  setId(id);
570  }
571  setName(elem.attribute("name", "untitled"));
572  setVisible(elem.attribute("visibility", "1").toInt());
573 }
void clear()
QString attribute(const QString &name, const QString &defValue) const const
void removeAt(int i)
bool isNull() const const
int indexOf(const T &value, int from) const const
int count(const T &value) const const
void append(const T &value)
void setAttribute(const QString &name, const QString &value)
int toInt(bool *ok, int base) const const
bool isEmpty() const const
QList::iterator end()
void setParent(QObject *parent)
bool contains(const T &value) const const
void insert(int i, const T &value)
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
Definition: object.h:54
QDomElement createElement(const QString &tagName)
QList::iterator begin()