1
2
3 #include "filmstripcommand.h"
4 #include "tapp.h"
5 #include "toonz/palettecontroller.h"
6 #include "toonz/txshlevelhandle.h"
7 #include "toonz/txsheethandle.h"
8 #include "toonz/tscenehandle.h"
9 #include "toonz/tpalettehandle.h"
10 #include "toonz/tframehandle.h"
11 #include "tinbetween.h"
12 #include "tvectorimage.h"
13 #include "ttoonzimage.h"
14 #include "toonzqt/selection.h"
15 #include "toonzqt/dvdialog.h"
16 #include "drawingdata.h"
17 #include "toonzqt/strokesdata.h"
18 #include "toonzqt/rasterimagedata.h"
19 #include "timagecache.h"
20 #include "tools/toolutils.h"
21 #include "toonzqt/icongenerator.h"
22
23 #include "tundo.h"
24 #include "toonz/txshsimplelevel.h"
25 #include "toonz/txshchildlevel.h"
26 #include "toonz/txshsoundlevel.h"
27 #include "toonz/txshpalettelevel.h"
28 #include "toonz/txshpalettecolumn.h"
29 #include "toonz/txshsoundcolumn.h"
30 #include "toonz/txsheet.h"
31 #include "toonz/txshcell.h"
32 #include "toonz/toonzscene.h"
33 #include "toonz/levelset.h"
34 #include "toonz/txshleveltypes.h"
35 #include "toonz/toonzimageutils.h"
36 #include "toonz/trasterimageutils.h"
37 #include "toonz/tcamera.h"
38 #include "toonz/preferences.h"
39 #include "trop.h"
40
41 #include "toonzqt/gutil.h"
42
43 #include "historytypes.h"
44
45 #include <QApplication>
46 #include <QClipboard>
47
48 //=============================================================================
49
operator +(const TFrameId & fid,int d)50 TFrameId operator+(const TFrameId &fid, int d) {
51 return TFrameId(fid.getNumber() + d, fid.getLetter());
52 }
53
54 //-----------------------------------------------------------------------------
55 /*
56 void doUpdateXSheet(TXshSimpleLevel *sl, std::vector<TFrameId> oldFids,
57 std::vector<TFrameId> newFids, TXsheet *xsh,
58 std::vector<TXshChildLevel *> &childLevels) {
59 for (int c = 0; c < xsh->getColumnCount(); ++c) {
60 int r0, r1;
61 int n = xsh->getCellRange(c, r0, r1);
62 if (n > 0) {
63 bool changed = false;
64 std::vector<TXshCell> cells(n);
65 xsh->getCells(r0, c, n, &cells[0]);
66 for (int i = 0; i < n; i++) {
67 TXshCell currCell = cells[i];
68 // check the sub xsheets too
69 if (!cells[i].isEmpty() &&
70 cells[i].m_level->getType() == CHILD_XSHLEVEL) {
71 TXshChildLevel *level = cells[i].m_level->getChildLevel();
72 // make sure we haven't already checked the level
73 if (level && std::find(childLevels.begin(), childLevels.end(),
74 level) == childLevels.end()) {
75 childLevels.push_back(level);
76 TXsheet *subXsh = level->getXsheet();
77 doUpdateXSheet(sl, oldFids, newFids, subXsh, childLevels);
78 }
79 }
80 for (int j = 0; j < oldFids.size(); j++) {
81 if (oldFids.at(j) == newFids.at(j)) continue;
82 TXshCell tempCell(sl, oldFids.at(j));
83 bool sameSl = tempCell.getSimpleLevel() == currCell.getSimpleLevel();
84 bool sameFid = tempCell.getFrameId() == currCell.getFrameId();
85 if (sameSl && sameFid) {
86 TXshCell newCell(sl, newFids.at(j));
87 cells[i] = newCell;
88 changed = true;
89 break;
90 }
91 }
92 }
93 if (changed) {
94 xsh->setCells(r0, c, n, &cells[0]);
95 TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
96 }
97 }
98 }
99 }
100 */
101 //-----------------------------------------------------------------------------
102
updateXSheet(TXshSimpleLevel * sl,std::vector<TFrameId> oldFids,std::vector<TFrameId> newFids)103 static void updateXSheet(TXshSimpleLevel *sl, std::vector<TFrameId> oldFids,
104 std::vector<TFrameId> newFids) {
105 std::vector<TXshChildLevel *> childLevels;
106 TXsheet *xsh =
107 TApp::instance()->getCurrentScene()->getScene()->getTopXsheet();
108 bool changed =
109 ToolUtils::doUpdateXSheet(sl, oldFids, newFids, xsh, childLevels);
110 if (changed) TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
111 }
112
113 //=============================================================================
114 // makeSpaceForFid
115 // se necessario renumera gli altri fid del livello in modo che
116 // framesToInsert siano liberi
117 // n.b. modifica
118 //-----------------------------------------------------------------------------
119
makeSpaceForFids(TXshSimpleLevel * sl,const std::set<TFrameId> & framesToInsert)120 void makeSpaceForFids(TXshSimpleLevel *sl,
121 const std::set<TFrameId> &framesToInsert) {
122 std::vector<TFrameId> fids;
123 std::vector<TFrameId> oldFids;
124 sl->getFids(fids);
125 sl->getFids(oldFids);
126 std::set<TFrameId>::const_iterator it;
127 std::set<TFrameId> touchedFids;
128 for (it = framesToInsert.begin(); it != framesToInsert.end(); ++it) {
129 // devo inserire fid
130 TFrameId fid(*it);
131 std::vector<TFrameId>::iterator j;
132 // controllo che non ci sia gia'
133 j = fids.begin();
134 while (j = std::find(j, fids.end(), fid), j != fids.end()) {
135 // c'e' gia' un fid. faccio fid -> fid + 1
136 touchedFids.insert(fid);
137 fid = fid + 1;
138 touchedFids.insert(fid);
139 *j = fid;
140 // adesso devo controllare che il nuovo fid non ci sia gia' nella
141 // parte restante dell'array fids
142 ++j;
143 }
144 }
145 if (!touchedFids.empty()) {
146 if (Preferences::instance()->isSyncLevelRenumberWithXsheetEnabled())
147 updateXSheet(sl, oldFids, fids);
148 sl->renumber(fids);
149 sl->setDirtyFlag(true);
150 }
151 }
152
153 //=============================================================================
154 namespace {
155 //-----------------------------------------------------------------------------
156
copyFramesWithoutUndo(TXshSimpleLevel * sl,std::set<TFrameId> & frames)157 void copyFramesWithoutUndo(TXshSimpleLevel *sl, std::set<TFrameId> &frames) {
158 QClipboard *clipboard = QApplication::clipboard();
159 TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
160 DrawingData *data = new DrawingData();
161 data->setLevelFrames(sl, frames);
162 clipboard->setMimeData(data, QClipboard::Clipboard);
163 }
164
165 //-----------------------------------------------------------------------------
166 // frames is a selected frames in the film strip
pasteAreasWithoutUndo(const QMimeData * data,TXshSimpleLevel * sl,std::set<TFrameId> & frames,TTileSet ** tileSet,std::map<TFrameId,std::set<int>> & indices)167 bool pasteAreasWithoutUndo(const QMimeData *data, TXshSimpleLevel *sl,
168 std::set<TFrameId> &frames, TTileSet **tileSet,
169 std::map<TFrameId, std::set<int>> &indices) {
170 // paste between the same level must keep the palette unchanged
171 // Not emitting PaletteChanged signal can avoid the update of color model
172 bool paletteHasChanged = true;
173
174 if (const StrokesData *strokesData =
175 dynamic_cast<const StrokesData *>(data)) {
176 std::set<TFrameId>::iterator it;
177 for (it = frames.begin(); it != frames.end(); ++it) {
178 TImageP img = sl->getFrame(*it, true);
179 if (!img) {
180 img = sl->createEmptyFrame();
181 sl->setFrame(*it, img);
182 }
183 TVectorImageP vi = img;
184 TToonzImageP ti = img;
185 TRasterImageP ri = img;
186 if (vi) {
187 std::set<int> imageIndices;
188 strokesData->getImage(vi, imageIndices, true);
189 indices[*it] = imageIndices;
190 } else if (ti) {
191 ToonzImageData *toonzImageData = strokesData->toToonzImageData(ti);
192 return pasteAreasWithoutUndo(toonzImageData, sl, frames, tileSet,
193 indices);
194 } else if (ri) {
195 double dpix, dpiy;
196 ri->getDpi(dpix, dpiy);
197 if (dpix == 0 || dpiy == 0) {
198 TPointD dpi = sl->getScene()->getCurrentCamera()->getDpi();
199 dpix = dpi.x;
200 dpiy = dpi.y;
201 ri->setDpi(dpix, dpiy);
202 }
203 FullColorImageData *fullColorImageData =
204 strokesData->toFullColorImageData(ri);
205 return pasteAreasWithoutUndo(fullColorImageData, sl, frames, tileSet,
206 indices);
207 }
208 }
209 }
210 // when pasting the copied area selected with the selection tool
211 else if (const RasterImageData *rasterImageData =
212 dynamic_cast<const RasterImageData *>(data)) {
213 std::set<TFrameId>::iterator it;
214 for (it = frames.begin(); it != frames.end(); ++it) {
215 if ((sl->getType() == PLI_XSHLEVEL || sl->getType() == TZP_XSHLEVEL) &&
216 dynamic_cast<const FullColorImageData *>(rasterImageData)) {
217 DVGui::error(QObject::tr(
218 "The copied selection cannot be pasted in the current drawing."));
219 return false;
220 }
221 // obtain the image data to be pasted
222 TImageP img = sl->getFrame(*it, true);
223 if (!img) {
224 img = sl->createEmptyFrame();
225 sl->setFrame(*it, img);
226 }
227 TToonzImageP ti = img;
228 TRasterImageP ri = img;
229 TVectorImageP vi = img;
230 // pasting TLV
231 if (ti) {
232 TRasterP ras;
233 double dpiX, dpiY;
234 std::vector<TRectD> rects;
235 std::vector<TStroke> strokes;
236 std::vector<TStroke> originalStrokes;
237 TAffine affine;
238
239 // style will be merged in getData() if the palettes are different
240 int styleCountBeforePasteImage = ti->getPalette()->getStyleCount();
241
242 rasterImageData->getData(ras, dpiX, dpiY, rects, strokes,
243 originalStrokes, affine, ti->getPalette());
244
245 if (styleCountBeforePasteImage == ti->getPalette()->getStyleCount())
246 paletteHasChanged = false;
247
248 double imgDpiX, imgDpiY;
249 ti->getDpi(imgDpiX, imgDpiY);
250 TScale sc(imgDpiX / dpiX, imgDpiY / dpiY);
251 affine *= sc;
252 int i;
253 TRectD boxD;
254 if (rects.size() > 0) boxD = rects[0];
255 if (strokes.size() > 0) boxD = strokes[0].getBBox();
256 for (i = 0; i < rects.size(); i++) boxD += rects[i];
257 for (i = 0; i < strokes.size(); i++) boxD += strokes[i].getBBox();
258 boxD = affine * boxD;
259 TRect box = ToonzImageUtils::convertWorldToRaster(boxD, ti);
260 TPoint pos = box.getP00();
261
262 if (pos.x < 0) pos.x = 0;
263 if (pos.y < 0) pos.y = 0;
264
265 if (*tileSet == 0)
266 *tileSet = new TTileSetCM32(ti->getRaster()->getSize());
267 if (box.overlaps(ti->getRaster()->getBounds()))
268 (*tileSet)->add(ti->getRaster(), box);
269 else
270 (*tileSet)->add(0);
271 TRasterCM32P app = ras;
272 if (app) {
273 TRop::over(ti->getRaster(), app, pos, affine);
274 ToolUtils::updateSaveBox(sl, *it);
275 }
276 } else if (ri) {
277 TRasterP ras;
278 double dpiX = 0, dpiY = 0;
279 double imgDpiX = 0, imgDpiY = 0;
280 std::vector<TRectD> rects;
281 std::vector<TStroke> strokes;
282 std::vector<TStroke> originalStrokes;
283 TAffine affine;
284
285 TPointD cameraDpi;
286
287 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
288 if (scene) {
289 TCamera *camera = scene->getCurrentCamera();
290 cameraDpi = camera->getDpi();
291 if (cameraDpi.x == 0.0 ||
292 cameraDpi.y == 0.0) // it should never happen. just in case...
293 return false;
294 } else
295 return false;
296
297 rasterImageData->getData(ras, dpiX, dpiY, rects, strokes,
298 originalStrokes, affine, ri->getPalette());
299 if (dpiX == 0 || dpiY == 0) {
300 dpiX = cameraDpi.x;
301 dpiY = cameraDpi.y;
302 }
303
304 ri->getDpi(imgDpiX, imgDpiY);
305 if (imgDpiX == 0 || imgDpiY == 0) {
306 imgDpiX = cameraDpi.x;
307 imgDpiY = cameraDpi.y;
308 }
309 TScale sc(imgDpiX / dpiX, imgDpiY / dpiY);
310 affine *= sc;
311 int i;
312 TRectD boxD;
313 if (rects.size() > 0) boxD = rects[0];
314 if (strokes.size() > 0) boxD = strokes[0].getBBox();
315 for (i = 0; i < rects.size(); i++) boxD += rects[i];
316 for (i = 0; i < strokes.size(); i++) boxD += strokes[i].getBBox();
317 boxD = affine * boxD;
318 TRect box = TRasterImageUtils::convertWorldToRaster(boxD, ri);
319 TPoint pos = box.getP00();
320 if (*tileSet == 0)
321 *tileSet = new TTileSetFullColor(ri->getRaster()->getSize());
322 if (box.overlaps(ri->getRaster()->getBounds()))
323 (*tileSet)->add(ri->getRaster(), box);
324 else
325 (*tileSet)->add(0);
326 TRasterCM32P app = ras;
327 if (app)
328 TRop::over(ri->getRaster(), app, ri->getPalette(), pos, affine);
329 else
330 TRop::over(ri->getRaster(), ras, pos, affine);
331 } else if (vi) {
332 StrokesData *strokesData =
333 rasterImageData->toStrokesData(sl->getScene());
334 return pasteAreasWithoutUndo(strokesData, sl, frames, tileSet, indices);
335 }
336 }
337 } else
338 return false;
339
340 if (paletteHasChanged)
341 TApp::instance()
342 ->getPaletteController()
343 ->getCurrentLevelPalette()
344 ->notifyPaletteChanged();
345
346 invalidateIcons(sl, frames);
347 sl->setDirtyFlag(true);
348 TApp::instance()->getCurrentLevel()->notifyLevelChange();
349
350 return true;
351 }
352
353 //-----------------------------------------------------------------------------
354 // Se insert == true incolla i frames nel livello inserendoli, se necessario
355 // spostando
356 // verso il basso i preesistenti. Altrimenti incolla i frames sostituendoli.
357 // il parametro clone images si mette a false quando questa funzione viene usata
358 // per un undo/redo.
359
pasteFramesWithoutUndo(const DrawingData * data,TXshSimpleLevel * sl,std::set<TFrameId> & frames,DrawingData::ImageSetType setType,bool cloneImages,bool & keepOriginalPalette,bool isRedo=false)360 bool pasteFramesWithoutUndo(const DrawingData *data, TXshSimpleLevel *sl,
361 std::set<TFrameId> &frames,
362 DrawingData::ImageSetType setType, bool cloneImages,
363 bool &keepOriginalPalette, bool isRedo = false) {
364 if (!data || (frames.empty() && setType != DrawingData::OVER_FRAMEID))
365 return false;
366
367 bool isPaste = data->getLevelFrames(sl, frames, setType, cloneImages,
368 keepOriginalPalette, isRedo);
369 if (!isPaste) return false;
370
371 if (keepOriginalPalette)
372 invalidateIcons(sl, frames);
373 else {
374 std::vector<TFrameId> sl_fids;
375 sl->getFids(sl_fids);
376 invalidateIcons(sl, sl_fids);
377 }
378 sl->setDirtyFlag(true);
379 TApp::instance()->getCurrentLevel()->notifyLevelChange();
380 TApp::instance()
381 ->getPaletteController()
382 ->getCurrentLevelPalette()
383 ->notifyPaletteChanged();
384
385 return true;
386 }
387
388 //-----------------------------------------------------------------------------
389
390 // "Svuota" i frames: i frames vengono buttati e al loro posto
391 // vengono inseriti frames vuoti.
clearFramesWithoutUndo(const TXshSimpleLevelP & sl,const std::set<TFrameId> & frames)392 std::map<TFrameId, QString> clearFramesWithoutUndo(
393 const TXshSimpleLevelP &sl, const std::set<TFrameId> &frames) {
394 std::map<TFrameId, QString> clearedFrames;
395 if (!sl || frames.empty()) return clearedFrames;
396
397 std::set<TFrameId>::const_iterator it;
398 for (it = frames.begin(); it != frames.end(); ++it) {
399 TFrameId frameId = *it;
400 /* UINT にキャストしたらだめだろ */
401 // QString id =
402 // "clearFrames"+QString::number((UINT)sl.getPointer())+"-"+QString::number(it->getNumber());
403 QString id = "clearFrames" + QString::number((uintptr_t)sl.getPointer()) +
404 "-" + QString::number(it->getNumber());
405 TImageCache::instance()->add(id, sl->getFrame(frameId, false));
406 clearedFrames[frameId] = id;
407 // empty frame must be created BEFORE erasing frame or it may initialize
408 // palette.
409 TImageP emptyFrame = sl->createEmptyFrame();
410 sl->eraseFrame(frameId);
411 sl->setFrame(*it, emptyFrame);
412 }
413 invalidateIcons(sl.getPointer(), frames);
414 TApp::instance()->getCurrentLevel()->notifyLevelChange();
415 sl->setDirtyFlag(true);
416 return clearedFrames;
417 }
418
419 //-----------------------------------------------------------------------------
420
421 // Rimuove i frames dal livello
removeFramesWithoutUndo(const TXshSimpleLevelP & sl,const std::set<TFrameId> & frames)422 void removeFramesWithoutUndo(const TXshSimpleLevelP &sl,
423 const std::set<TFrameId> &frames) {
424 if (!sl || frames.empty()) return;
425 std::set<TFrameId>::const_iterator it;
426 for (it = frames.begin(); it != frames.end(); ++it) sl->eraseFrame(*it);
427 removeIcons(sl.getPointer(), frames);
428 sl->setDirtyFlag(true);
429 TApp::instance()->getCurrentLevel()->notifyLevelChange();
430 }
431
432 //-----------------------------------------------------------------------------
433
cutFramesWithoutUndo(TXshSimpleLevel * sl,std::set<TFrameId> & frames)434 void cutFramesWithoutUndo(TXshSimpleLevel *sl, std::set<TFrameId> &frames) {
435 std::map<TFrameId, QString> imageSet;
436
437 HookSet *levelHooks = sl->getHookSet();
438 int currentFrameIndex = TApp::instance()->getCurrentFrame()->getFrameIndex();
439 std::set<TFrameId>::const_iterator it;
440 int i = 0;
441 for (it = frames.begin(); it != frames.end(); ++it, i++) {
442 TFrameId frameId = *it;
443 // QString id =
444 // "cutFrames"+QString::number((UINT)sl)+"-"+QString::number(it->getNumber());
445 QString id = "cutFrames" + QString::number((uintptr_t)sl) + "-" +
446 QString::number(it->getNumber());
447 TImageCache::instance()->add(id, sl->getFrame(frameId, false));
448 imageSet[frameId] = id;
449 }
450 removeIcons(sl, frames);
451
452 sl->setDirtyFlag(true);
453
454 QClipboard *clipboard = QApplication::clipboard();
455 DrawingData *data = new DrawingData();
456 data->setFrames(imageSet, sl, *levelHooks);
457 clipboard->setMimeData(data, QClipboard::Clipboard);
458
459 for (it = frames.begin(); it != frames.end(); ++it, i++) {
460 sl->eraseFrame(*it);
461 }
462
463 std::vector<TFrameId> newFids;
464 sl->getFids(newFids);
465 // Devo settare i nuovi fids al frame handle prima di mandare la notifica di
466 // cambiamento del livello
467 TApp::instance()->getCurrentFrame()->setFrameIds(newFids);
468 TApp::instance()->getCurrentFrame()->setFrameIndex(currentFrameIndex);
469 TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
470 sl->setDirtyFlag(true);
471 TApp::instance()->getCurrentLevel()->notifyLevelChange();
472 }
473
474 //-----------------------------------------------------------------------------
475
insertNotEmptyframes(const TXshSimpleLevelP & sl,const std::map<TFrameId,QString> & framesToInsert)476 void insertNotEmptyframes(const TXshSimpleLevelP &sl,
477 const std::map<TFrameId, QString> &framesToInsert) {
478 if (framesToInsert.empty() || !sl) return;
479 std::vector<TFrameId> fids;
480 sl->getFids(fids);
481 std::set<TFrameId> frames;
482 for (auto const &frame : framesToInsert) {
483 frames.insert(frame.first);
484 }
485 makeSpaceForFids(sl.getPointer(), frames);
486
487 for (auto const &frame : framesToInsert) {
488 TImageP img = TImageCache::instance()->get(frame.second, false);
489 TImageCache::instance()->remove(frame.second);
490 assert(img);
491 sl->setFrame(frame.first, img);
492 }
493 invalidateIcons(sl.getPointer(), frames);
494 sl->setDirtyFlag(true);
495 TApp::instance()->getCurrentLevel()->notifyLevelChange();
496 }
497
498 //=============================================================================
499 // PasteRasterAreasUndo
500 //-----------------------------------------------------------------------------
501
502 class PasteRasterAreasUndo final : public TUndo {
503 TXshSimpleLevelP m_level;
504 std::set<TFrameId> m_frames;
505 TTileSet *m_tiles;
506 RasterImageData *m_data;
507 TPaletteP m_oldPalette;
508 TPaletteP m_newPalette;
509 bool m_isFrameInserted;
510
511 public:
PasteRasterAreasUndo(TXshSimpleLevel * sl,const std::set<TFrameId> & frames,TTileSet * tiles,RasterImageData * data,TPalette * plt,bool isFrameInserted)512 PasteRasterAreasUndo(TXshSimpleLevel *sl, const std::set<TFrameId> &frames,
513 TTileSet *tiles, RasterImageData *data, TPalette *plt,
514 bool isFrameInserted)
515 : TUndo()
516 , m_level(sl)
517 , m_frames(frames)
518 , m_tiles(tiles)
519 , m_oldPalette(plt->clone())
520 , m_isFrameInserted(isFrameInserted) {
521 m_data = data->clone();
522 assert(m_tiles->getTileCount() == m_frames.size());
523 }
524
~PasteRasterAreasUndo()525 ~PasteRasterAreasUndo() {
526 if (m_tiles) delete m_tiles;
527 if (m_data) delete m_data;
528 }
529
onAdd()530 void onAdd() override { m_newPalette = m_level->getPalette()->clone(); }
531
undo() const532 void undo() const override {
533 if (!m_level || m_frames.empty()) return;
534 std::set<TFrameId> frames = m_frames;
535
536 if (m_isFrameInserted) {
537 // Faccio remove dei frame incollati
538 removeFramesWithoutUndo(m_level, frames);
539 } else {
540 std::set<TFrameId>::const_iterator it;
541 int i = 0;
542 TTileSetCM32 *tileSetCM = dynamic_cast<TTileSetCM32 *>(m_tiles);
543 TTileSetFullColor *tileSetFC = dynamic_cast<TTileSetFullColor *>(m_tiles);
544 for (it = m_frames.begin(); it != m_frames.end(); it++, i++) {
545 TImageP image = m_level->getFrame(*it, true);
546 if (!image) continue;
547 TRasterImageP ri(image);
548 TToonzImageP ti(image);
549 if (tileSetCM) {
550 const TTileSetCM32::Tile *tile = tileSetCM->getTile(i);
551 if (!tile) continue;
552 TRasterCM32P tileRas;
553 tile->getRaster(tileRas);
554 assert(ti);
555 ti->getRaster()->copy(tileRas, tile->m_rasterBounds.getP00());
556 ToolUtils::updateSaveBox(m_level, *it);
557 } else if (tileSetFC) {
558 const TTileSetFullColor::Tile *tile = tileSetFC->getTile(i);
559 if (!tile) continue;
560 TRasterP tileRas;
561 tile->getRaster(tileRas);
562 assert(ri);
563 ri->getRaster()->copy(tileRas, tile->m_rasterBounds.getP00());
564 }
565 }
566 }
567 // Setto la vecchia paletta al livello
568 if (m_oldPalette.getPointer()) {
569 m_level->getPalette()->assign(m_oldPalette->clone());
570 TApp::instance()
571 ->getPaletteController()
572 ->getCurrentLevelPalette()
573 ->notifyPaletteChanged();
574 }
575
576 invalidateIcons(m_level.getPointer(), m_frames);
577 TApp::instance()->getCurrentLevel()->notifyLevelChange();
578 }
579
redo() const580 void redo() const override {
581 if (!m_level || m_frames.empty()) return;
582 if (m_isFrameInserted) {
583 assert(m_frames.size() == 1);
584 TImageP img = m_level->createEmptyFrame();
585 m_level->setFrame(*m_frames.begin(), img);
586 }
587
588 std::set<TFrameId> frames = m_frames;
589
590 std::set<TFrameId>::const_iterator it;
591 for (it = m_frames.begin(); it != m_frames.end(); it++) {
592 TImageP image = m_level->getFrame(*it, true);
593 TRasterImageP ri = image;
594 TToonzImageP ti = image;
595 if (ti) {
596 TRasterP ras;
597 double dpiX, dpiY;
598 std::vector<TRectD> rects;
599 std::vector<TStroke> strokes;
600 std::vector<TStroke> originalStrokes;
601 TAffine affine;
602 m_data->getData(ras, dpiX, dpiY, rects, strokes, originalStrokes,
603 affine, ti->getPalette());
604 double imgDpiX, imgDpiY;
605 ti->getDpi(imgDpiX, imgDpiY);
606 TScale sc(imgDpiX / dpiX, imgDpiY / dpiY);
607 affine *= sc;
608
609 int i;
610 TRectD boxD;
611 if (rects.size() > 0) boxD = rects[0];
612 if (strokes.size() > 0) boxD = strokes[0].getBBox();
613 for (i = 0; i < rects.size(); i++) boxD += rects[i];
614 for (i = 0; i < strokes.size(); i++) boxD += strokes[i].getBBox();
615 boxD = affine * boxD;
616 TRect box = ToonzImageUtils::convertWorldToRaster(boxD, ti);
617 TPoint pos = box.getP00();
618 TRasterCM32P app = ras;
619 TRop::over(ti->getRaster(), app, pos, affine);
620 ToolUtils::updateSaveBox(m_level, *it);
621 } else if (ri) {
622 TRasterP ras;
623 double dpiX, dpiY;
624 std::vector<TRectD> rects;
625 std::vector<TStroke> strokes;
626 std::vector<TStroke> originalStrokes;
627 TAffine affine;
628 m_data->getData(ras, dpiX, dpiY, rects, strokes, originalStrokes,
629 affine, ri->getPalette());
630 double imgDpiX, imgDpiY;
631 if (dpiX == 0 && dpiY == 0) {
632 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
633 if (scene) {
634 TCamera *camera = scene->getCurrentCamera();
635 TPointD dpi = camera->getDpi();
636 dpiX = dpi.x;
637 dpiY = dpi.y;
638 } else
639 return;
640 }
641 ri->getDpi(imgDpiX, imgDpiY);
642 TScale sc(imgDpiX / dpiX, imgDpiY / dpiY);
643 affine *= sc;
644 int i;
645 TRectD boxD;
646 if (rects.size() > 0) boxD = rects[0];
647 if (strokes.size() > 0) boxD = strokes[0].getBBox();
648 for (i = 0; i < rects.size(); i++) boxD += rects[i];
649 for (i = 0; i < strokes.size(); i++) boxD += strokes[i].getBBox();
650 boxD = affine * boxD;
651 TRect box = TRasterImageUtils::convertWorldToRaster(boxD, ri);
652 TPoint pos = box.getP00();
653 TRasterCM32P app = ras;
654 if (app)
655 TRop::over(ri->getRaster(), app, ri->getPalette(), pos, affine);
656 else
657 TRop::over(ri->getRaster(), ras, pos, affine);
658 }
659 }
660
661 if (m_newPalette.getPointer()) {
662 m_level->getPalette()->assign(m_newPalette->clone());
663 TApp::instance()
664 ->getPaletteController()
665 ->getCurrentLevelPalette()
666 ->notifyPaletteChanged();
667 }
668
669 invalidateIcons(m_level.getPointer(), m_frames);
670 TApp::instance()->getCurrentLevel()->notifyLevelChange();
671 }
672
getSize() const673 int getSize() const override {
674 return sizeof(*this) + sizeof(*m_data) + sizeof(*m_tiles);
675 }
676
getHistoryString()677 QString getHistoryString() override {
678 QString str = QObject::tr("Paste : Level %1 : Frame ")
679 .arg(QString::fromStdWString(m_level->getName()));
680
681 std::set<TFrameId>::const_iterator it;
682 for (it = m_frames.begin(); it != m_frames.end(); it++) {
683 if (it != m_frames.begin()) str += QString(", ");
684 str += QString::number((*it).getNumber());
685 }
686
687 return str;
688 }
getHistoryType()689 int getHistoryType() override { return HistoryType::FilmStrip; }
690 };
691
692 //=============================================================================
693 // PasteVectorAreasUndo
694 //-----------------------------------------------------------------------------
695
696 class PasteVectorAreasUndo final : public TUndo {
697 TXshSimpleLevelP m_level;
698 std::set<TFrameId> m_frames;
699 std::map<TFrameId, std::set<int>> m_indices;
700 StrokesData *m_data;
701 TPaletteP m_oldPalette;
702 TPaletteP m_newPalette;
703 bool m_isFrameInserted;
704
705 public:
PasteVectorAreasUndo(TXshSimpleLevel * sl,const std::set<TFrameId> & frames,std::map<TFrameId,std::set<int>> & indices,StrokesData * data,TPalette * plt,bool isFrameInserted)706 PasteVectorAreasUndo(TXshSimpleLevel *sl, const std::set<TFrameId> &frames,
707 std::map<TFrameId, std::set<int>> &indices,
708 StrokesData *data, TPalette *plt, bool isFrameInserted)
709 : TUndo()
710 , m_level(sl)
711 , m_frames(frames)
712 , m_indices(indices)
713 , m_oldPalette(plt->clone())
714 , m_isFrameInserted(isFrameInserted) {
715 m_data = data->clone();
716 }
717
~PasteVectorAreasUndo()718 ~PasteVectorAreasUndo() {
719 if (m_data) delete m_data;
720 }
721
onAdd()722 void onAdd() override { m_newPalette = m_level->getPalette()->clone(); }
723
undo() const724 void undo() const override {
725 if (!m_level || m_frames.empty()) return;
726
727 std::set<TFrameId> frames = m_frames;
728
729 if (m_isFrameInserted) {
730 // Faccio remove dei frame incollati
731 removeFramesWithoutUndo(m_level, frames);
732 } else {
733 std::set<TFrameId>::const_iterator it;
734 for (it = m_frames.begin(); it != m_frames.end(); it++) {
735 TVectorImageP img = m_level->getFrame(*it, true);
736 assert(img);
737 if (!img) continue;
738 std::map<TFrameId, std::set<int>>::const_iterator mapIt =
739 m_indices.find(*it);
740 if (mapIt == m_indices.end()) continue;
741 std::set<int> imageIndices = mapIt->second;
742 ;
743 std::set<int>::const_iterator it2 = imageIndices.end();
744 while (it2 != imageIndices.begin()) {
745 it2--;
746 img->removeStroke(*it2);
747 }
748 }
749 }
750
751 // Setto la vecchia paletta al livello
752 if (m_oldPalette.getPointer()) {
753 m_level->getPalette()->assign(m_oldPalette->clone());
754 TApp::instance()
755 ->getPaletteController()
756 ->getCurrentLevelPalette()
757 ->notifyPaletteChanged();
758 }
759
760 invalidateIcons(m_level.getPointer(), m_frames);
761 TApp::instance()->getCurrentLevel()->notifyLevelChange();
762 }
763
redo() const764 void redo() const override {
765 if (!m_level || m_frames.empty()) return;
766
767 if (m_isFrameInserted) {
768 assert(m_frames.size() == 1);
769 TVectorImageP img = m_level->createEmptyFrame();
770 m_level->setFrame(*m_frames.begin(), img);
771 }
772
773 std::set<TFrameId> frames = m_frames;
774 std::set<TFrameId>::const_iterator it;
775 for (it = m_frames.begin(); it != m_frames.end(); it++) {
776 TVectorImageP img = m_level->getFrame(*it, true);
777 assert(img);
778 if (!img) continue;
779 std::set<int> app;
780 m_data->getImage(img, app, true);
781 }
782
783 if (m_newPalette.getPointer()) {
784 m_level->getPalette()->assign(m_newPalette->clone());
785 TApp::instance()
786 ->getPaletteController()
787 ->getCurrentLevelPalette()
788 ->notifyPaletteChanged();
789 }
790
791 invalidateIcons(m_level.getPointer(), m_frames);
792 TApp::instance()->getCurrentLevel()->notifyLevelChange();
793 }
794
getSize() const795 int getSize() const override { return sizeof(*this) + sizeof(*m_data); }
796
getHistoryString()797 QString getHistoryString() override {
798 QString str = QObject::tr("Paste : Level %1 : Frame ")
799 .arg(QString::fromStdWString(m_level->getName()));
800
801 std::set<TFrameId>::const_iterator it;
802 for (it = m_frames.begin(); it != m_frames.end(); it++) {
803 if (it != m_frames.begin()) str += QString(", ");
804 str += QString::number((*it).getNumber());
805 }
806
807 return str;
808 }
getHistoryType()809 int getHistoryType() override { return HistoryType::FilmStrip; }
810 };
811
812 /*//=============================================================================
813 // PasteAreasUndo
814 //-----------------------------------------------------------------------------
815
816 class PasteAreasUndo final : public TUndo
817 {
818 TXshSimpleLevelP m_level;
819 std::set<TFrameId> m_frames;
820 TPaletteP m_oldPalette;
821 TPaletteP m_newPalette;
822 bool m_isFrameInserted;
823
824 public:
825 PasteAreasUndo(TXshSimpleLevel *sl, const std::set<TFrameId> &frames, bool
826 isFrameInserted)
827 : TUndo()
828 , m_level(sl)
829 , m_frames(frames)
830 , m_isFrameInserted(isFrameInserted)
831 {
832 m_oldPalette = m_level->getPalette()->clone();
833 if(!m_isFrameInserted)
834 {
835 std::set<TFrameId>::iterator it;
836 for(it=m_frames.begin(); it!=m_frames.end(); it++)
837 {
838 TImageP img = m_level->getFrame(*it,true);
839 TImageCache::instance()->add("PasteAreasUndoOld"+QString::number((UINT)this)+QString::number((*it).getNumber()),
840 img->cloneImage());
841 }
842 }
843 }
844
845 void onAdd()
846 {
847 m_newPalette = m_level->getPalette()->clone();
848 std::set<TFrameId>::iterator it;
849 for(it=m_frames.begin(); it!=m_frames.end(); it++)
850 {
851 TImageP img = m_level->getFrame(*it,true);
852 TImageCache::instance()->add("PasteAreasUndoNew"+QString::number((UINT)this)+QString::number((*it).getNumber()),
853 img->cloneImage());
854 }
855 }
856
857 ~PasteAreasUndo() {
858 std::set<TFrameId>::const_iterator it;
859
860 if(!m_isFrameInserted)
861 {
862 for(it=m_frames.begin(); it!=m_frames.end(); it++)
863 TImageCache::instance()->remove("PasteAreasUndoOld"+QString::number((UINT)this)+QString::number((*it).getNumber()));
864 }
865 for(it=m_frames.begin(); it!=m_frames.end(); it++)
866 TImageCache::instance()->remove("PasteAreasUndoNew"+QString::number((UINT)this)+QString::number((*it).getNumber()));
867 }
868
869 void undo() const
870 {
871 std::set<TFrameId> frames = m_frames;
872
873 if(m_isFrameInserted)
874 {
875 // Faccio remove dei frame incollati
876 removeFramesWithoutUndo(m_level, frames);
877 }
878 else
879 {
880 std::set<TFrameId>::const_iterator it;
881 for(it=m_frames.begin(); it!=m_frames.end(); it++)
882 {
883 TImageP img =
884 TImageCache::instance()->get("PasteAreasUndoOld"+QString::number((UINT)this)+QString::number((*it).getNumber()),true);
885 assert(img);
886 m_level->setFrame(*it,img);
887 }
888 }
889
890 //Setto la vecchia paletta al livello
891 if(m_oldPalette.getPointer())
892 {
893 m_level->getPalette()->assign(m_oldPalette->clone());
894 TApp::instance()->getPaletteController()->getCurrentLevelPalette()->notifyPaletteChanged();
895 }
896
897 invalidateIcons(m_level.getPointer(), m_frames);
898 TApp::instance()->getCurrentLevel()->notifyLevelChange();
899 }
900
901 void redo() const
902 {
903 if(!m_level || m_frames.empty()) return;
904
905 std::set<TFrameId> frames = m_frames;
906
907 std::set<TFrameId>::const_iterator it;
908 for(it=m_frames.begin(); it!=m_frames.end(); it++)
909 {
910 TImageP img =
911 TImageCache::instance()->get("PasteAreasUndoNew"+QString::number((UINT)this)+QString::number((*it).getNumber()),true);
912 if(!img) continue;
913 m_level->setFrame(*it, img, true);
914 }
915
916 if(m_newPalette.getPointer())
917 {
918 m_level->getPalette()->assign(m_newPalette->clone());
919 TApp::instance()->getPaletteController()->getCurrentLevelPalette()->notifyPaletteChanged();
920 }
921
922 invalidateIcons(m_level.getPointer(), m_frames);
923 TApp::instance()->getCurrentLevel()->notifyLevelChange();
924 }
925
926 int getSize() const{
927 return sizeof(*this);
928 }
929 };*/
930
931 //=============================================================================
932 // PasteFramesUndo
933 //-----------------------------------------------------------------------------
934
935 class PasteFramesUndo final : public TUndo {
936 TXshSimpleLevelP m_sl;
937 std::set<TFrameId> m_frames;
938 std::vector<TFrameId> m_oldLevelFrameId;
939 TPaletteP m_oldPalette;
940 DrawingData *m_oldData;
941 DrawingData *m_newData;
942 DrawingData::ImageSetType m_setType;
943 HookSet *m_oldLevelHooks;
944 bool m_updateXSheet;
945 bool m_keepOriginalPalette;
946
947 public:
PasteFramesUndo(TXshSimpleLevel * sl,const std::set<TFrameId> & frames,const std::vector<TFrameId> & oldLevelFrameId,TPaletteP oldPalette,DrawingData::ImageSetType setType,HookSet * oldLevelHooks,bool keepOriginalPalette,DrawingData * oldData=0)948 PasteFramesUndo(TXshSimpleLevel *sl, const std::set<TFrameId> &frames,
949 const std::vector<TFrameId> &oldLevelFrameId,
950 TPaletteP oldPalette, DrawingData::ImageSetType setType,
951 HookSet *oldLevelHooks, bool keepOriginalPalette,
952 DrawingData *oldData = 0)
953 : m_sl(sl)
954 , m_frames(frames)
955 , m_oldLevelFrameId(oldLevelFrameId)
956 , m_oldPalette(oldPalette)
957 , m_setType(setType)
958 , m_keepOriginalPalette(keepOriginalPalette)
959 , m_oldData(oldData)
960 , m_oldLevelHooks(oldLevelHooks) {
961 QClipboard *clipboard = QApplication::clipboard();
962 QMimeData *data = cloneData(clipboard->mimeData());
963 m_newData = dynamic_cast<DrawingData *>(data);
964 assert(m_newData);
965 m_updateXSheet =
966 Preferences::instance()->isSyncLevelRenumberWithXsheetEnabled();
967 }
968
~PasteFramesUndo()969 ~PasteFramesUndo() {
970 if (m_oldData) m_oldData->releaseData();
971 if (m_newData) m_newData->releaseData();
972 }
973
undo() const974 void undo() const override {
975 TSelection *selection = TSelection::getCurrent();
976 if (selection) selection->selectNone();
977 std::set<TFrameId> frames = m_frames;
978
979 // Faccio remove dei frame incollati
980 if (m_setType != DrawingData::OVER_SELECTION)
981 removeFramesWithoutUndo(m_sl, frames);
982
983 // Renumero i frame con i vecchi fids
984 if (m_setType == DrawingData::INSERT) {
985 assert(m_sl->getFrameCount() == m_oldLevelFrameId.size());
986 if (m_updateXSheet) {
987 std::vector<TFrameId> newFrames;
988 m_sl->getFids(newFrames);
989 updateXSheet(m_sl.getPointer(), newFrames, m_oldLevelFrameId);
990 }
991 m_sl->renumber(m_oldLevelFrameId);
992 m_sl->setDirtyFlag(true);
993 TApp::instance()
994 ->getPaletteController()
995 ->getCurrentLevelPalette()
996 ->notifyPaletteChanged();
997 TApp::instance()->getCurrentLevel()->notifyLevelChange();
998 }
999
1000 // Reinserisco i vecchi frame che ho sovrascritto
1001 if (m_setType != DrawingData::INSERT) {
1002 std::set<TFrameId> framesToModify;
1003 m_oldData->getFrames(framesToModify);
1004
1005 bool dummy = true;
1006 // Incollo i frames sovrascrivendoli
1007 pasteFramesWithoutUndo(m_oldData, m_sl.getPointer(), framesToModify,
1008 DrawingData::OVER_SELECTION, true, dummy);
1009 }
1010
1011 // Setto la vecchia paletta al livello
1012 if (m_oldPalette.getPointer()) {
1013 TPalette *levelPalette = m_sl->getPalette();
1014 if (levelPalette) levelPalette->assign(m_oldPalette.getPointer());
1015
1016 TApp *app = TApp::instance();
1017 if (app->getCurrentLevel()->getLevel() == m_sl.getPointer())
1018 app->getPaletteController()
1019 ->getCurrentLevelPalette()
1020 ->notifyPaletteChanged();
1021 }
1022
1023 // update all icons
1024 std::vector<TFrameId> sl_fids;
1025 m_sl.getPointer()->getFids(sl_fids);
1026 invalidateIcons(m_sl.getPointer(), sl_fids);
1027
1028 *m_sl->getHookSet() = *m_oldLevelHooks;
1029 }
1030
redo() const1031 void redo() const override {
1032 if (!m_sl || m_frames.empty()) return;
1033 TSelection *selection = TSelection::getCurrent();
1034 if (selection) selection->selectNone();
1035 std::set<TFrameId> frames = m_frames;
1036
1037 bool keepOriginalPalette = m_keepOriginalPalette;
1038 pasteFramesWithoutUndo(m_newData, m_sl.getPointer(), frames, m_setType,
1039 true, keepOriginalPalette, true);
1040 }
1041
getSize() const1042 int getSize() const override { return sizeof(*this); }
1043
getHistoryString()1044 QString getHistoryString() override {
1045 QString str = QObject::tr("Paste : Level %1 : Frame ")
1046 .arg(QString::fromStdWString(m_sl->getName()));
1047
1048 std::set<TFrameId>::const_iterator it;
1049 for (it = m_frames.begin(); it != m_frames.end(); it++) {
1050 if (it != m_frames.begin()) str += QString(", ");
1051 str += QString::number((*it).getNumber());
1052 }
1053
1054 return str;
1055 }
getHistoryType()1056 int getHistoryType() override { return HistoryType::FilmStrip; }
1057 };
1058
1059 //=============================================================================
1060 // DeleteFramesUndo
1061 //-----------------------------------------------------------------------------
1062
1063 class DeleteFramesUndo final : public TUndo {
1064 TXshSimpleLevel *m_sl;
1065 std::set<TFrameId> m_frames;
1066 DrawingData *m_oldData;
1067 DrawingData *m_newData;
1068
1069 public:
DeleteFramesUndo(TXshSimpleLevel * sl,std::set<TFrameId> & frames,DrawingData * oldData,DrawingData * newData)1070 DeleteFramesUndo(TXshSimpleLevel *sl, std::set<TFrameId> &frames,
1071 DrawingData *oldData, DrawingData *newData)
1072 : m_sl(sl), m_frames(frames), m_oldData(oldData), m_newData(newData) {}
1073
~DeleteFramesUndo()1074 ~DeleteFramesUndo() {
1075 if (m_oldData) m_oldData->releaseData();
1076 if (m_newData) m_newData->releaseData();
1077 }
1078
pasteFramesFromData(const DrawingData * data) const1079 void pasteFramesFromData(const DrawingData *data) const {
1080 std::set<TFrameId> frames = m_frames;
1081
1082 bool dummy = true;
1083 // Incollo i frames sovrascrivendoli
1084 pasteFramesWithoutUndo(data, m_sl, frames, DrawingData::OVER_SELECTION,
1085 true, dummy);
1086 }
1087
undo() const1088 void undo() const override { pasteFramesFromData(m_oldData); }
1089
1090 // OSS.: Non posso usare il metodo "clearFramesWithoutUndo(...)" perche'
1091 // genera un NUOVO frame vuoto, perdendo quello precedente e le eventuali
1092 // modifiche che ad esso possono essere state fatte successivamente.
redo() const1093 void redo() const override { pasteFramesFromData(m_newData); }
1094
getSize() const1095 int getSize() const override { return sizeof(*this); }
1096
getHistoryString()1097 QString getHistoryString() override {
1098 QString str = QObject::tr("Delete Frames : Level %1 : Frame ")
1099 .arg(QString::fromStdWString(m_sl->getName()));
1100
1101 std::set<TFrameId>::const_iterator it;
1102 for (it = m_frames.begin(); it != m_frames.end(); it++) {
1103 if (it != m_frames.begin()) str += QString(", ");
1104 str += QString::number((*it).getNumber());
1105 }
1106
1107 return str;
1108 }
getHistoryType()1109 int getHistoryType() override { return HistoryType::FilmStrip; }
1110 };
1111
1112 //=============================================================================
1113
1114 //-----------------------------------------------------------------------------
1115
1116 class CutFramesUndo final : public TUndo {
1117 TXshSimpleLevel *m_sl;
1118 std::set<TFrameId> m_framesCutted;
1119 std::vector<TFrameId> m_oldFrames;
1120 DrawingData *m_newData;
1121
1122 public:
CutFramesUndo(TXshSimpleLevel * sl,std::set<TFrameId> & framesCutted,std::vector<TFrameId> & oldFrames)1123 CutFramesUndo(TXshSimpleLevel *sl, std::set<TFrameId> &framesCutted,
1124 std::vector<TFrameId> &oldFrames)
1125 : m_sl(sl), m_framesCutted(framesCutted), m_oldFrames(oldFrames) {
1126 QClipboard *clipboard = QApplication::clipboard();
1127 QMimeData *data = cloneData(clipboard->mimeData());
1128 m_newData = dynamic_cast<DrawingData *>(data);
1129 assert(m_newData);
1130 }
1131
~CutFramesUndo()1132 ~CutFramesUndo() {
1133 if (m_newData) m_newData->releaseData();
1134 }
1135
undo() const1136 void undo() const override {
1137 std::set<TFrameId> frames = m_framesCutted;
1138 bool dummy = true;
1139 pasteFramesWithoutUndo(m_newData, m_sl, frames, DrawingData::OVER_SELECTION,
1140 true, dummy);
1141 TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
1142 }
1143
redo() const1144 void redo() const override {
1145 // Prendo il clipboard corrente.
1146 QClipboard *clipboard = QApplication::clipboard();
1147 QMimeData *currentData = cloneData(clipboard->mimeData());
1148
1149 std::set<TFrameId> frames = m_framesCutted;
1150 cutFramesWithoutUndo(m_sl, frames);
1151
1152 // Setto il clipboard corrente
1153 clipboard->setMimeData(currentData, QClipboard::Clipboard);
1154 }
1155
getSize() const1156 int getSize() const override { return sizeof(*this); }
1157
getHistoryString()1158 QString getHistoryString() override {
1159 QString str = QObject::tr("Cut Frames : Level %1 : Frame ")
1160 .arg(QString::fromStdWString(m_sl->getName()));
1161
1162 std::set<TFrameId>::const_iterator it;
1163 for (it = m_framesCutted.begin(); it != m_framesCutted.end(); it++) {
1164 if (it != m_framesCutted.begin()) str += QString(", ");
1165 str += QString::number((*it).getNumber());
1166 }
1167
1168 return str;
1169 }
getHistoryType()1170 int getHistoryType() override { return HistoryType::FilmStrip; }
1171 };
1172
1173 } // namespace
1174
1175 //=============================================================================
1176
1177 //-----------------------------------------------------------------------------
1178
1179 namespace {
1180 //-----------------------------------------------------------------------------
1181
1182 class AddFramesUndo final : public TUndo {
1183 TXshSimpleLevelP m_level;
1184 std::set<TFrameId> m_insertedFids;
1185 std::vector<TFrameId> m_oldFids;
1186 bool m_updateXSheet;
1187
1188 public:
AddFramesUndo(const TXshSimpleLevelP & level,const std::set<TFrameId> insertedFids,std::vector<TFrameId> oldFids)1189 AddFramesUndo(const TXshSimpleLevelP &level,
1190 const std::set<TFrameId> insertedFids,
1191 std::vector<TFrameId> oldFids)
1192 : m_level(level), m_insertedFids(insertedFids), m_oldFids(oldFids) {
1193 m_updateXSheet =
1194 Preferences::instance()->isSyncLevelRenumberWithXsheetEnabled();
1195 }
1196
undo() const1197 void undo() const override {
1198 removeFramesWithoutUndo(m_level, m_insertedFids);
1199 if (m_updateXSheet) {
1200 std::vector<TFrameId> newFrames;
1201 m_level->getFids(newFrames);
1202 updateXSheet(m_level.getPointer(), newFrames, m_oldFids);
1203 }
1204 m_level->renumber(m_oldFids);
1205 m_level->setDirtyFlag(true);
1206
1207 TApp *app = TApp::instance();
1208 app->getCurrentScene()->setDirtyFlag(true);
1209 app->getCurrentLevel()->notifyLevelChange();
1210 }
1211
redo() const1212 void redo() const override {
1213 makeSpaceForFids(m_level.getPointer(), m_insertedFids);
1214
1215 for (auto const &fid : m_insertedFids) {
1216 m_level->setFrame(fid, m_level->createEmptyFrame());
1217 IconGenerator::instance()->invalidate(m_level.getPointer(), fid);
1218 }
1219 m_level->setDirtyFlag(true);
1220
1221 TApp *app = TApp::instance();
1222 app->getCurrentScene()->setDirtyFlag(true);
1223 app->getCurrentLevel()->notifyLevelChange();
1224 }
1225
getSize() const1226 int getSize() const override { return sizeof(*this); }
1227
getHistoryString()1228 QString getHistoryString() override {
1229 QString str = QObject::tr("Add Frames : Level %1 : Frame ")
1230 .arg(QString::fromStdWString(m_level->getName()));
1231
1232 std::set<TFrameId>::const_iterator it;
1233 for (it = m_insertedFids.begin(); it != m_insertedFids.end(); it++) {
1234 if (it != m_insertedFids.begin()) str += QString(", ");
1235 str += QString::number((*it).getNumber());
1236 }
1237
1238 return str;
1239 }
getHistoryType()1240 int getHistoryType() override { return HistoryType::FilmStrip; }
1241 };
1242
1243 } // namespace
1244
1245 //=============================================================================
1246 // AddFrames
1247 //-----------------------------------------------------------------------------
1248
addFrames(TXshSimpleLevel * sl,int start,int end,int step)1249 void FilmstripCmd::addFrames(TXshSimpleLevel *sl, int start, int end,
1250 int step) {
1251 if (start < 1 || step < 1 || start > end || !sl || sl->isSubsequence() ||
1252 sl->isReadOnly())
1253 return;
1254
1255 std::vector<TFrameId> oldFids;
1256 sl->getFids(oldFids);
1257
1258 std::set<TFrameId> fidsToInsert;
1259 int frame = 0;
1260 for (frame = start; frame <= end; frame += step)
1261 fidsToInsert.insert(TFrameId(frame));
1262
1263 makeSpaceForFids(sl, fidsToInsert);
1264
1265 for (auto const &fid : fidsToInsert) {
1266 sl->setFrame(fid, sl->createEmptyFrame());
1267 IconGenerator::instance()->invalidate(sl, fid);
1268 }
1269 sl->setDirtyFlag(true);
1270
1271 AddFramesUndo *undo = new AddFramesUndo(sl, fidsToInsert, oldFids);
1272 TUndoManager::manager()->add(undo);
1273
1274 TApp *app = TApp::instance();
1275 app->getCurrentScene()->setDirtyFlag(true);
1276 app->getCurrentLevel()->notifyLevelChange();
1277 }
1278
1279 //=============================================================================
1280 // RenumberUndo
1281 //-----------------------------------------------------------------------------
1282
1283 namespace {
1284
1285 class RenumberUndo final : public TUndo {
1286 TXshSimpleLevelP m_level;
1287 std::vector<TFrameId> m_fids;
1288 std::map<TFrameId, TFrameId> m_mapOldFrameId;
1289 bool m_updateXSheet = false;
1290
1291 public:
RenumberUndo(const TXshSimpleLevelP & level,const std::vector<TFrameId> & fids,bool forceCallUpdateXSheet=false)1292 RenumberUndo(const TXshSimpleLevelP &level, const std::vector<TFrameId> &fids,
1293 bool forceCallUpdateXSheet = false)
1294 : m_level(level), m_fids(fids) {
1295 assert(m_level);
1296 std::vector<TFrameId> oldFids;
1297 m_level->getFids(oldFids);
1298 assert(oldFids.size() == m_fids.size());
1299 int i;
1300 for (i = 0; i < m_fids.size(); i++) {
1301 if (m_fids[i] != oldFids[i]) m_mapOldFrameId[m_fids[i]] = oldFids[i];
1302 }
1303 m_updateXSheet =
1304 Preferences::instance()->isSyncLevelRenumberWithXsheetEnabled() ||
1305 forceCallUpdateXSheet;
1306 }
renumber(std::vector<TFrameId> fids) const1307 void renumber(std::vector<TFrameId> fids) const {
1308 if (m_updateXSheet) {
1309 std::vector<TFrameId> oldFrames;
1310 m_level->getFids(oldFrames);
1311 updateXSheet(m_level.getPointer(), oldFrames, fids);
1312 }
1313 m_level->renumber(fids);
1314 TSelection *selection = TSelection::getCurrent();
1315 if (selection) selection->selectNone();
1316 m_level->setDirtyFlag(true);
1317 TApp::instance()->getCurrentLevel()->notifyLevelChange();
1318 }
undo() const1319 void undo() const override {
1320 std::vector<TFrameId> fids;
1321 m_level->getFids(fids);
1322 assert(fids.size() == m_fids.size());
1323 int i;
1324 for (i = 0; i < fids.size(); i++) {
1325 if (m_mapOldFrameId.count(fids[i]) > 0) {
1326 std::map<TFrameId, TFrameId>::const_iterator it;
1327 it = m_mapOldFrameId.find(fids[i]);
1328 assert(it != m_mapOldFrameId.end());
1329 if (it != m_mapOldFrameId.end()) fids[i] = TFrameId(it->second);
1330 }
1331 }
1332 renumber(fids);
1333 }
redo() const1334 void redo() const override { renumber(m_fids); }
getSize() const1335 int getSize() const override {
1336 return sizeof(*this) + sizeof(TFrameId) * m_fids.size();
1337 }
1338
getHistoryString()1339 QString getHistoryString() override {
1340 return QObject::tr("Renumber : Level %1")
1341 .arg(QString::fromStdWString(m_level->getName()));
1342 }
getHistoryType()1343 int getHistoryType() override { return HistoryType::FilmStrip; }
1344 };
1345
1346 } // namespace
1347
1348 //=============================================================================
1349 // Renumber
1350 //-----------------------------------------------------------------------------
1351
renumber(TXshSimpleLevel * sl,const std::vector<std::pair<TFrameId,TFrameId>> & table,bool forceCallUpdateXSheet)1352 void FilmstripCmd::renumber(
1353 TXshSimpleLevel *sl,
1354 const std::vector<std::pair<TFrameId, TFrameId>> &table,
1355 bool forceCallUpdateXSheet) {
1356 if (!sl || sl->isSubsequence() || sl->isReadOnly()) return;
1357 if (table.empty()) return;
1358
1359 // table:src->dst; check that src is a fid of the level
1360 std::vector<std::pair<TFrameId, TFrameId>>::const_iterator it;
1361 for (it = table.begin(); it != table.end(); ++it) {
1362 TFrameId srcFid = it->first;
1363 if (!sl->isFid(srcFid)) {
1364 // todo: error messages
1365 return;
1366 }
1367 }
1368
1369 // tmp contains all the level fids that are not affected by the renumbering
1370 std::vector<TFrameId> fids, rfids, oldFrames;
1371 sl->getFids(fids);
1372 sl->getFids(oldFrames);
1373 std::set<TFrameId> tmp;
1374 for (int i = 0; i < (int)fids.size(); i++) tmp.insert(fids[i]);
1375 for (it = table.begin(); it != table.end(); ++it) tmp.erase(it->first);
1376
1377 // fids contain the new numbering of all the level drawings
1378 // (note: fids can be not ordered)
1379 for (int i = 0; i < (int)fids.size(); i++) {
1380 TFrameId srcFid = fids[i];
1381 for (it = table.begin(); it != table.end() && it->first != srcFid; ++it) {
1382 }
1383 if (it != table.end()) {
1384 // srcFid is affected by the renumbering
1385 TFrameId tarFid = it->second;
1386 // make sure that srcFid has not been used. add a letter if this is needed
1387 if (tmp.count(tarFid) > 0) {
1388 do {
1389 char letter = tarFid.getLetter();
1390 tarFid = TFrameId(tarFid.getNumber(), letter == 0 ? 'a' : letter + 1);
1391 } while (tarFid.getLetter() <= 'z' && tmp.count(tarFid) > 0);
1392 if (tarFid.getLetter() > 'z') {
1393 // todo: error message
1394 return;
1395 }
1396 }
1397 tmp.insert(tarFid);
1398 fids[i] = tarFid;
1399 }
1400 }
1401
1402 TUndoManager::manager()->add(
1403 new RenumberUndo(sl, fids, forceCallUpdateXSheet));
1404 if (Preferences::instance()->isSyncLevelRenumberWithXsheetEnabled() ||
1405 forceCallUpdateXSheet) {
1406 updateXSheet(sl, oldFrames, fids);
1407 }
1408 sl->renumber(fids);
1409 TApp::instance()->getCurrentScene()->setDirtyFlag(true);
1410 TApp::instance()->getCurrentLevel()->notifyLevelChange();
1411
1412 /*
1413 int i;
1414 std::set<TFrameId>::iterator it2;
1415 it2=frames.begin();
1416 std::set<TFrameId> newFrames;
1417 for (i=0; i<frames.size(); i++, it2++)
1418 newFrames.insert(TFrameId(startFrame+(i*stepFrame),it2->getLetter()));
1419 assert(frames.size()==newFrames.size());
1420 frames.swap(newFrames);
1421 */
1422 }
1423
1424 //-----------------------------------------------------------------------------
1425
renumber(TXshSimpleLevel * sl,std::set<TFrameId> & frames,int startFrame,int stepFrame)1426 void FilmstripCmd::renumber(TXshSimpleLevel *sl, std::set<TFrameId> &frames,
1427 int startFrame, int stepFrame) {
1428 if (!sl || sl->isSubsequence() || sl->isReadOnly()) return;
1429 assert(startFrame > 0 && stepFrame > 0);
1430 if (startFrame <= 0 || stepFrame <= 0 || frames.empty()) return;
1431
1432 std::vector<TFrameId> fids;
1433 std::vector<TFrameId> oldFrames;
1434 sl->getFids(oldFrames);
1435 sl->getFids(fids);
1436
1437 std::set<TFrameId> modifiedFids;
1438
1439 // tmp contiene i frames del livello, meno quelli da renumerare
1440 std::set<TFrameId> tmp(fids.begin(), fids.end());
1441 std::set<TFrameId>::const_iterator it;
1442 for (it = frames.begin(); it != frames.end(); ++it) tmp.erase(*it);
1443
1444 int frame = startFrame;
1445 std::vector<TFrameId>::iterator j = fids.begin();
1446 for (it = frames.begin(); it != frames.end(); ++it) {
1447 TFrameId srcFid(*it);
1448 TFrameId dstFid(frame);
1449 frame += stepFrame;
1450 // faccio il controllo su tmp e non su fids. considera:
1451 // fids = [1,2,3,4], renumber = [2->3,3->5]
1452 if (tmp.count(dstFid) > 0) {
1453 DVGui::error(("can't renumber: frame conflict"));
1454 return;
1455 }
1456 j = std::find(j, fids.end(), srcFid);
1457 // i frames selezionati fanno parte del livello sl. Quindi:
1458 assert(j != fids.end());
1459 assert(srcFid == *j);
1460 if (j == fids.end()) continue; // per sicurezza
1461 int k = std::distance(fids.begin(), j);
1462 if (srcFid != dstFid) {
1463 modifiedFids.insert(srcFid);
1464 modifiedFids.insert(dstFid);
1465 *j = dstFid;
1466 ++j;
1467 }
1468 }
1469 TUndoManager::manager()->add(new RenumberUndo(sl, fids));
1470 if (Preferences::instance()->isSyncLevelRenumberWithXsheetEnabled()) {
1471 updateXSheet(sl, oldFrames, fids);
1472 }
1473 sl->renumber(fids);
1474 sl->setDirtyFlag(true);
1475 TApp::instance()->getCurrentScene()->setDirtyFlag(true);
1476 int i;
1477 std::set<TFrameId>::iterator it2;
1478 it2 = frames.begin();
1479 std::set<TFrameId> newFrames;
1480 for (i = 0; i < frames.size(); i++, it2++)
1481 newFrames.insert(TFrameId(startFrame + (i * stepFrame), it2->getLetter()));
1482 assert(frames.size() == newFrames.size());
1483 frames.swap(newFrames);
1484
1485 TApp::instance()->getCurrentLevel()->notifyLevelChange();
1486 }
1487
1488 //=============================================================================
1489 // copy
1490 //-----------------------------------------------------------------------------
1491
copy(TXshSimpleLevel * sl,std::set<TFrameId> & frames)1492 void FilmstripCmd::copy(TXshSimpleLevel *sl, std::set<TFrameId> &frames) {
1493 if (!sl || frames.empty()) return;
1494 copyFramesWithoutUndo(sl, frames);
1495 }
1496
1497 //=============================================================================
1498 // paste
1499 //-----------------------------------------------------------------------------
1500
paste(TXshSimpleLevel * sl,std::set<TFrameId> & frames)1501 void FilmstripCmd::paste(TXshSimpleLevel *sl, std::set<TFrameId> &frames) {
1502 if (!sl || sl->isReadOnly() || frames.empty()) return;
1503
1504 std::vector<TFrameId> oldLevelFrameId;
1505 sl->getFids(oldLevelFrameId);
1506
1507 TPaletteP oldPalette;
1508 if (TPalette *pal = sl->getPalette()) oldPalette = pal->clone();
1509
1510 QClipboard *clipboard = QApplication::clipboard();
1511 QMimeData *data = cloneData(clipboard->mimeData());
1512 // when pasting the filmstrip frames
1513 DrawingData *drawingData = dynamic_cast<DrawingData *>(data);
1514 if (drawingData) {
1515 if (sl->isSubsequence()) return;
1516
1517 // keep the choosed option of "Keep Original Palette" and reproduce it in
1518 // undo
1519 bool keepOriginalPalette;
1520
1521 HookSet *oldLevelHooks = new HookSet();
1522 *oldLevelHooks = *sl->getHookSet();
1523
1524 bool isPaste =
1525 pasteFramesWithoutUndo(drawingData, sl, frames, DrawingData::INSERT,
1526 true, keepOriginalPalette);
1527 if (!isPaste) return;
1528 TUndoManager::manager()->add(new PasteFramesUndo(
1529 sl, frames, oldLevelFrameId, oldPalette, DrawingData::INSERT,
1530 oldLevelHooks, keepOriginalPalette));
1531 }
1532 // when pasting the copied part of the image which is selected with the
1533 // selection tool
1534 else {
1535 bool isFrameToInsert =
1536 (frames.size() == 1) ? !sl->isFid((*frames.begin())) : false;
1537 TTileSet *tileSet = 0;
1538 std::map<TFrameId, std::set<int>> indices;
1539 TUndo *undo = 0;
1540 TPaletteP plt = sl->getPalette()->clone();
1541 bool isPaste = pasteAreasWithoutUndo(data, sl, frames, &tileSet, indices);
1542 RasterImageData *rasterImageData = dynamic_cast<RasterImageData *>(data);
1543 StrokesData *strokesData = dynamic_cast<StrokesData *>(data);
1544 if (rasterImageData && tileSet)
1545 undo = new PasteRasterAreasUndo(sl, frames, tileSet, rasterImageData,
1546 plt.getPointer(), isFrameToInsert);
1547 if (strokesData && tileSet) {
1548 TImageP img = sl->getFrame(*frames.begin(), false);
1549 TRasterImageP ri = img;
1550 TToonzImageP ti = img;
1551 assert(img);
1552 if (ti)
1553 undo = new PasteRasterAreasUndo(sl, frames, tileSet,
1554 strokesData->toToonzImageData(ti),
1555 plt.getPointer(), isFrameToInsert);
1556 else if (ri) {
1557 double dpix, dpiy;
1558 ri->getDpi(dpix, dpiy);
1559 if (dpix == 0 || dpiy == 0) {
1560 TPointD dpi = sl->getScene()->getCurrentCamera()->getDpi();
1561 dpix = dpi.x;
1562 dpiy = dpi.y;
1563 ri->setDpi(dpix, dpiy);
1564 }
1565 undo = new PasteRasterAreasUndo(sl, frames, tileSet,
1566 strokesData->toFullColorImageData(ri),
1567 plt.getPointer(), isFrameToInsert);
1568 }
1569 }
1570 if (strokesData && !indices.empty())
1571 undo = new PasteVectorAreasUndo(sl, frames, indices, strokesData,
1572 plt.getPointer(), isFrameToInsert);
1573 if (rasterImageData && !indices.empty())
1574 undo = new PasteVectorAreasUndo(
1575 sl, frames, indices, rasterImageData->toStrokesData(sl->getScene()),
1576 plt.getPointer(), isFrameToInsert);
1577 if (!isPaste) return;
1578 if (undo) TUndoManager::manager()->add(undo);
1579 }
1580 }
1581
1582 //=============================================================================
1583 // merge
1584 //-----------------------------------------------------------------------------
1585
merge(TXshSimpleLevel * sl,std::set<TFrameId> & frames)1586 void FilmstripCmd::merge(TXshSimpleLevel *sl, std::set<TFrameId> &frames) {
1587 if (!sl || sl->isReadOnly() || sl->isSubsequence()) return;
1588
1589 std::vector<TFrameId> oldLevelFrameId;
1590 sl->getFids(oldLevelFrameId);
1591 TPaletteP oldPalette = sl->getPalette()->clone();
1592 std::set<TFrameId> frameIdToChange;
1593
1594 QClipboard *clipboard = QApplication::clipboard();
1595 if (const DrawingData *drawingData =
1596 dynamic_cast<const DrawingData *>(clipboard->mimeData())) {
1597 drawingData->getFrames(frameIdToChange);
1598 DrawingData *data = new DrawingData();
1599 data->setLevelFrames(sl, frameIdToChange);
1600 HookSet *oldLevelHooks = new HookSet();
1601 *oldLevelHooks = *sl->getHookSet();
1602
1603 bool keepOriginalPalette = true;
1604
1605 bool isPaste = pasteFramesWithoutUndo(drawingData, sl, frames,
1606 DrawingData::OVER_FRAMEID, true,
1607 keepOriginalPalette);
1608 if (!isPaste) return;
1609 TUndoManager::manager()->add(new PasteFramesUndo(
1610 sl, frames, oldLevelFrameId, oldPalette, DrawingData::OVER_FRAMEID,
1611 oldLevelHooks, keepOriginalPalette, data));
1612 }
1613 }
1614
1615 //=============================================================================
1616 // pasteInto
1617 //-----------------------------------------------------------------------------
1618
pasteInto(TXshSimpleLevel * sl,std::set<TFrameId> & frames)1619 void FilmstripCmd::pasteInto(TXshSimpleLevel *sl, std::set<TFrameId> &frames) {
1620 if (!sl || sl->isReadOnly() || sl->isSubsequence()) return;
1621
1622 std::vector<TFrameId> oldLevelFrameId;
1623 sl->getFids(oldLevelFrameId);
1624
1625 TPaletteP oldPalette;
1626 if (TPalette *pal = sl->getPalette()) oldPalette = pal->clone();
1627
1628 QClipboard *clipboard = QApplication::clipboard();
1629 if (const DrawingData *drawingData =
1630 dynamic_cast<const DrawingData *>(clipboard->mimeData())) {
1631 DrawingData *data = new DrawingData();
1632 data->setLevelFrames(sl, frames);
1633
1634 HookSet *oldLevelHooks = new HookSet();
1635 *oldLevelHooks = *sl->getHookSet();
1636
1637 bool keepOriginalPalette = true;
1638 bool isPaste = pasteFramesWithoutUndo(drawingData, sl, frames,
1639 DrawingData::OVER_SELECTION, true,
1640 keepOriginalPalette);
1641 if (!isPaste) return;
1642
1643 TUndoManager::manager()->add(new PasteFramesUndo(
1644 sl, frames, oldLevelFrameId, oldPalette, DrawingData::OVER_SELECTION,
1645 oldLevelHooks, keepOriginalPalette, data));
1646 }
1647 }
1648
1649 //=============================================================================
1650 // cut
1651 //-----------------------------------------------------------------------------
1652
cut(TXshSimpleLevel * sl,std::set<TFrameId> & frames)1653 void FilmstripCmd::cut(TXshSimpleLevel *sl, std::set<TFrameId> &frames) {
1654 if (!sl || frames.empty() || sl->isSubsequence() || sl->isReadOnly()) return;
1655
1656 std::set<TFrameId> framesToCut = frames;
1657 std::vector<TFrameId> oldFrames;
1658 sl->getFids(oldFrames);
1659 cutFramesWithoutUndo(sl, frames);
1660 TUndoManager::manager()->add(new CutFramesUndo(sl, framesToCut, oldFrames));
1661 }
1662
1663 //=============================================================================
1664 // clear
1665 //-----------------------------------------------------------------------------
1666
clear(TXshSimpleLevel * sl,std::set<TFrameId> & frames)1667 void FilmstripCmd::clear(TXshSimpleLevel *sl, std::set<TFrameId> &frames) {
1668 if (!sl || frames.empty()) return;
1669
1670 if (sl->isReadOnly()) {
1671 std::set<TFrameId> editableFrames = sl->getEditableRange();
1672 if (editableFrames.empty()) return;
1673
1674 // Browser all the frames and return if some frames are not editable
1675 std::set<TFrameId>::const_iterator it;
1676 for (it = frames.begin(); it != frames.end(); ++it) {
1677 TFrameId frameId = *it;
1678 if (editableFrames.count(frameId) == 0) return;
1679 }
1680 }
1681
1682 HookSet *levelHooks = sl->getHookSet();
1683 std::set<TFrameId> oldFrames = frames;
1684 std::map<TFrameId, QString> clearedFrames =
1685 clearFramesWithoutUndo(sl, frames);
1686 DrawingData *oldData = new DrawingData();
1687 oldData->setFrames(clearedFrames, sl, *levelHooks);
1688 DrawingData *newData = new DrawingData();
1689 newData->setLevelFrames(sl, frames);
1690 frames.clear();
1691 TUndoManager::manager()->add(
1692 new DeleteFramesUndo(sl, oldFrames, oldData, newData));
1693 }
1694
1695 //-----------------------------------------------------------------------------
1696 namespace {
1697 //-----------------------------------------------------------------------------
1698
insertEmptyFilmstripFrames(const TXshSimpleLevelP & sl,const std::set<TFrameId> & frames)1699 void insertEmptyFilmstripFrames(const TXshSimpleLevelP &sl,
1700 const std::set<TFrameId> &frames) {
1701 if (!sl || frames.empty()) return;
1702 makeSpaceForFids(sl.getPointer(), frames);
1703 std::set<TFrameId>::const_iterator it;
1704 for (it = frames.begin(); it != frames.end(); ++it)
1705 sl->setFrame(*it, sl->createEmptyFrame());
1706 invalidateIcons(sl.getPointer(), frames);
1707 sl->setDirtyFlag(true);
1708 // TApp::instance()->getCurrentScene()->setDirtyFlag(true);
1709 TApp::instance()->getCurrentLevel()->notifyLevelChange();
1710 }
1711
1712 //-----------------------------------------------------------------------------
1713
1714 class UndoInsertEmptyFrames final : public TUndo {
1715 TXshSimpleLevelP m_level;
1716 std::vector<TFrameId> m_oldFrames;
1717 std::set<TFrameId> m_frames;
1718 bool m_updateXSheet;
1719
1720 public:
UndoInsertEmptyFrames(const TXshSimpleLevelP & level,std::set<TFrameId> frames,std::vector<TFrameId> oldFrames)1721 UndoInsertEmptyFrames(const TXshSimpleLevelP &level,
1722 std::set<TFrameId> frames,
1723 std::vector<TFrameId> oldFrames)
1724 : m_level(level), m_frames(frames), m_oldFrames(oldFrames) {
1725 if (m_level->getType() == TZP_XSHLEVEL) {
1726 std::set<TFrameId>::iterator it;
1727 for (it = m_frames.begin(); it != m_frames.end(); it++) {
1728 TToonzImageP img = m_level->getFrame(*it, true);
1729 // TImageCache::instance()->add("UndoInsertEmptyFrames"+QString::number((UINT)this),
1730 // img);
1731 TImageCache::instance()->add(
1732 "UndoInsertEmptyFrames" + QString::number((uintptr_t)this), img);
1733 }
1734 }
1735 m_updateXSheet =
1736 Preferences::instance()->isSyncLevelRenumberWithXsheetEnabled();
1737 }
1738
~UndoInsertEmptyFrames()1739 ~UndoInsertEmptyFrames() {
1740 // TImageCache::instance()->remove("UndoInsertEmptyFrames"+QString::number((UINT)this));
1741 TImageCache::instance()->remove("UndoInsertEmptyFrames" +
1742 QString::number((uintptr_t)this));
1743 }
1744
undo() const1745 void undo() const override {
1746 removeFramesWithoutUndo(m_level, m_frames);
1747 assert(m_oldFrames.size() == m_level->getFrameCount());
1748 if (m_updateXSheet) {
1749 std::vector<TFrameId> newFrames;
1750 m_level->getFids(newFrames);
1751 updateXSheet(m_level.getPointer(), newFrames, m_oldFrames);
1752 }
1753 m_level->renumber(m_oldFrames);
1754 m_level->setDirtyFlag(true);
1755 TApp::instance()->getCurrentLevel()->notifyLevelChange();
1756 }
1757
redo() const1758 void redo() const override {
1759 if (!m_level || m_frames.empty()) return;
1760 if (m_level->getType() == PLI_XSHLEVEL)
1761 FilmstripCmd::insert(m_level.getPointer(), m_frames, false);
1762 else if (m_level->getType() == TZP_XSHLEVEL) {
1763 makeSpaceForFids(m_level.getPointer(), m_frames);
1764 std::set<TFrameId>::const_iterator it;
1765 // TToonzImageP image =
1766 // (TToonzImageP)TImageCache::instance()->get("UndoInsertEmptyFrames"+QString::number((UINT)this),
1767 // true);
1768 TToonzImageP image = (TToonzImageP)TImageCache::instance()->get(
1769 "UndoInsertEmptyFrames" + QString::number((uintptr_t)this), true);
1770 if (!image) return;
1771 for (it = m_frames.begin(); it != m_frames.end(); ++it)
1772 m_level->setFrame(*it, image);
1773 invalidateIcons(m_level.getPointer(), m_frames);
1774 m_level->setDirtyFlag(true);
1775 TApp::instance()->getCurrentLevel()->notifyLevelChange();
1776 }
1777 }
1778
getSize() const1779 int getSize() const override { return sizeof(*this); }
1780
getHistoryString()1781 QString getHistoryString() override {
1782 return QObject::tr("Insert : Level %1")
1783 .arg(QString::fromStdWString(m_level->getName()));
1784 }
getHistoryType()1785 int getHistoryType() override { return HistoryType::FilmStrip; }
1786 };
1787
1788 } // namespace
1789
1790 //=============================================================================
1791 // insert
1792 //-----------------------------------------------------------------------------
1793
insert(TXshSimpleLevel * sl,const std::set<TFrameId> & frames,bool withUndo)1794 void FilmstripCmd::insert(TXshSimpleLevel *sl, const std::set<TFrameId> &frames,
1795 bool withUndo) {
1796 if (frames.empty() || !sl || sl->isSubsequence() || sl->isReadOnly()) return;
1797 std::vector<TFrameId> oldFrames;
1798 if (withUndo) sl->getFids(oldFrames);
1799
1800 insertEmptyFilmstripFrames(sl, frames);
1801 if (withUndo)
1802 TUndoManager::manager()->add(
1803 new UndoInsertEmptyFrames(sl, frames, oldFrames));
1804 TApp::instance()->getCurrentScene()->setDirtyFlag(true);
1805 }
1806
1807 //=============================================================================
1808
1809 //-----------------------------------------------------------------------------
1810 namespace {
1811 //-----------------------------------------------------------------------------
1812
performReverse(const TXshSimpleLevelP & sl,const std::set<TFrameId> & frames)1813 void performReverse(const TXshSimpleLevelP &sl,
1814 const std::set<TFrameId> &frames) {
1815 if (!sl || frames.empty()) return;
1816
1817 std::vector<TFrameId> fids;
1818 std::vector<TFrameId> oldFrames;
1819 sl->getFids(oldFrames);
1820 sl->getFids(fids);
1821 int i = 0, j = (int)fids.size() - 1;
1822 for (;;) {
1823 while (i < j && frames.count(fids[i]) == 0) i++;
1824 while (i < j && frames.count(fids[j]) == 0) j--;
1825 if (i >= j) break;
1826 std::swap(fids[i], fids[j]);
1827 i++;
1828 j--;
1829 }
1830 if (Preferences::instance()->isSyncLevelRenumberWithXsheetEnabled()) {
1831 updateXSheet(sl.getPointer(), oldFrames, fids);
1832 }
1833 sl->renumber(fids);
1834 sl->setDirtyFlag(true);
1835 // TApp::instance()->getCurrentScene()->setDirtyFlag(true);
1836 TApp::instance()->getCurrentLevel()->notifyLevelChange();
1837 }
1838
1839 //-----------------------------------------------------------------------------
1840
1841 class FilmstripReverseUndo final : public TUndo {
1842 TXshSimpleLevelP m_level;
1843 std::set<TFrameId> m_frames;
1844
1845 public:
FilmstripReverseUndo(TXshSimpleLevelP level,std::set<TFrameId> frames)1846 FilmstripReverseUndo(TXshSimpleLevelP level, std::set<TFrameId> frames)
1847 : m_level(level), m_frames(frames) {}
1848
undo() const1849 void undo() const override { performReverse(m_level, m_frames); }
redo() const1850 void redo() const override { performReverse(m_level, m_frames); }
getSize() const1851 int getSize() const override { return sizeof *this; }
1852
getHistoryString()1853 QString getHistoryString() override {
1854 return QObject::tr("Reverse : Level %1")
1855 .arg(QString::fromStdWString(m_level->getName()));
1856 }
getHistoryType()1857 int getHistoryType() override { return HistoryType::FilmStrip; }
1858 };
1859
1860 } // namespace
1861
1862 //=============================================================================
1863 // reverse
1864 //-----------------------------------------------------------------------------
1865
reverse(TXshSimpleLevel * sl,std::set<TFrameId> & frames)1866 void FilmstripCmd::reverse(TXshSimpleLevel *sl, std::set<TFrameId> &frames) {
1867 if (!sl || sl->isSubsequence() || sl->isReadOnly()) return;
1868 performReverse(sl, frames);
1869 TUndoManager::manager()->add(new FilmstripReverseUndo(sl, frames));
1870 TApp::instance()->getCurrentScene()->setDirtyFlag(true);
1871 }
1872
1873 //=============================================================================
1874
1875 //-----------------------------------------------------------------------------
1876 namespace {
1877 //-----------------------------------------------------------------------------
1878
performSwing(const TXshSimpleLevelP & sl,const std::set<TFrameId> & frames)1879 void performSwing(const TXshSimpleLevelP &sl,
1880 const std::set<TFrameId> &frames) {
1881 if (!sl) return;
1882 int count = frames.size() - 1;
1883 if (count <= 0) return; // niente swing con un solo frame
1884 TFrameId lastFid = *frames.rbegin();
1885 TFrameId insertPoint = lastFid + 1;
1886 std::set<TFrameId> framesToInsert;
1887 int i;
1888 for (i = 0; i < count; i++) framesToInsert.insert(insertPoint + i);
1889
1890 std::vector<TImage *> clonedImages;
1891 std::set<TFrameId>::const_reverse_iterator k;
1892 k = frames.rbegin();
1893 for (++k; k != frames.rend(); ++k) {
1894 TImageP img = sl->getFrame(*k, false);
1895 clonedImages.push_back(img ? img->cloneImage() : 0);
1896 }
1897
1898 makeSpaceForFids(sl.getPointer(), framesToInsert);
1899 assert(count == (int)clonedImages.size());
1900 for (i = 0; i < count && (int)i < (int)clonedImages.size(); i++) {
1901 TImage *img = clonedImages[i];
1902 if (img) sl->setFrame(insertPoint + i, img);
1903 }
1904 invalidateIcons(sl.getPointer(), framesToInsert);
1905 sl->setDirtyFlag(true);
1906 // TApp::instance()->getCurrentScene()->setDirtyFlag(true);
1907 TApp::instance()->getCurrentLevel()->notifyLevelChange();
1908 }
1909
1910 //-----------------------------------------------------------------------------
1911
1912 class FilmstripSwingUndo final : public TUndo {
1913 TXshSimpleLevelP m_level;
1914 std::set<TFrameId> m_frames;
1915 std::set<TFrameId> m_newFrames;
1916
1917 public:
FilmstripSwingUndo(const TXshSimpleLevelP & level,const std::set<TFrameId> & frames)1918 FilmstripSwingUndo(const TXshSimpleLevelP &level,
1919 const std::set<TFrameId> &frames)
1920 : m_level(level), m_frames(frames) {
1921 int count = frames.size() - 1;
1922 if (count <= 0) return; // niente swing con un solo frame
1923 TFrameId lastFid = *frames.rbegin();
1924 TFrameId insertPoint = lastFid + 1;
1925 std::set<TFrameId> framesToInsert;
1926 int i;
1927 for (i = 0; i < count; i++) m_newFrames.insert(insertPoint + i);
1928 }
1929
undo() const1930 void undo() const override {
1931 TSelection *selection = TSelection::getCurrent();
1932 if (selection) selection->selectNone();
1933 removeFramesWithoutUndo(m_level, m_newFrames);
1934 }
redo() const1935 void redo() const override {
1936 TSelection *selection = TSelection::getCurrent();
1937 if (selection) selection->selectNone();
1938 performSwing(m_level, m_frames);
1939 }
getSize() const1940 int getSize() const override { return sizeof *this; }
1941
getHistoryString()1942 QString getHistoryString() override {
1943 return QObject::tr("Swing : Level %1")
1944 .arg(QString::fromStdWString(m_level->getName()));
1945 }
getHistoryType()1946 int getHistoryType() override { return HistoryType::FilmStrip; }
1947 };
1948
1949 } // namespace
1950
1951 //=============================================================================
1952 // swing
1953 //-----------------------------------------------------------------------------
1954
swing(TXshSimpleLevel * sl,std::set<TFrameId> & frames)1955 void FilmstripCmd::swing(TXshSimpleLevel *sl, std::set<TFrameId> &frames) {
1956 if (!sl || sl->isSubsequence() || sl->isReadOnly()) return;
1957 performSwing(sl, frames);
1958 TUndoManager::manager()->add(new FilmstripSwingUndo(sl, frames));
1959 TApp::instance()->getCurrentScene()->setDirtyFlag(true);
1960 }
1961
1962 //=============================================================================
1963
1964 //-----------------------------------------------------------------------------
1965 namespace {
1966 //-----------------------------------------------------------------------------
1967
stepFilmstripFrames(const TXshSimpleLevelP & sl,const std::set<TFrameId> & frames,int step=2)1968 void stepFilmstripFrames(const TXshSimpleLevelP &sl,
1969 const std::set<TFrameId> &frames, int step = 2) {
1970 if (!sl || frames.empty() || step < 2) return;
1971 std::vector<TFrameId> fids;
1972 std::set<TFrameId> changedFids;
1973 std::vector<int> insertIndices;
1974 std::vector<TFrameId> oldFrames;
1975 sl->getFids(oldFrames);
1976 sl->getFids(fids);
1977 int i, offset = 0;
1978 for (i = 0; i < (int)fids.size(); i++) {
1979 bool frameToStep = (frames.count(fids[i]) > 0);
1980 if (offset > 0) {
1981 changedFids.insert(fids[i]);
1982 fids[i] = fids[i] + offset;
1983 changedFids.insert(fids[i]);
1984 }
1985 if (frameToStep) {
1986 insertIndices.push_back(i);
1987 offset += step - 1;
1988 }
1989 }
1990 if (Preferences::instance()->isSyncLevelRenumberWithXsheetEnabled()) {
1991 updateXSheet(sl.getPointer(), oldFrames, fids);
1992 }
1993 sl->renumber(fids);
1994 for (i = 0; i < (int)insertIndices.size(); i++) {
1995 int j = insertIndices[i];
1996 TFrameId fid = fids[j];
1997 TImageP img = sl->getFrame(fid, false);
1998 if (img) {
1999 int h;
2000 for (h = 1; h < step; h++) {
2001 sl->setFrame(fid + h, img->cloneImage());
2002 changedFids.insert(fid + h);
2003 }
2004 }
2005 }
2006 invalidateIcons(sl.getPointer(), changedFids);
2007 sl->setDirtyFlag(true);
2008 TApp::instance()->getCurrentLevel()->notifyLevelChange();
2009 }
2010
2011 //-----------------------------------------------------------------------------
2012
2013 class StepFilmstripUndo final : public TUndo {
2014 TXshSimpleLevelP m_level;
2015 std::set<TFrameId> m_insertedFrames;
2016 std::set<TFrameId> m_frames;
2017 std::vector<TFrameId> m_oldFrames;
2018 int m_step;
2019 bool m_updateXSheet;
2020
2021 public:
StepFilmstripUndo(const TXshSimpleLevelP & level,const std::set<TFrameId> & frames,int step)2022 StepFilmstripUndo(const TXshSimpleLevelP &level,
2023 const std::set<TFrameId> &frames, int step)
2024 : m_level(level), m_frames(frames), m_step(step) {
2025 assert(m_level);
2026 m_level->getFids(m_oldFrames);
2027 int d = 0;
2028 std::set<TFrameId>::const_iterator it;
2029 for (it = frames.begin(); it != frames.end(); ++it)
2030 for (int j = 1; j < step; j++) m_insertedFrames.insert(*it + (++d));
2031 m_updateXSheet =
2032 Preferences::instance()->isSyncLevelRenumberWithXsheetEnabled();
2033 }
2034
undo() const2035 void undo() const override {
2036 removeFramesWithoutUndo(m_level, m_insertedFrames);
2037 std::set<TFrameId>::const_iterator it = m_frames.begin();
2038 if (m_updateXSheet) {
2039 std::vector<TFrameId> newFrames;
2040 m_level->getFids(newFrames);
2041 updateXSheet(m_level.getPointer(), newFrames, m_oldFrames);
2042 }
2043 m_level->renumber(m_oldFrames);
2044 TSelection *selection = TSelection::getCurrent();
2045 if (selection) selection->selectNone();
2046 m_level->setDirtyFlag(true);
2047 TApp::instance()->getCurrentLevel()->notifyLevelChange();
2048 }
redo() const2049 void redo() const override {
2050 TSelection *selection = TSelection::getCurrent();
2051 if (selection) selection->selectNone();
2052 stepFilmstripFrames(m_level, m_frames, m_step);
2053 }
getSize() const2054 int getSize() const override { return sizeof *this; }
2055
getHistoryString()2056 QString getHistoryString() override {
2057 return QObject::tr("Step %1 : Level %2")
2058 .arg(QString::number(m_step))
2059 .arg(QString::fromStdWString(m_level->getName()));
2060 }
getHistoryType()2061 int getHistoryType() override { return HistoryType::FilmStrip; }
2062 };
2063
2064 } // namespace
2065
2066 //=============================================================================
2067 // step
2068 //-----------------------------------------------------------------------------
2069
step(TXshSimpleLevel * sl,std::set<TFrameId> & frames,int step)2070 void FilmstripCmd::step(TXshSimpleLevel *sl, std::set<TFrameId> &frames,
2071 int step) {
2072 if (!sl || sl->isSubsequence() || sl->isReadOnly()) return;
2073 QApplication::setOverrideCursor(Qt::WaitCursor);
2074 StepFilmstripUndo *undo = new StepFilmstripUndo(sl, frames, step);
2075 stepFilmstripFrames(sl, frames, step);
2076 TUndoManager::manager()->add(undo);
2077 frames.clear();
2078 TApp::instance()->getCurrentScene()->setDirtyFlag(true);
2079 QApplication::restoreOverrideCursor();
2080 }
2081
2082 //=============================================================================
2083
2084 //-----------------------------------------------------------------------------
2085 namespace {
2086 //-----------------------------------------------------------------------------
2087
eachFilmstripFrames(const TXshSimpleLevelP & sl,const std::set<TFrameId> & frames,int each)2088 std::map<TFrameId, QString> eachFilmstripFrames(
2089 const TXshSimpleLevelP &sl, const std::set<TFrameId> &frames, int each) {
2090 if (frames.empty() || !sl || each < 2) return std::map<TFrameId, QString>();
2091 std::vector<TFrameId> framesToDelete;
2092 std::set<TFrameId>::const_iterator it;
2093 int k = 0;
2094 for (it = frames.begin(); it != frames.end(); ++it, ++k)
2095 if ((k % each) > 0) framesToDelete.push_back(*it);
2096 int i = 0;
2097 std::vector<TFrameId>::reverse_iterator fit;
2098 std::map<TFrameId, QString> cutFrames;
2099
2100 for (fit = framesToDelete.rbegin(); fit != framesToDelete.rend(); ++fit) {
2101 TImageP img = sl->getFrame(*fit, false);
2102 if (img) {
2103 // QString id =
2104 // "eachFrames"+QString::number((UINT)sl.getPointer())+"-"+QString::number(fit->getNumber());
2105 QString id = "eachFrames" + QString::number((uintptr_t)sl.getPointer()) +
2106 "-" + QString::number(fit->getNumber());
2107 TImageCache::instance()->add(id, img);
2108
2109 cutFrames[*fit] = id;
2110 }
2111 sl->eraseFrame(*fit); // toglie da cache?
2112 IconGenerator::instance()->remove(sl.getPointer(), *fit);
2113 }
2114
2115 TApp::instance()->getCurrentLevel()->notifyLevelChange();
2116 return cutFrames;
2117 }
2118
2119 //-----------------------------------------------------------------------------
2120
2121 class EachFilmstripUndo final : public TUndo {
2122 TXshSimpleLevelP m_level;
2123 std::set<TFrameId> m_frames;
2124 std::map<TFrameId, QString> m_cutFrames;
2125 int m_each;
2126
2127 public:
EachFilmstripUndo(const TXshSimpleLevelP & level,int each,const std::set<TFrameId> & frames,std::map<TFrameId,QString> deletedFrames)2128 EachFilmstripUndo(const TXshSimpleLevelP &level, int each,
2129 const std::set<TFrameId> &frames,
2130 std::map<TFrameId, QString> deletedFrames)
2131 : m_level(level)
2132 , m_cutFrames(deletedFrames)
2133 , m_each(each)
2134 , m_frames(frames) {}
~EachFilmstripUndo()2135 ~EachFilmstripUndo() {
2136 std::map<TFrameId, QString>::iterator it = m_cutFrames.begin();
2137 for (; it != m_cutFrames.end(); ++it)
2138 TImageCache::instance()->remove(it->second);
2139 }
undo() const2140 void undo() const override {
2141 TSelection *selection = TSelection::getCurrent();
2142 if (selection) selection->selectNone();
2143 insertNotEmptyframes(m_level, m_cutFrames);
2144 }
redo() const2145 void redo() const override {
2146 TSelection *selection = TSelection::getCurrent();
2147 if (selection) selection->selectNone();
2148 eachFilmstripFrames(m_level, m_frames, m_each);
2149 }
getSize() const2150 int getSize() const override { return sizeof *this; }
2151
getHistoryString()2152 QString getHistoryString() override {
2153 return QObject::tr("Each %1 : Level %2")
2154 .arg(QString::number(m_each))
2155 .arg(QString::fromStdWString(m_level->getName()));
2156 }
getHistoryType()2157 int getHistoryType() override { return HistoryType::FilmStrip; }
2158 };
2159
2160 } // namespace
2161
2162 //=============================================================================
2163 // each
2164 //-----------------------------------------------------------------------------
2165
each(TXshSimpleLevel * sl,std::set<TFrameId> & frames,int each)2166 void FilmstripCmd::each(TXshSimpleLevel *sl, std::set<TFrameId> &frames,
2167 int each) {
2168 if (!sl || sl->isSubsequence() || sl->isReadOnly()) return;
2169 std::map<TFrameId, QString> deletedFrames =
2170 eachFilmstripFrames(sl, frames, each);
2171 TUndoManager::manager()->add(
2172 new EachFilmstripUndo(sl, each, frames, deletedFrames));
2173 frames.clear();
2174 TApp::instance()->getCurrentScene()->setDirtyFlag(true);
2175 }
2176
2177 //=============================================================================
2178
2179 //-----------------------------------------------------------------------------
2180 namespace {
2181 //-----------------------------------------------------------------------------
2182
2183 class UndoDuplicateDrawing final : public TUndo {
2184 TXshSimpleLevelP m_level;
2185 std::set<TFrameId> m_frameInserted;
2186 std::vector<TFrameId> m_oldFrames;
2187 std::set<TFrameId> m_framesForRedo;
2188 bool m_updateXSheet;
2189
2190 public:
UndoDuplicateDrawing(const TXshSimpleLevelP & level,const std::vector<TFrameId> oldFrames,std::set<TFrameId> frameInserted,std::set<TFrameId> framesForRedo)2191 UndoDuplicateDrawing(const TXshSimpleLevelP &level,
2192 const std::vector<TFrameId> oldFrames,
2193 std::set<TFrameId> frameInserted,
2194 std::set<TFrameId> framesForRedo)
2195 : m_level(level)
2196 , m_oldFrames(oldFrames)
2197 , m_frameInserted(frameInserted)
2198 , m_framesForRedo(framesForRedo) {
2199 m_updateXSheet =
2200 Preferences::instance()->isSyncLevelRenumberWithXsheetEnabled();
2201 }
2202
undo() const2203 void undo() const override {
2204 assert(m_level);
2205 removeFramesWithoutUndo(m_level, m_frameInserted);
2206 if (m_updateXSheet) {
2207 std::vector<TFrameId> newFrames;
2208 m_level->getFids(newFrames);
2209 updateXSheet(m_level.getPointer(), newFrames, m_oldFrames);
2210 }
2211 m_level->renumber(m_oldFrames);
2212 m_level->setDirtyFlag(true);
2213 TApp::instance()->getCurrentLevel()->notifyLevelChange();
2214 }
redo() const2215 void redo() const override {
2216 std::set<TFrameId> framesForRedo = m_framesForRedo;
2217 FilmstripCmd::duplicate(m_level.getPointer(), framesForRedo, false);
2218 }
getSize() const2219 int getSize() const override { return sizeof(*this); }
2220
getHistoryString()2221 QString getHistoryString() override {
2222 return QObject::tr("Duplicate : Level %1")
2223 .arg(QString::fromStdWString(m_level->getName()));
2224 }
getHistoryType()2225 int getHistoryType() override { return HistoryType::FilmStrip; }
2226 };
2227
2228 } // namespace
2229
2230 //=============================================================================
2231 // duplicate
2232 //-----------------------------------------------------------------------------
2233
duplicateFrameWithoutUndo(TXshSimpleLevel * sl,TFrameId srcFrame,TFrameId targetFrame)2234 void FilmstripCmd::duplicateFrameWithoutUndo(TXshSimpleLevel *sl,
2235 TFrameId srcFrame,
2236 TFrameId targetFrame) {
2237 if (srcFrame.isNoFrame() || targetFrame.isNoFrame()) return;
2238 if (srcFrame.isEmptyFrame()) return;
2239
2240 std::set<TFrameId> frames;
2241
2242 frames.insert(srcFrame);
2243 DrawingData *data = new DrawingData();
2244 data->setLevelFrames(sl, frames);
2245
2246 frames.clear();
2247 frames.insert(targetFrame);
2248
2249 bool keepOriginalPalette = true;
2250
2251 pasteFramesWithoutUndo(data, sl, frames, DrawingData::OVER_SELECTION, true,
2252 keepOriginalPalette);
2253 }
2254
duplicate(TXshSimpleLevel * sl,std::set<TFrameId> & frames,bool withUndo)2255 void FilmstripCmd::duplicate(TXshSimpleLevel *sl, std::set<TFrameId> &frames,
2256 bool withUndo) {
2257 if (frames.empty() || !sl || sl->isSubsequence() || sl->isReadOnly()) return;
2258
2259 TFrameId insertPoint = (*frames.rbegin()) + 1;
2260
2261 std::map<TFrameId, QString> framesToInsert;
2262 std::set<TFrameId> newFrames;
2263 int i = 0;
2264 for (auto const &fid : frames) {
2265 TImageP img = sl->getFrame(fid, false);
2266 TImageP imgClone = (img) ? img->cloneImage() : 0;
2267 QString id = "dupFrames" + QString::number((uintptr_t)sl) + "-" +
2268 QString::number(fid.getNumber());
2269 TImageCache::instance()->add(id, imgClone);
2270 framesToInsert[insertPoint + i] = id;
2271 newFrames.insert(insertPoint + i);
2272 i++;
2273 }
2274 std::vector<TFrameId> oldFrames;
2275 sl->getFids(oldFrames);
2276 insertNotEmptyframes(sl, framesToInsert);
2277 if (withUndo)
2278 TUndoManager::manager()->add(
2279 new UndoDuplicateDrawing(sl, oldFrames, newFrames, frames));
2280 TApp::instance()->getCurrentScene()->setDirtyFlag(true);
2281 }
2282
2283 //=============================================================================
2284
2285 //-----------------------------------------------------------------------------
2286 namespace {
2287 //-----------------------------------------------------------------------------
2288
moveToSceneFrames(TXshLevel * level,const std::set<TFrameId> & frames)2289 void moveToSceneFrames(TXshLevel *level, const std::set<TFrameId> &frames) {
2290 if (frames.empty() || !level) return;
2291
2292 TXsheetHandle *xh = TApp::instance()->getCurrentXsheet();
2293 TXsheet *xsh = xh->getXsheet();
2294 int row = 0;
2295 int col = xsh->getFirstFreeColumnIndex();
2296 std::set<TFrameId>::const_iterator it;
2297 if (level->getPaletteLevel()) {
2298 TXshPaletteColumn *column = new TXshPaletteColumn;
2299 xsh->insertColumn(col, column);
2300 }
2301 for (it = frames.begin(); it != frames.end(); ++it) {
2302 xsh->setCell(row, col, TXshCell(level, *it));
2303 ++row;
2304 }
2305 xh->notifyXsheetChanged();
2306 }
2307
2308 //-----------------------------------------------------------------------------
2309
2310 class MoveLevelToSceneUndo final : public TUndo {
2311 std::wstring m_levelName;
2312 int m_col;
2313 std::set<TFrameId> m_fids;
2314
2315 public:
MoveLevelToSceneUndo(std::wstring levelName,int col,std::set<TFrameId> fids)2316 MoveLevelToSceneUndo(std::wstring levelName, int col, std::set<TFrameId> fids)
2317 : m_levelName(levelName), m_col(col), m_fids(fids) {}
2318
undo() const2319 void undo() const override {
2320 TApp *app = TApp::instance();
2321 TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
2322 ToonzScene *scene = app->getCurrentScene()->getScene();
2323 TXshLevel *xl = scene->getLevelSet()->getLevel(m_levelName);
2324 if (xl->getPaletteLevel()) xsh->removeColumn(m_col);
2325 xsh->clearCells(0, m_col, m_fids.size());
2326 app->getCurrentXsheet()->notifyXsheetChanged();
2327 }
redo() const2328 void redo() const override {
2329 TApp *app = TApp::instance();
2330 ToonzScene *scene = app->getCurrentScene()->getScene();
2331 TXshLevel *xl = scene->getLevelSet()->getLevel(m_levelName);
2332 if (!xl) return;
2333 moveToSceneFrames(xl, m_fids);
2334 }
getSize() const2335 int getSize() const override { return sizeof *this; }
2336
getHistoryString()2337 QString getHistoryString() override {
2338 return QObject::tr("Move Level to Scene : Level %1")
2339 .arg(QString::fromStdWString(m_levelName));
2340 }
getHistoryType()2341 int getHistoryType() override { return HistoryType::FilmStrip; }
2342 };
2343
2344 } // namespace
2345
2346 //=============================================================================
2347 // moveToScene
2348 //-----------------------------------------------------------------------------
2349
moveToScene(TXshLevel * sl,std::set<TFrameId> & frames)2350 void FilmstripCmd::moveToScene(TXshLevel *sl, std::set<TFrameId> &frames) {
2351 if (frames.empty() || !sl) return;
2352
2353 TXsheetHandle *xh = TApp::instance()->getCurrentXsheet();
2354 TXsheet *xsh = xh->getXsheet();
2355 int row = 0;
2356 int col = xsh->getFirstFreeColumnIndex();
2357 std::set<TFrameId>::const_iterator it;
2358 for (it = frames.begin(); it != frames.end(); ++it) {
2359 xsh->setCell(row, col, TXshCell(sl, *it));
2360 ++row;
2361 }
2362 xh->notifyXsheetChanged();
2363 TUndoManager::manager()->add(
2364 new MoveLevelToSceneUndo(sl->getName(), col, frames));
2365 TApp::instance()->getCurrentScene()->setDirtyFlag(true);
2366 }
2367
2368 //-----------------------------------------------------------------------------
2369
moveToScene(TXshSimpleLevel * sl)2370 void FilmstripCmd::moveToScene(TXshSimpleLevel *sl) {
2371 std::vector<TFrameId> fids;
2372 sl->getFids(fids);
2373 std::set<TFrameId> fidsSet(fids.begin(), fids.end());
2374 moveToScene(sl, fidsSet);
2375 }
2376
2377 //-----------------------------------------------------------------------------
2378
moveToScene(TXshPaletteLevel * pl)2379 void FilmstripCmd::moveToScene(TXshPaletteLevel *pl) {
2380 if (!pl) return;
2381 std::set<TFrameId> fidsSet;
2382 fidsSet.insert(TFrameId(1));
2383
2384 TXsheetHandle *xh = TApp::instance()->getCurrentXsheet();
2385 TXsheet *xsh = xh->getXsheet();
2386 int row = 0;
2387 int col = xsh->getFirstFreeColumnIndex();
2388 TXshPaletteColumn *column = new TXshPaletteColumn;
2389 xsh->insertColumn(col, column);
2390 std::set<TFrameId>::const_iterator it;
2391 for (it = fidsSet.begin(); it != fidsSet.end(); ++it) {
2392 xsh->setCell(row, col, TXshCell(pl, *it));
2393 ++row;
2394 }
2395 xh->notifyXsheetChanged();
2396 TUndoManager::manager()->add(
2397 new MoveLevelToSceneUndo(pl->getName(), col, fidsSet));
2398 TApp::instance()->getCurrentScene()->setDirtyFlag(true);
2399 }
2400
2401 //-----------------------------------------------------------------------------
2402
moveToScene(TXshSoundLevel * sl)2403 void FilmstripCmd::moveToScene(TXshSoundLevel *sl) {
2404 std::vector<TFrameId> fids;
2405 sl->getFids(fids);
2406 std::set<TFrameId> fidsSet(fids.begin(), fids.end());
2407 moveToScene(sl, fidsSet);
2408 }
2409
2410 //=============================================================================
2411 // UndoInbetween
2412 //-----------------------------------------------------------------------------
2413
2414 namespace {
2415
2416 class UndoInbetween final : public TUndo {
2417 TXshSimpleLevelP m_level;
2418 std::vector<TFrameId> m_fids;
2419 std::vector<TVectorImageP> m_images;
2420 FilmstripCmd::InbetweenInterpolation m_interpolation;
2421
2422 public:
UndoInbetween(TXshSimpleLevel * xl,std::vector<TFrameId> fids,FilmstripCmd::InbetweenInterpolation interpolation)2423 UndoInbetween(TXshSimpleLevel *xl, std::vector<TFrameId> fids,
2424 FilmstripCmd::InbetweenInterpolation interpolation)
2425 : m_level(xl), m_fids(fids), m_interpolation(interpolation) {
2426 std::vector<TFrameId>::iterator it = fids.begin();
2427 // mi salvo tutte le immagine
2428 for (; it != fids.end(); ++it)
2429 m_images.push_back(m_level->getFrame(
2430 *it, false)); // non si fa clone perche' il livello subito dopo
2431 // rilascia queste immagini a causa dell'inbetweener
2432 }
2433
undo() const2434 void undo() const override {
2435 UINT levelSize = m_fids.size() - 1;
2436 for (UINT count = 1; count != levelSize; count++) {
2437 TVectorImageP vImage = m_images[count];
2438 m_level->setFrame(m_fids[count], vImage);
2439 IconGenerator::instance()->invalidate(m_level.getPointer(),
2440 m_fids[count]);
2441 }
2442
2443 TApp::instance()->getCurrentLevel()->notifyLevelChange();
2444 }
2445
redo() const2446 void redo() const override {
2447 TFrameId fid0 = *m_fids.begin();
2448 TFrameId fid1 = *(--m_fids.end());
2449 FilmstripCmd::inbetweenWithoutUndo(m_level.getPointer(), fid0, fid1,
2450 m_interpolation);
2451 }
2452
getSize() const2453 int getSize() const override {
2454 assert(!m_images.empty());
2455 return m_images.size() * m_images.front()->getStrokeCount() * 100;
2456 }
2457
getHistoryString()2458 QString getHistoryString() override {
2459 QString str = QObject::tr("Inbetween : Level %1, ")
2460 .arg(QString::fromStdWString(m_level->getName()));
2461 switch (m_interpolation) {
2462 case FilmstripCmd::II_Linear:
2463 str += QString("Linear Interpolation");
2464 break;
2465 case FilmstripCmd::II_EaseIn:
2466 str += QString("Ease In Interpolation");
2467 break;
2468 case FilmstripCmd::II_EaseOut:
2469 str += QString("Ease Out Interpolation");
2470 break;
2471 case FilmstripCmd::II_EaseInOut:
2472 str += QString("Ease In-Out Interpolation");
2473 break;
2474 }
2475 return str;
2476 }
getHistoryType()2477 int getHistoryType() override { return HistoryType::FilmStrip; }
2478 };
2479
2480 } // namespace
2481
2482 //=============================================================================
2483 // inbetween
2484 //-----------------------------------------------------------------------------
2485
inbetweenWithoutUndo(TXshSimpleLevel * sl,const TFrameId & fid0,const TFrameId & fid1,FilmstripCmd::InbetweenInterpolation interpolation)2486 void FilmstripCmd::inbetweenWithoutUndo(
2487 TXshSimpleLevel *sl, const TFrameId &fid0, const TFrameId &fid1,
2488 FilmstripCmd::InbetweenInterpolation interpolation) {
2489 if (!sl) return;
2490 std::vector<TFrameId> fids;
2491 sl->getFids(fids);
2492 std::vector<TFrameId>::iterator it;
2493 it = std::find(fids.begin(), fids.end(), fid0);
2494 if (it == fids.end()) return;
2495 int ia = std::distance(fids.begin(), it);
2496 it = std::find(fids.begin(), fids.end(), fid1);
2497 if (it == fids.end()) return;
2498 int ib = std::distance(fids.begin(), it);
2499 if (ib - ia < 2) return;
2500
2501 TVectorImageP img0 = sl->getFrame(fid0, false);
2502 TVectorImageP img1 = sl->getFrame(fid1, false);
2503 if (!img0 || !img1) return;
2504
2505 enum TInbetween::TweenAlgorithm algorithm;
2506 switch (interpolation) {
2507 case II_Linear:
2508 algorithm = TInbetween::LinearInterpolation;
2509 break;
2510 case II_EaseIn:
2511 algorithm = TInbetween::EaseInInterpolation;
2512 break;
2513 case II_EaseOut:
2514 algorithm = TInbetween::EaseOutInterpolation;
2515 break;
2516 case II_EaseInOut:
2517 algorithm = TInbetween::EaseInOutInterpolation;
2518 break;
2519 }
2520
2521 TInbetween inbetween(img0, img1);
2522 int i;
2523 for (i = ia + 1; i < ib; i++) {
2524 double t = (double)(i - ia) / (double)(ib - ia);
2525 double s = TInbetween::interpolation(t, algorithm);
2526
2527 TVectorImageP vi = inbetween.tween(s);
2528 sl->setFrame(fids[i], vi);
2529 IconGenerator::instance()->invalidate(sl, fids[i]);
2530 }
2531 sl->setDirtyFlag(true);
2532 TApp::instance()->getCurrentLevel()->notifyLevelChange();
2533 }
2534
2535 //-----------------------------------------------------------------------------
2536
inbetween(TXshSimpleLevel * sl,const TFrameId & fid0,const TFrameId & fid1,FilmstripCmd::InbetweenInterpolation interpolation)2537 void FilmstripCmd::inbetween(
2538 TXshSimpleLevel *sl, const TFrameId &fid0, const TFrameId &fid1,
2539 FilmstripCmd::InbetweenInterpolation interpolation) {
2540 std::vector<TFrameId> fids;
2541 std::vector<TFrameId> levelFids;
2542 sl->getFids(levelFids);
2543 for (auto const &fid : levelFids) {
2544 int curFid = fid.getNumber();
2545 if (fid0.getNumber() <= curFid && curFid <= fid1.getNumber())
2546 fids.push_back(fid);
2547 }
2548
2549 TUndoManager::manager()->add(new UndoInbetween(sl, fids, interpolation));
2550
2551 inbetweenWithoutUndo(sl, fid0, fid1, interpolation);
2552 TApp::instance()->getCurrentScene()->setDirtyFlag(true);
2553 }
2554
2555 //-----------------------------------------------------------------------------
2556
renumberDrawing(TXshSimpleLevel * sl,const TFrameId & oldFid,const TFrameId & desiredNewFid)2557 void FilmstripCmd::renumberDrawing(TXshSimpleLevel *sl, const TFrameId &oldFid,
2558 const TFrameId &desiredNewFid) {
2559 if (oldFid == desiredNewFid) return;
2560 std::vector<TFrameId> fids;
2561 std::vector<TFrameId> oldFrames;
2562 sl->getFids(oldFrames);
2563 sl->getFids(fids);
2564 std::vector<TFrameId>::iterator it =
2565 std::find(fids.begin(), fids.end(), oldFid);
2566 if (it == fids.end()) return;
2567 TFrameId newFid = desiredNewFid;
2568 while (std::find(fids.begin(), fids.end(), newFid) != fids.end()) {
2569 char letter = newFid.getLetter();
2570 if (letter == 'z') return;
2571 if (letter == 0)
2572 letter = 'a';
2573 else
2574 letter++;
2575 newFid = TFrameId(newFid.getNumber(), letter);
2576 }
2577 *it = newFid;
2578 if (Preferences::instance()->isSyncLevelRenumberWithXsheetEnabled()) {
2579 updateXSheet(sl, oldFrames, fids);
2580 }
2581 sl->renumber(fids);
2582 sl->setDirtyFlag(true);
2583
2584 TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
2585 TApp::instance()->getCurrentLevel()->notifyLevelChange();
2586 TApp::instance()->getCurrentScene()->setDirtyFlag(true);
2587 }
2588