1
2
3 #include "filmstrip.h"
4
5 // Tnz6 includes
6 #include "tapp.h"
7 #include "filmstripcommand.h"
8 #include "frameheadgadget.h"
9 #include "floatingpanelcommand.h"
10 #include "menubarcommandids.h"
11 #include "filmstripselection.h"
12 #include "onionskinmaskgui.h"
13 #include "comboviewerpane.h"
14
15 // TnzQt includes
16 #include "toonzqt/icongenerator.h"
17 #include "toonzqt/trepetitionguard.h"
18 #include "toonzqt/gutil.h"
19 #include "toonzqt/tselectionhandle.h"
20
21 // TnzLib includes
22 #include "toonz/txshlevelhandle.h"
23 #include "toonz/tcolumnhandle.h"
24 #include "toonz/txsheethandle.h"
25 #include "toonz/tframehandle.h"
26 #include "toonz/tonionskinmaskhandle.h"
27 #include "toonz/tobjecthandle.h"
28 #include "toonz/txshleveltypes.h"
29 #include "toonz/txshsimplelevel.h"
30 #include "toonz/stage2.h"
31 #include "toonz/levelproperties.h"
32 #include "toonz/palettecontroller.h"
33 #include "toonz/tpalettehandle.h"
34 #include "toonz/tscenehandle.h"
35 #include "toonz/toonzscene.h"
36 #include "toonz/levelset.h"
37 #include "toonz/preferences.h"
38
39 // TnzCore includes
40 #include "tpalette.h"
41
42 // Qt includes
43 #include <QPainter>
44 #include <QScrollBar>
45 #include <QComboBox>
46 #include <QPushButton>
47 #include <QSettings>
48 #include <QApplication>
49 #include <QMainWindow>
50 #include <QMimeData>
51 #include <QDrag>
52
53 namespace {
fidToFrameNumberWithLetter(int f)54 QString fidToFrameNumberWithLetter(int f) {
55 QString str = QString::number((int)(f / 10));
56 while (str.length() < 3) str.push_front("0");
57 switch (f % 10) {
58 case 1:
59 str.append('A');
60 break;
61 case 2:
62 str.append('B');
63 break;
64 case 3:
65 str.append('C');
66 break;
67 case 4:
68 str.append('D');
69 break;
70 case 5:
71 str.append('E');
72 break;
73 case 6:
74 str.append('F');
75 break;
76 case 7:
77 str.append('G');
78 break;
79 case 8:
80 str.append('H');
81 break;
82 case 9:
83 str.append('I');
84 break;
85 default:
86 str.append(' ');
87 break;
88 }
89 return str;
90 }
91 } // namespace
92
93 //=============================================================================
94 // Filmstrip
95 //-----------------------------------------------------------------------------
96
97 #if QT_VERSION >= 0x050500
FilmstripFrames(QScrollArea * parent,Qt::WindowFlags flags)98 FilmstripFrames::FilmstripFrames(QScrollArea *parent, Qt::WindowFlags flags)
99 #else
100 FilmstripFrames::FilmstripFrames(QScrollArea *parent, Qt::WFlags flags)
101 #endif
102 : QFrame(parent, flags)
103 , m_scrollArea(parent)
104 , m_selection(new TFilmstripSelection())
105 , m_frameHeadGadget(0)
106 , m_inbetweenDialog(0)
107 , m_pos(0, 0)
108 , m_iconSize(dimension2QSize(IconGenerator::instance()->getIconSize()))
109 , m_frameLabelWidth(11)
110 , m_selectingRange(0, 0)
111 , m_scrollSpeed(0)
112 , m_dragSelectionStartIndex(-1)
113 , m_dragSelectionEndIndex(-1)
114 , m_timerId(0)
115 , m_selecting(false)
116 , m_dragDropArmed(false)
117 , m_readOnly(false) {
118 setObjectName("filmStripFrames");
119 setFrameStyle(QFrame::StyledPanel);
120
121 setFocusPolicy(Qt::StrongFocus);
122 if (m_isVertical) {
123 setFixedWidth(m_iconSize.width() + fs_leftMargin + fs_rightMargin +
124 fs_iconMarginLR * 2);
125 setFixedHeight(parentWidget()->height());
126 } else {
127 setFixedHeight(parentWidget()->height());
128 setFixedWidth(parentWidget()->width());
129 }
130
131 // la testa mobile che indica il frame corrente (e gestisce la GUI dell'onion
132 // skin)
133 m_frameHeadGadget = new FilmstripFrameHeadGadget(this);
134 installEventFilter(m_frameHeadGadget);
135
136 m_selection->setView(this);
137 setMouseTracking(true);
138
139 m_viewer = NULL;
140 }
141
142 //-----------------------------------------------------------------------------
143
~FilmstripFrames()144 FilmstripFrames::~FilmstripFrames() {
145 delete m_selection;
146 delete m_frameHeadGadget;
147 }
148
149 //-----------------------------------------------------------------------------
150
getLevel() const151 TXshSimpleLevel *FilmstripFrames::getLevel() const {
152 TXshLevel *xl = TApp::instance()->getCurrentLevel()->getLevel();
153 return xl ? xl->getSimpleLevel() : 0;
154 }
155
156 //-----------------------------------------------------------------------------
157
y2index(int y) const158 int FilmstripFrames::y2index(int y) const {
159 const int dy = getIconSize().height() + fs_frameSpacing + fs_iconMarginTop +
160 fs_iconMarginBottom;
161 return y / dy;
162 }
163
164 //-----------------------------------------------------------------------------
165
x2index(int x) const166 int FilmstripFrames::x2index(int x) const {
167 const int dx = getIconSize().width() + fs_frameSpacing + fs_iconMarginLR +
168 fs_leftMargin + fs_rightMargin;
169 return x / dx;
170 }
171
172 //-----------------------------------------------------------------------------
173
index2y(int index) const174 int FilmstripFrames::index2y(int index) const {
175 const int dy = getIconSize().height() + fs_frameSpacing + fs_iconMarginTop +
176 fs_iconMarginBottom;
177 return index * dy;
178 }
179
180 //-----------------------------------------------------------------------------
181
index2x(int index) const182 int FilmstripFrames::index2x(int index) const {
183 const int dx = getIconSize().width() + fs_frameSpacing + fs_iconMarginLR +
184 fs_leftMargin + fs_rightMargin;
185 return index * dx;
186 }
187
188 //-----------------------------------------------------------------------------
189
index2fid(int index) const190 TFrameId FilmstripFrames::index2fid(int index) const {
191 TXshSimpleLevel *sl = getLevel();
192 if (!sl || index < 0) return TFrameId();
193 return sl->index2fid(index);
194 }
195
196 //-----------------------------------------------------------------------------
197
fid2index(const TFrameId & fid) const198 int FilmstripFrames::fid2index(const TFrameId &fid) const {
199 TXshSimpleLevel *sl = getLevel();
200 if (!sl) return -1;
201 return sl->guessIndex(fid); // ATTENZIONE: dovrebbe usare fid2index()
202 }
203
204 //-----------------------------------------------------------------------------
205
getFramesHeight() const206 int FilmstripFrames::getFramesHeight() const {
207 TXshSimpleLevel *level = getLevel();
208 int frameCount = level ? level->getFrameCount() : 1;
209 int frameHeight = m_iconSize.height() + fs_frameSpacing + fs_iconMarginTop +
210 fs_iconMarginBottom;
211 return frameHeight * (frameCount + 1);
212 }
213
214 //-----------------------------------------------------------------------------
215
getFramesWidth() const216 int FilmstripFrames::getFramesWidth() const {
217 TXshSimpleLevel *level = getLevel();
218 int frameCount = level ? level->getFrameCount() : 1;
219 int frameWidth = m_iconSize.width() + fs_frameSpacing + fs_leftMargin +
220 fs_rightMargin + fs_iconMarginLR;
221 return frameWidth * (frameCount + 1);
222 }
223
224 //-----------------------------------------------------------------------------
225
getOneFrameHeight()226 int FilmstripFrames::getOneFrameHeight() {
227 return m_iconSize.height() + fs_frameSpacing + fs_iconMarginTop +
228 fs_iconMarginBottom;
229 }
230
231 //-----------------------------------------------------------------------------
232
getOneFrameWidth()233 int FilmstripFrames::getOneFrameWidth() {
234 return m_iconSize.width() + fs_frameSpacing + fs_leftMargin +
235 fs_iconMarginLR + fs_rightMargin;
236 }
237
238 //-----------------------------------------------------------------------------
updateContentHeight(int minimumHeight)239 void FilmstripFrames::updateContentHeight(int minimumHeight) {
240 if (minimumHeight < 0)
241 minimumHeight = visibleRegion().boundingRect().bottom();
242 int contentHeight = getFramesHeight();
243 if (contentHeight < minimumHeight) contentHeight = minimumHeight;
244 int parentHeight = parentWidget()->height();
245 if (contentHeight < parentHeight) contentHeight = parentHeight;
246 if (contentHeight != height()) setFixedHeight(contentHeight);
247 }
248
249 //-----------------------------------------------------------------------------
updateContentWidth(int minimumWidth)250 void FilmstripFrames::updateContentWidth(int minimumWidth) {
251 setFixedHeight(getOneFrameHeight());
252 if (minimumWidth < 0) minimumWidth = visibleRegion().boundingRect().right();
253 int contentWidth = getFramesWidth();
254 if (contentWidth < minimumWidth) contentWidth = minimumWidth;
255 int parentWidth = parentWidget()->width();
256 if (contentWidth < parentWidth) contentWidth = parentWidth;
257 if (contentWidth != width()) setFixedWidth(contentWidth);
258 }
259
260 //-----------------------------------------------------------------------------
261
showFrame(int index)262 void FilmstripFrames::showFrame(int index) {
263 TXshSimpleLevel *level = getLevel();
264 if (m_isVertical) {
265 if (!level->isFid(index2fid(index))) {
266 if (!level->isFid(index2fid(index))) return;
267 }
268 int y0 = index2y(index);
269 int y1 = y0 + m_iconSize.height() + fs_frameSpacing + fs_iconMarginTop +
270 fs_iconMarginBottom;
271 if (y1 > height()) setFixedHeight(y1);
272 m_scrollArea->ensureVisible(0, (y0 + y1) / 2, 50, (y1 - y0) / 2);
273 } else {
274 if (!level->isFid(index2fid(index))) {
275 if (!level->isFid(index2fid(index - 1))) return;
276 }
277 int x0 = index2x(index);
278 int x1 = x0 + m_iconSize.width() + fs_frameSpacing + fs_leftMargin +
279 fs_rightMargin + fs_iconMarginLR;
280 if (x1 > width()) setFixedWidth(x1);
281 m_scrollArea->ensureVisible((x0 + x1) / 2, 0, (x1 - x0) / 2, 50);
282 }
283 }
284
285 //-----------------------------------------------------------------------------
286
scroll(int dy)287 void FilmstripFrames::scroll(int dy) {
288 if (m_isVertical) {
289 QScrollBar *sb = m_scrollArea->verticalScrollBar();
290 int sbValue = sb->value();
291
292 updateContentHeight(getFramesHeight());
293 if (sbValue + dy > getFramesHeight()) {
294 sb->setValue(getFramesHeight());
295 return;
296 }
297 sb->setValue(sbValue + dy);
298 } else {
299 QScrollBar *sb = m_scrollArea->horizontalScrollBar();
300 int sbValue = sb->value();
301
302 updateContentWidth(getFramesWidth());
303 if (sbValue + dy > getFramesWidth()) {
304 sb->setValue(getFramesWidth());
305 return;
306 }
307 sb->setValue(sbValue + dy);
308 }
309 }
310
311 //---------------------------------------------------------------------------
312
mouseDoubleClickEvent(QMouseEvent * event)313 void FilmstripFrames::mouseDoubleClickEvent(QMouseEvent *event) {
314 int index;
315 if (m_isVertical) {
316 index = y2index(event->pos().y());
317 } else {
318 index = x2index(event->pos().x());
319 }
320 select(index, ONLY_SELECT); // ONLY_SELECT
321 }
322
323 //-----------------------------------------------------------------------------
324
select(int index,SelectionMode mode)325 void FilmstripFrames::select(int index, SelectionMode mode) {
326 TXshSimpleLevel *sl = getLevel();
327 bool outOfRange = !sl || index < 0 || index >= sl->getFrameCount();
328
329 TFrameId fid;
330 if (!outOfRange) fid = index2fid(index);
331
332 switch (mode) {
333 // select one frame only
334 case ONLY_SELECT:
335 m_selection->selectNone();
336 if (!outOfRange) m_selection->select(fid);
337 break;
338 case SIMPLE_SELECT:
339 // Bail out if fid is already selected
340 if (!outOfRange && m_selection->isSelected(fid)) return;
341
342 m_selection->selectNone();
343 if (!outOfRange) m_selection->select(fid);
344 break;
345
346 case SHIFT_SELECT:
347 if (outOfRange) return;
348
349 // Bail out if fid is already selected
350 if (m_selection->isSelected(fid)) return;
351
352 if (m_selection->isEmpty())
353 m_selection->select(fid);
354 else {
355 TXshSimpleLevel *sl = getLevel();
356 if (!sl) return;
357
358 // seleziono il range da fid al piu' vicino frame selezionato (in entrambe
359 // le direzioni)
360 int frameCount = sl->getFrameCount();
361
362 // calcolo il limite inferiore della selezione
363 int ia = index;
364 while (ia > 0 && !m_selection->isSelected(sl->index2fid(ia - 1))) ia--;
365 if (ia == 0) ia = index;
366
367 // calcolo il limite superiore della selezione
368 int ib = index;
369 while (ib < frameCount - 1 &&
370 !m_selection->isSelected(sl->index2fid(ib + 1)))
371 ib++;
372 if (ib == frameCount - 1) ib = index;
373
374 // seleziono
375 for (int i = ia; i <= ib; i++) m_selection->select(sl->index2fid(i));
376 }
377 break;
378
379 case CTRL_SELECT:
380 if (outOfRange) return;
381
382 m_selection->select(fid, !m_selection->isSelected(fid));
383 break;
384
385 case START_DRAG_SELECT:
386 m_selection->selectNone();
387
388 if (outOfRange) {
389 m_dragSelectionStartIndex = m_dragSelectionEndIndex = -1;
390
391 break;
392 }
393
394 m_selection->select(fid);
395 m_dragSelectionStartIndex = index;
396 break;
397
398 case DRAG_SELECT:
399 if (outOfRange || m_dragSelectionStartIndex < 0 ||
400 m_dragSelectionEndIndex == index)
401 return;
402
403 m_dragSelectionEndIndex = index;
404
405 m_selection->selectNone();
406
407 int ia = m_dragSelectionStartIndex;
408 int ib = index;
409
410 if (ia > ib) std::swap(ia, ib);
411
412 for (int i = ia; i <= ib; ++i) m_selection->select(index2fid(i));
413
414 break;
415 }
416
417 TObjectHandle *objectHandle = TApp::instance()->getCurrentObject();
418 if (objectHandle->isSpline()) objectHandle->setIsSpline(false);
419
420 // Update current selection
421 m_selection->makeCurrent();
422
423 TSelectionHandle *selHandle = TApp::instance()->getCurrentSelection();
424 selHandle->notifySelectionChanged();
425 }
426
427 //-----------------------------------------------------------------------------
428
showEvent(QShowEvent *)429 void FilmstripFrames::showEvent(QShowEvent *) {
430 TApp *app = TApp::instance();
431
432 // cambiamenti al livello
433 TXshLevelHandle *levelHandle = app->getCurrentLevel();
434 bool ret = true;
435 ret = ret && connect(levelHandle, SIGNAL(xshLevelSwitched(TXshLevel *)), this,
436 SLOT(onLevelSwitched(TXshLevel *)));
437 ret = ret && connect(levelHandle, SIGNAL(xshLevelChanged()), this,
438 SLOT(onLevelChanged()));
439 ret = ret && connect(levelHandle, SIGNAL(xshLevelViewChanged()), this,
440 SLOT(onLevelChanged()));
441
442 // al frame corrente
443 ret = ret && connect(app->getCurrentFrame(), SIGNAL(frameSwitched()), this,
444 SLOT(onFrameSwitched()));
445 ret = ret && connect(app->getCurrentFrame(), SIGNAL(frameTypeChanged()), this,
446 SLOT(update()));
447
448 // iconcine
449 ret = ret && connect(IconGenerator::instance(), SIGNAL(iconGenerated()), this,
450 SLOT(update()));
451
452 // onion skin
453 ret = ret && connect(app->getCurrentOnionSkin(),
454 SIGNAL(onionSkinMaskChanged()), this, SLOT(update()));
455
456 // active viewer change
457 ret = ret &&
458 connect(app, SIGNAL(activeViewerChanged()), this, SLOT(getViewer()));
459
460 assert(ret);
461 getViewer();
462 }
463
464 //-----------------------------------------------------------------------------
465
hideEvent(QHideEvent *)466 void FilmstripFrames::hideEvent(QHideEvent *) {
467 TApp *app = TApp::instance();
468
469 // cambiamenti al livello
470 disconnect(app->getCurrentLevel(), 0, this, 0);
471
472 // al frame corrente
473 disconnect(app->getCurrentFrame(), SIGNAL(frameSwitched()), this,
474 SLOT(onFrameSwitched()));
475 disconnect(app->getCurrentFrame(), SIGNAL(frameTypeChanged()), this,
476 SLOT(update()));
477
478 // iconcine
479 disconnect(IconGenerator::instance(), SIGNAL(iconGenerated()), this,
480 SLOT(update()));
481
482 // onion skin
483 disconnect(app->getCurrentOnionSkin(), SIGNAL(onionSkinMaskChanged()), this,
484 SLOT(update()));
485
486 // active viewer change
487 disconnect(app, SIGNAL(activeViewerChanged()), this, SLOT(getViewer()));
488
489 if (m_viewer) {
490 disconnect(m_viewer, SIGNAL(onZoomChanged()), this, SLOT(update()));
491 disconnect(m_viewer, SIGNAL(refreshNavi()), this, SLOT(update()));
492 m_viewer = nullptr;
493 }
494 }
495
496 //-----------------------------------------------------------------------------
497
getViewer()498 void FilmstripFrames::getViewer() {
499 bool viewerChanged = false;
500 if (m_viewer != TApp::instance()->getActiveViewer()) {
501 if (m_viewer) {
502 disconnect(m_viewer, SIGNAL(onZoomChanged()), this, SLOT(update()));
503 disconnect(m_viewer, SIGNAL(refreshNavi()), this, SLOT(update()));
504 disconnect(m_viewer, SIGNAL(aboutToBeDestroyed()), this,
505 SLOT(onViewerAboutToBeDestroyed()));
506 }
507 viewerChanged = true;
508 }
509
510 m_viewer = TApp::instance()->getActiveViewer();
511
512 if (m_viewer && viewerChanged) {
513 connect(m_viewer, SIGNAL(onZoomChanged()), this, SLOT(update()));
514 connect(m_viewer, SIGNAL(refreshNavi()), this, SLOT(update()));
515 connect(m_viewer, SIGNAL(aboutToBeDestroyed()), this,
516 SLOT(onViewerAboutToBeDestroyed()));
517 update();
518 }
519 }
520
521 //-----------------------------------------------------------------------------
522
paintEvent(QPaintEvent * evt)523 void FilmstripFrames::paintEvent(QPaintEvent *evt) {
524 QPainter p(this);
525
526 // p.setRenderHint(QPainter::Antialiasing, true);
527
528 QRect clipRect = evt->rect();
529
530 p.fillRect(clipRect, Qt::black);
531 // thumbnail rect, including offsets
532 QRect iconImgRect = QRect(QPoint(fs_leftMargin + fs_iconMarginLR,
533 fs_frameSpacing / 2 + fs_iconMarginTop),
534 m_iconSize);
535 // frame size with margins
536 QSize frameSize = m_iconSize + QSize(fs_iconMarginLR * 2,
537 fs_iconMarginTop + fs_iconMarginBottom);
538 // .. and with offset
539 QRect frameRect =
540 QRect(QPoint(fs_leftMargin, fs_frameSpacing / 2), frameSize);
541
542 int oneFrameHeight = frameSize.height() + fs_frameSpacing;
543 int oneFrameWidth = frameSize.width() + fs_frameSpacing;
544
545 // visible frame index range
546 int i0, i1;
547 if (m_isVertical) {
548 i0 = y2index(clipRect.top());
549 i1 = y2index(clipRect.bottom());
550 } else {
551 i0 = x2index(clipRect.left());
552 i1 = x2index(clipRect.right());
553 }
554
555 // fids, frameCount <- frames del livello
556 std::vector<TFrameId> fids;
557 TXshSimpleLevel *sl = getLevel();
558 if (sl)
559 sl->getFids(fids);
560 else {
561 for (int i = i0; i <= i1; i++) {
562 // draw white rectangles if obtaining the level is failed
563 QRect iconRect;
564 if (m_isVertical) {
565 iconRect = frameRect.translated(QPoint(0, oneFrameHeight * i));
566 } else {
567 iconRect = frameRect.translated(QPoint(oneFrameWidth * i, 0));
568 }
569 p.setBrush(QColor(192, 192, 192));
570 p.setPen(Qt::NoPen);
571 p.drawRect(iconRect);
572 }
573 return;
574 }
575
576 //--- compute navigator rect ---
577
578 QRect naviRect;
579
580 if ((sl->getType() == TZP_XSHLEVEL || sl->getType() == OVL_XSHLEVEL) &&
581 m_viewer && m_viewer->isVisible()) {
582 // imgSize: image's pixel size
583 QSize imgSize(sl->getProperties()->getImageRes().lx,
584 sl->getProperties()->getImageRes().ly);
585 // Viewer affine
586 TAffine viewerAff = m_viewer->getViewMatrix();
587 // pixel size which will be displayed with 100% scale in Viewer Stage
588 TFrameId currentId = TApp::instance()->getCurrentFrame()->getFid();
589 double imgPixelWidth =
590 (double)(imgSize.width()) / sl->getDpi(currentId).x * Stage::inch;
591 double imgPixelHeight =
592 (double)(imgSize.height()) / sl->getDpi(currentId).y * Stage::inch;
593
594 // get the image's corner positions in viewer matrix (with current zoom
595 // scale)
596 TPointD imgTopRight =
597 viewerAff * TPointD(imgPixelWidth / 2.0f, imgPixelHeight / 2.0f);
598 TPointD imgBottomLeft =
599 viewerAff * TPointD(-imgPixelWidth / 2.0f, -imgPixelHeight / 2.0f);
600
601 // pixel size in viewer matrix ( with current zoom scale )
602 QSizeF imgSizeInViewer(imgTopRight.x - imgBottomLeft.x,
603 imgTopRight.y - imgBottomLeft.y);
604
605 // ratio of the Viewer frame's position and size
606 QRectF naviRatio(
607 (-(float)m_viewer->width() * 0.5f - (float)imgBottomLeft.x) /
608 imgSizeInViewer.width(),
609 1.0f - ((float)m_viewer->height() * 0.5f - (float)imgBottomLeft.y) /
610 imgSizeInViewer.height(),
611 (float)m_viewer->width() / imgSizeInViewer.width(),
612 (float)m_viewer->height() / imgSizeInViewer.height());
613
614 naviRect = QRect(iconImgRect.left() +
615 (int)(naviRatio.left() * (float)iconImgRect.width()),
616 iconImgRect.top() +
617 (int)(naviRatio.top() * (float)iconImgRect.height()),
618 (int)((float)iconImgRect.width() * naviRatio.width()),
619 (int)((float)iconImgRect.height() * naviRatio.height()));
620 // for drag move
621 m_naviRectPos = naviRect.center();
622
623 naviRect = naviRect.intersected(frameRect);
624
625 m_icon2ViewerRatio.setX(imgSizeInViewer.width() /
626 (float)iconImgRect.width());
627 m_icon2ViewerRatio.setY(imgSizeInViewer.height() /
628 (float)iconImgRect.height());
629 }
630
631 //--- compute navigator rect end ---
632
633 int frameCount = (int)fids.size();
634
635 bool isReadOnly = false;
636 if (sl) isReadOnly = sl->isReadOnly();
637
638 int i;
639 int iconWidth = m_iconSize.width();
640 int x0 = m_frameLabelWidth;
641 int x1 = x0 + iconWidth;
642 int frameHeight = m_iconSize.height();
643
644 // linee orizzontali che separano i frames
645 p.setPen(getLightLineColor());
646 for (i = i0; i <= i1; i++) {
647 if (m_isVertical) {
648 int y = index2y(i) + frameHeight;
649 p.drawLine(0, y, x1, y);
650 } else {
651 int x = index2x(i) + iconWidth;
652 p.drawLine(x, 0, x, frameHeight);
653 }
654 }
655
656 TFilmstripSelection::InbetweenRange range = m_selection->getInbetweenRange();
657
658 // draw for each frames
659 for (i = i0; i <= i1; i++) {
660 QRect tmp_iconImgRect, tmp_frameRect;
661 if (m_isVertical) {
662 tmp_iconImgRect = iconImgRect.translated(QPoint(0, oneFrameHeight * i));
663 tmp_frameRect = frameRect.translated(QPoint(0, oneFrameHeight * i));
664 } else {
665 tmp_iconImgRect = iconImgRect.translated(QPoint(oneFrameWidth * i, 0));
666 tmp_frameRect = frameRect.translated(QPoint(oneFrameWidth * i, 0));
667 }
668 bool isCurrentFrame =
669 (i == sl->fid2index(TApp::instance()->getCurrentFrame()->getFid()));
670 bool isSelected =
671 (0 <= i && i < frameCount && m_selection->isSelected(fids[i]));
672 TFrameId fid;
673 if (0 <= i && i < frameCount) {
674 fid = fids[i];
675 // normal or inbetween (for vector levels)
676 int flags = (sl->getType() == PLI_XSHLEVEL && range.first < fid &&
677 fid < range.second)
678 ? F_INBETWEEN_RANGE
679 : F_NORMAL;
680
681 // draw icons
682 drawFrameIcon(p, tmp_iconImgRect, i, fid, flags);
683
684 p.setPen(Qt::NoPen);
685 p.setBrush(Qt::NoBrush);
686 p.drawRect(tmp_iconImgRect);
687
688 // Frame number
689 if (m_selection->isSelected(fids[i])) {
690 if (TApp::instance()->getCurrentFrame()->isEditingLevel() &&
691 isCurrentFrame)
692 p.setPen(Qt::red);
693 else
694 p.setPen(Qt::white);
695 } else
696 p.setPen(QColor(192, 192, 192));
697
698 p.setBrush(Qt::NoBrush);
699 // for single frame
700 QString text;
701 if (fid.getNumber() == TFrameId::EMPTY_FRAME ||
702 fid.getNumber() == TFrameId::NO_FRAME) {
703 text = QString("Single Frame");
704 }
705 // for sequencial frame (with letter)
706 else if (Preferences::instance()->isShowFrameNumberWithLettersEnabled()) {
707 text = fidToFrameNumberWithLetter(fid.getNumber());
708 }
709 // for sequencial frame
710 else {
711 char letter = fid.getLetter();
712 text = QString::number(fid.getNumber()).rightJustified(4, '0') +
713 (letter != '\0' ? QString(letter) : "");
714 }
715 p.drawText(tmp_frameRect.adjusted(0, 0, -3, 2), text,
716 QTextOption(Qt::AlignRight | Qt::AlignBottom));
717 p.setPen(Qt::NoPen);
718
719 // Read-only frames (lock)
720 if (0 <= i && i < frameCount) {
721 if (sl->isFrameReadOnly(fids[i])) {
722 static QPixmap lockPixmap(":Resources/forbidden.png");
723 p.drawPixmap(tmp_frameRect.bottomLeft() + QPoint(3, -13), lockPixmap);
724 }
725 }
726 }
727
728 // navigator rect
729 if (m_showNavigator && naviRect.isValid() && fid >= 0 &&
730 fid == getCurrentFrameId()) {
731 p.setPen(QPen(Qt::red, 1));
732 if (m_isVertical) {
733 p.drawRect(naviRect.translated(0, oneFrameHeight * i));
734 } else {
735 p.drawRect(naviRect.translated(oneFrameWidth * i, 0));
736 }
737 p.setPen(Qt::NoPen);
738 }
739
740 // red frame for the current frame
741 if (TApp::instance()->getCurrentFrame()->isEditingLevel() &&
742 (isCurrentFrame || isSelected)) {
743 QPen pen;
744 pen.setColor(Qt::red);
745 pen.setWidth(2);
746 pen.setJoinStyle(Qt::RoundJoin);
747 p.setPen(pen);
748
749 p.drawRect(tmp_frameRect.adjusted(-1, -1, 2, 2));
750 p.setPen(Qt::NoPen);
751 }
752 }
753
754 // se sono in modalita' level edit faccio vedere la freccia che indica il
755 // frame corrente
756 if (TApp::instance()->getCurrentFrame()->isEditingLevel())
757 m_frameHeadGadget->draw(p, QColor(Qt::white), QColor(Qt::black));
758 }
759
760 //-----------------------------------------------------------------------------
761
drawFrameIcon(QPainter & p,const QRect & r,int index,const TFrameId & fid,int flags)762 void FilmstripFrames::drawFrameIcon(QPainter &p, const QRect &r, int index,
763 const TFrameId &fid, int flags) {
764 QPixmap pm;
765 TXshSimpleLevel *sl = getLevel();
766 if (sl) {
767 pm = IconGenerator::instance()->getIcon(sl, fid);
768 }
769 if (!pm.isNull()) {
770 p.drawPixmap(r.left(), r.top(), pm);
771
772 if (sl && sl->getType() == PLI_XSHLEVEL && flags & F_INBETWEEN_RANGE) {
773 if (m_isVertical) {
774 int x1 = r.right();
775 int x0 = x1 - 12;
776 int y0 = r.top();
777 int y1 = r.bottom();
778 p.fillRect(x0, y0, x1 - x0 + 1, y1 - y0 + 1,
779 QColor(180, 180, 180, 255));
780 p.setPen(Qt::black);
781 p.drawLine(x0 - 1, y0, x0 - 1, y1);
782
783 QRectF txtRect(y0 + 1, -x1, y1 - y0 - 1, x1 - x0 + 1);
784 QFontMetricsF tmpFm(p.font());
785 QRectF bbox = tmpFm.boundingRect(
786 txtRect, Qt::AlignBottom | Qt::AlignHCenter, tr("INBETWEEN"));
787 double ratio = std::min(1.0, txtRect.width() / bbox.width());
788
789 p.save();
790 p.setRenderHint(QPainter::TextAntialiasing);
791 p.rotate(90.0);
792 p.scale(ratio, 1.0);
793 p.drawText(QRectF(txtRect.left() / ratio, txtRect.top(),
794 txtRect.width() / ratio, txtRect.height()),
795 tr("INBETWEEN"),
796 QTextOption(Qt::AlignBottom | Qt::AlignHCenter));
797 p.restore();
798 } else {
799 int x1 = r.right();
800 int x0 = r.left();
801 int y0 = r.bottom() - 15;
802 int y1 = r.bottom();
803 p.fillRect(x0, y0, x1 - x0 + 1, y1 - y0 + 1,
804 QColor(180, 180, 180, 255));
805 p.setPen(Qt::black);
806 p.drawLine(x0, y0, x1, y0);
807 p.drawText(r, tr("INBETWEEN"),
808 QTextOption(Qt::AlignBottom | Qt::AlignHCenter));
809 }
810 }
811 } else {
812 // non riesco (per qualche ragione) a visualizzare l'icona
813 p.fillRect(r, QColor(255, 200, 200));
814 p.setPen(Qt::black);
815 p.drawText(r, tr("no icon"), QTextOption(Qt::AlignCenter));
816 }
817 }
818
enterEvent(QEvent * event)819 void FilmstripFrames::enterEvent(QEvent *event) { getViewer(); }
820
821 //-----------------------------------------------------------------------------
822
getCurrentFrameId()823 TFrameId FilmstripFrames::getCurrentFrameId() {
824 TApp *app = TApp::instance();
825 TFrameHandle *fh = app->getCurrentFrame();
826 TFrameId currFid;
827 if (fh->isEditingLevel())
828 currFid = fh->getFid();
829 else {
830 TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
831 int col = app->getCurrentColumn()->getColumnIndex();
832 int row = fh->getFrame();
833 if (row < 0 || col < 0) return TFrameId();
834 TXshCell cell = xsh->getCell(row, col);
835 // if (cell.isEmpty()) return;
836 currFid = cell.getFrameId();
837 }
838 return currFid;
839 }
840
841 //-----------------------------------------------------------------------------
842
mousePressEvent(QMouseEvent * event)843 void FilmstripFrames::mousePressEvent(QMouseEvent *event) {
844 m_selecting = false;
845 int index = 0;
846 if (m_isVertical) {
847 index = y2index(event->pos().y());
848 } else {
849 index = x2index(event->pos().x());
850 }
851 TFrameId fid = index2fid(index);
852
853 TXshSimpleLevel *sl = getLevel();
854 int frameHeight = m_iconSize.height() + fs_frameSpacing + fs_iconMarginTop +
855 fs_iconMarginBottom;
856 int frameWidth = m_iconSize.width() + fs_frameSpacing + fs_iconMarginLR +
857 fs_leftMargin + fs_rightMargin;
858
859 int i0;
860 QPoint clickedPos;
861 bool actualIconClicked;
862
863 if (m_isVertical) {
864 i0 = y2index(0);
865 clickedPos = event->pos() - QPoint(0, (index - i0) * frameHeight);
866 } else {
867 i0 = x2index(0);
868 clickedPos = event->pos() - QPoint((index - i0) * frameWidth, 0);
869 }
870 actualIconClicked =
871 QRect(QPoint(fs_leftMargin + fs_iconMarginLR,
872 fs_frameSpacing / 2 +
873 fs_iconMarginTop) //<- top-left position of the icon
874 ,
875 m_iconSize)
876 .contains(clickedPos);
877
878 if (event->button() == Qt::LeftButton ||
879 event->button() == Qt::MiddleButton) {
880 // navigator pan
881 // make sure the viewer is visible and that a toonz raster or raster level
882 // is current
883 if (fid.getNumber() >= 0 && fid == getCurrentFrameId() &&
884 (sl->getType() == TZP_XSHLEVEL || sl->getType() == OVL_XSHLEVEL) &&
885 m_viewer && m_viewer->isVisible() && actualIconClicked &&
886 event->button() == Qt::MiddleButton) {
887 if (m_showNavigator) {
888 m_isNavigatorPanning = true;
889 execNavigatorPan(event->pos());
890 QApplication::setOverrideCursor(Qt::ClosedHandCursor);
891 }
892 } else
893 m_isNavigatorPanning = false;
894 // end of navigator section
895
896 // return if frame empty or middle button pressed
897 if (fid == TFrameId() || event->button() == Qt::MiddleButton) {
898 m_justStartedSelection = false;
899 return;
900 }
901
902 // was the inbetween button clicked?
903 bool inbetweenSelected = false;
904 if (m_isVertical)
905 inbetweenSelected = event->pos().x() > width() - 20 - fs_rightMargin;
906 else
907 inbetweenSelected =
908 event->pos().y() > height() - fs_iconMarginBottom - 20 &&
909 event->pos().y() < height() - fs_iconMarginBottom - fs_frameSpacing;
910
911 // with shift or control
912 if (event->modifiers() & Qt::ShiftModifier) {
913 select(index, SHIFT_SELECT);
914 if (m_selection->isSelected(fid)) {
915 // If the frame is already selected enable
916 // drag'n'drop
917 m_dragDropArmed = true;
918 m_pos = event->pos();
919 }
920 } else if (event->modifiers() & Qt::ControlModifier)
921 select(index, CTRL_SELECT);
922
923 else if (sl->getType() == PLI_XSHLEVEL &&
924 m_selection->isInInbetweenRange(fid) && inbetweenSelected) {
925 inbetween();
926 } else {
927 // move current frame when clicked without modifier
928 TApp *tapp = TApp::instance();
929 std::vector<TFrameId> fids;
930 TXshLevel *level = tapp->getCurrentLevel()->getLevel();
931 level->getFids(fids);
932
933 tapp->getCurrentFrame()->setFrameIds(fids);
934 tapp->getCurrentFrame()->setFid(fid);
935
936 if (actualIconClicked &&
937 (!m_selection->isSelected(fid) || m_justStartedSelection)) {
938 // click on a non-selected frame
939 m_selecting = true; // allow drag-select
940 select(index, START_DRAG_SELECT);
941 } else if (m_selection->isSelected(fid)) {
942 // if it's already selected - it can be drag and dropped
943 m_dragDropArmed = true;
944 m_pos = event->pos();
945 // allow a the frame to be reselected if the mouse isn't moved far
946 // this is to enable a group selection to become a single selection
947 m_allowResetSelection = true;
948 m_indexForResetSelection = index;
949 } else if (!actualIconClicked) {
950 // this allows clicking the frame number to trigger an instant drag
951 select(index, ONLY_SELECT);
952 m_dragDropArmed = true;
953 m_pos = event->pos();
954 }
955 }
956 update();
957 } else if (event->button() == Qt::RightButton) {
958 select(index);
959 }
960 m_justStartedSelection = false;
961 }
962
963 //-----------------------------------------------------------------------------
964
execNavigatorPan(const QPoint & point)965 void FilmstripFrames::execNavigatorPan(const QPoint &point) {
966 int index = y2index(point.y());
967 if (!m_isVertical) index = x2index(point.x());
968 TFrameId fid = index2fid(index);
969 int i0 = y2index(0);
970 if (!m_isVertical) i0 = x2index(0);
971
972 int frameHeight = m_iconSize.height() + fs_frameSpacing + fs_iconMarginTop +
973 fs_iconMarginBottom;
974 int frameWidth = m_iconSize.width() + fs_frameSpacing + fs_iconMarginLR +
975 fs_leftMargin + fs_rightMargin;
976 QPoint clickedPos = point - QPoint(0, (index - i0) * frameHeight);
977 if (!m_isVertical) clickedPos = point - QPoint((index - i0) * frameWidth, 0);
978
979 if (fid != getCurrentFrameId()) return;
980
981 QRect iconRect =
982 QRect(QPoint(fs_leftMargin + fs_iconMarginLR,
983 fs_frameSpacing / 2 +
984 fs_iconMarginTop) //<- top-left position of the icon
985 ,
986 m_iconSize);
987
988 QPointF delta = m_naviRectPos - clickedPos;
989
990 if (iconRect.left() > clickedPos.x() || iconRect.right() < clickedPos.x())
991 delta.setX(0.0);
992 if (iconRect.top() > clickedPos.y() || iconRect.bottom() < clickedPos.y())
993 delta.setY(0.0);
994 if (delta.x() == 0.0 && delta.y() == 0.0) return;
995
996 delta.setX(delta.x() * m_icon2ViewerRatio.x());
997 delta.setY(delta.y() * m_icon2ViewerRatio.y());
998
999 if (m_viewer) m_viewer->navigatorPan(delta.toPoint());
1000 }
1001
1002 //-----------------------------------------------------------------------------
1003
mouseReleaseEvent(QMouseEvent * e)1004 void FilmstripFrames::mouseReleaseEvent(QMouseEvent *e) {
1005 stopAutoPanning();
1006 m_selecting = false;
1007 m_dragDropArmed = false;
1008 m_isNavigatorPanning = false;
1009 if (m_allowResetSelection) {
1010 select(m_indexForResetSelection, ONLY_SELECT);
1011 update();
1012 }
1013 m_allowResetSelection = false;
1014 m_indexForResetSelection = -1;
1015 QApplication::restoreOverrideCursor();
1016 }
1017
1018 //-----------------------------------------------------------------------------
1019
mouseMoveEvent(QMouseEvent * e)1020 void FilmstripFrames::mouseMoveEvent(QMouseEvent *e) {
1021 QPoint pos = e->pos();
1022 int index = y2index(e->pos().y());
1023 if (!m_isVertical) index = x2index(e->pos().x());
1024 if (e->buttons() & Qt::LeftButton || e->buttons() & Qt::MiddleButton) {
1025 // navigator pan
1026 if (m_showNavigator && m_isNavigatorPanning) {
1027 execNavigatorPan(e->pos());
1028 e->accept();
1029 return;
1030 }
1031 if (e->buttons() & Qt::MiddleButton) return;
1032 if (m_dragDropArmed) {
1033 if ((m_pos - e->pos()).manhattanLength() > 10) {
1034 startDragDrop();
1035 m_dragDropArmed = false;
1036 m_allowResetSelection = false;
1037 }
1038 } else if (m_selecting) {
1039 m_pos = e->globalPos();
1040 select(index, DRAG_SELECT);
1041 }
1042
1043 // autopan
1044 int speed = getOneFrameHeight() / 64;
1045 if (!m_isVertical) speed = getOneFrameWidth() / 64;
1046
1047 QRect visibleRect = visibleRegion().boundingRect();
1048 int visibleTop = visibleRect.top();
1049 int visibleBottom = visibleRect.bottom();
1050 if (m_isVertical) {
1051 if (pos.y() < visibleRect.top()) {
1052 m_scrollSpeed = -speed;
1053 if (visibleRect.top() - pos.y() > 30) {
1054 m_timerInterval = 50;
1055 } else if (visibleRect.top() - pos.y() > 15) {
1056 m_timerInterval = 150;
1057 } else {
1058 m_timerInterval = 300;
1059 }
1060 } else if (pos.y() > visibleRect.bottom()) {
1061 m_scrollSpeed = speed;
1062 if (pos.y() - visibleRect.bottom() > 30) {
1063 m_timerInterval = 50;
1064 } else if (pos.y() - visibleRect.bottom() > 15) {
1065 m_timerInterval = 150;
1066 } else {
1067 m_timerInterval = 300;
1068 }
1069 } else
1070 m_scrollSpeed = 0;
1071 } else {
1072 if (pos.x() < visibleRect.left()) {
1073 m_scrollSpeed = -speed;
1074 if (visibleRect.left() - pos.x() > 30) {
1075 m_timerInterval = 50;
1076 } else if (visibleRect.left() - pos.x() > 15) {
1077 m_timerInterval = 150;
1078 } else {
1079 m_timerInterval = 300;
1080 }
1081 } else if (pos.x() > visibleRect.right()) {
1082 m_scrollSpeed = speed;
1083 if (pos.x() - visibleRect.right() > 30) {
1084 m_timerInterval = 50;
1085 } else if (pos.x() - visibleRect.right() > 15) {
1086 m_timerInterval = 150;
1087 } else {
1088 m_timerInterval = 300;
1089 }
1090 } else
1091 m_scrollSpeed = 0;
1092 }
1093 if (m_scrollSpeed != 0) {
1094 startAutoPanning();
1095 } else
1096 stopAutoPanning();
1097 update();
1098 } else if (e->buttons() & Qt::MidButton) {
1099 // scroll con il tasto centrale
1100 pos = e->globalPos();
1101 if (m_isVertical) {
1102 scroll((m_pos.y() - pos.y()) * 10);
1103 } else {
1104 scroll((m_pos.x() - pos.x()) * 10);
1105 }
1106 m_pos = pos;
1107 } else {
1108 TFrameId fid = index2fid(index);
1109 TXshSimpleLevel *sl = getLevel();
1110
1111 if (m_isVertical && sl && m_selection && sl->getType() == PLI_XSHLEVEL &&
1112 m_selection->isInInbetweenRange(fid) &&
1113 e->pos().x() > width() - 20 - fs_rightMargin) {
1114 setToolTip(tr("Auto Inbetween"));
1115 }
1116 if (!m_isVertical && sl && m_selection && sl->getType() == PLI_XSHLEVEL &&
1117 m_selection->isInInbetweenRange(fid) &&
1118 e->pos().y() > height() - 15 - fs_iconMarginBottom &&
1119 e->pos().y() < height() - fs_iconMarginBottom - fs_frameSpacing) {
1120 setToolTip(tr("Auto Inbetween"));
1121 }
1122 }
1123 }
1124
1125 //-----------------------------------------------------------------------------
1126
keyPressEvent(QKeyEvent * event)1127 void FilmstripFrames::keyPressEvent(QKeyEvent *event) {
1128 TFrameHandle *fh = TApp::instance()->getCurrentFrame();
1129 TXshSimpleLevel *level = getLevel();
1130 if (!level) return;
1131 std::vector<TFrameId> fids;
1132 level->getFids(fids);
1133 if (fids.empty()) return;
1134
1135 // If on a level frame pass the frame id after the last frame to allow
1136 // creating a new frame with the down arrow key
1137 TFrameId newId = 0;
1138 if (Preferences::instance()->getDownArrowLevelStripNewFrame() &&
1139 fh->getFrameType() == TFrameHandle::LevelFrame) {
1140 int frameCount = (int)fids.size();
1141 newId = index2fid(frameCount);
1142 }
1143
1144 fh->setFrameIds(fids);
1145 if (event->key() == Qt::Key_Up || event->key() == Qt::Key_Left)
1146 fh->prevFrame();
1147 else if (event->key() == Qt::Key_Down || event->key() == Qt::Key_Right)
1148 fh->nextFrame(newId);
1149 else if (event->key() == Qt::Key_Home)
1150 fh->firstFrame();
1151 else if (event->key() == Qt::Key_End)
1152 fh->lastFrame();
1153 else if (event->key() == Qt::Key_PageDown) {
1154 if (m_isVertical) {
1155 int frameHeight = m_iconSize.height();
1156 int visibleHeight = visibleRegion().rects()[0].height();
1157 int visibleFrames = double(visibleHeight) / double(frameHeight);
1158 scroll(visibleFrames * frameHeight);
1159 } else {
1160 int frameWidth = m_iconSize.width();
1161 int visibleWidth = visibleRegion().rects()[0].width();
1162 int visibleFrames = double(visibleWidth) / double(frameWidth);
1163 scroll(visibleFrames * frameWidth);
1164 }
1165 return;
1166 } else if (event->key() == Qt::Key_PageUp) {
1167 if (m_isVertical) {
1168 int frameHeight = m_iconSize.height();
1169 int visibleHeight = visibleRegion().rects()[0].height();
1170 int visibleFrames = double(visibleHeight) / double(frameHeight);
1171 scroll(-visibleFrames * frameHeight);
1172 } else {
1173 int frameWidth = m_iconSize.width();
1174 int visibleWidth = visibleRegion().rects()[0].width();
1175 int visibleFrames = double(visibleWidth) / double(frameWidth);
1176 scroll(-visibleFrames * frameWidth);
1177 }
1178 return;
1179 } else
1180 return;
1181
1182 m_selection->selectNone();
1183 if (getLevel()) m_selection->select(fh->getFid());
1184 int index = fid2index(fh->getFid());
1185 if (index >= 0) showFrame(index);
1186 }
1187
1188 //-----------------------------------------------------------------------------
1189
wheelEvent(QWheelEvent * event)1190 void FilmstripFrames::wheelEvent(QWheelEvent *event) {
1191 scroll(-event->delta());
1192 }
1193
1194 //-----------------------------------------------------------------------------
1195
startAutoPanning()1196 void FilmstripFrames::startAutoPanning() {
1197 if (m_timerId == 0) m_timerId = startTimer(m_timerInterval);
1198 }
1199
1200 //-----------------------------------------------------------------------------
1201
stopAutoPanning()1202 void FilmstripFrames::stopAutoPanning() {
1203 if (m_timerId != 0) {
1204 killTimer(m_timerId);
1205 m_timerId = 0;
1206 m_scrollSpeed = 0;
1207 }
1208 }
1209
1210 //-----------------------------------------------------------------------------
1211
timerEvent(QTimerEvent *)1212 void FilmstripFrames::timerEvent(QTimerEvent *) {
1213 scroll(m_scrollSpeed);
1214 // reset the timer in case m_scroll speed has changed
1215 killTimer(m_timerId);
1216 m_timerId = 0;
1217 m_timerId = startTimer(m_timerInterval);
1218 if (m_selecting) {
1219 QPoint pos = mapFromGlobal(m_pos);
1220 int index = y2index(pos.y());
1221 if (!m_isVertical) index = x2index(pos.x());
1222 select(index, DRAG_SELECT);
1223 showFrame(index);
1224 update();
1225 }
1226 }
1227
1228 //-----------------------------------------------------------------------------
1229
contextMenuEvent(QContextMenuEvent * event)1230 void FilmstripFrames::contextMenuEvent(QContextMenuEvent *event) {
1231 QMenu *menu = new QMenu();
1232 TXshSimpleLevel *sl = getLevel();
1233 bool isSubsequenceLevel = (sl && sl->isSubsequence());
1234 bool isReadOnly = (sl && sl->isReadOnly());
1235 CommandManager *cm = CommandManager::instance();
1236
1237 menu->addAction(cm->getAction(MI_SelectAll));
1238 menu->addAction(cm->getAction(MI_InvertSelection));
1239 menu->addSeparator();
1240 if (!isSubsequenceLevel && !isReadOnly) {
1241 menu->addAction(cm->getAction(MI_Cut));
1242 }
1243 menu->addAction(cm->getAction(MI_Copy));
1244
1245 if (!isSubsequenceLevel && !isReadOnly) {
1246 menu->addAction(cm->getAction(MI_Paste));
1247 menu->addAction(cm->getAction(MI_PasteInto));
1248 menu->addAction(cm->getAction(MI_Insert));
1249 menu->addAction(cm->getAction(MI_Clear));
1250 menu->addSeparator();
1251 menu->addAction(cm->getAction(MI_Reverse));
1252 menu->addAction(cm->getAction(MI_Swing));
1253 menu->addAction(cm->getAction(MI_Step2));
1254 menu->addAction(cm->getAction(MI_Step3));
1255 menu->addAction(cm->getAction(MI_Step4));
1256 menu->addAction(cm->getAction(MI_Each2));
1257 menu->addAction(cm->getAction(MI_Each3));
1258 menu->addAction(cm->getAction(MI_Each4));
1259 menu->addSeparator();
1260 menu->addAction(cm->getAction(MI_Duplicate));
1261 menu->addAction(cm->getAction(MI_MergeFrames));
1262 }
1263 menu->addAction(cm->getAction(MI_ExposeResource));
1264 if (!isSubsequenceLevel && !isReadOnly) {
1265 menu->addAction(cm->getAction(MI_AddFrames));
1266 menu->addAction(cm->getAction(MI_Renumber));
1267 if (sl && sl->getType() == TZP_XSHLEVEL)
1268 menu->addAction(cm->getAction(MI_RevertToCleanedUp));
1269 }
1270 if (sl &&
1271 (sl->getType() == TZP_XSHLEVEL || sl->getType() == PLI_XSHLEVEL ||
1272 (sl->getType() == OVL_XSHLEVEL && sl->getPath().getType() != "gif" &&
1273 sl->getPath().getType() != "mp4" && sl->getPath().getType() != "webm")))
1274 menu->addAction(cm->getAction(MI_RevertToLastSaved));
1275 menu->addSeparator();
1276 createSelectLevelMenu(menu);
1277 QMenu *panelMenu = menu->addMenu(tr("Panel Settings"));
1278 QAction *toggleOrientation = panelMenu->addAction(tr("Toggle Orientation"));
1279 QAction *hideComboBox = panelMenu->addAction(tr("Show/Hide Drop Down Menu"));
1280 QAction *hideNavigator =
1281 panelMenu->addAction(tr("Show/Hide Level Navigator"));
1282 hideComboBox->setCheckable(true);
1283 hideComboBox->setChecked(m_showComboBox);
1284 hideNavigator->setCheckable(true);
1285 hideNavigator->setChecked(m_showNavigator);
1286 connect(toggleOrientation, SIGNAL(triggered(bool)), this,
1287 SLOT(orientationToggled(bool)));
1288 connect(hideComboBox, SIGNAL(triggered(bool)), this,
1289 SLOT(comboBoxToggled(bool)));
1290 connect(hideNavigator, SIGNAL(triggered(bool)), this,
1291 SLOT(navigatorToggled(bool)));
1292
1293 menu->exec(event->globalPos());
1294 }
1295
1296 //-----------------------------------------------------------------------------
1297
createSelectLevelMenu(QMenu * menu)1298 void FilmstripFrames::createSelectLevelMenu(QMenu *menu) {
1299 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
1300 if (scene) {
1301 std::vector<TXshLevel *> levels;
1302 scene->getLevelSet()->listLevels(levels);
1303 std::vector<TXshLevel *>::iterator it;
1304 int i = 0;
1305 bool active = false;
1306 QMenu *levelSelectMenu;
1307 for (it = levels.begin(); it != levels.end(); ++it) {
1308 TXshSimpleLevel *sl = (*it)->getSimpleLevel();
1309 if (sl) {
1310 // register only used level in xsheet
1311 if (!scene->getTopXsheet()->isLevelUsed(sl)) continue;
1312 QString levelName = QString::fromStdWString(sl->getName());
1313 if (i == 0) {
1314 levelSelectMenu = menu->addMenu(tr("Select Level"));
1315 active = true;
1316 }
1317 if (active) {
1318 QAction *action = levelSelectMenu->addAction(levelName);
1319 connect(action, &QAction::triggered, [=] { levelSelected(i); });
1320 }
1321 i++;
1322 }
1323 }
1324 }
1325 }
1326
1327 //-----------------------------------------------------------------------------
1328
levelSelected(int index)1329 void FilmstripFrames::levelSelected(int index) {
1330 emit(levelSelectedSignal(index));
1331 }
1332
1333 //-----------------------------------------------------------------------------
1334
comboBoxToggled(bool ignore)1335 void FilmstripFrames::comboBoxToggled(bool ignore) {
1336 emit(comboBoxToggledSignal());
1337 }
1338
1339 //-----------------------------------------------------------------------------
1340
navigatorToggled(bool ignore)1341 void FilmstripFrames::navigatorToggled(bool ignore) {
1342 emit(navigatorToggledSignal());
1343 }
1344
1345 //-----------------------------------------------------------------------------
1346
orientationToggled(bool ignore)1347 void FilmstripFrames::orientationToggled(bool ignore) {
1348 m_isVertical = !m_isVertical;
1349 emit(orientationToggledSignal(m_isVertical));
1350 }
1351
1352 //-----------------------------------------------------------------------------
1353
setOrientation(bool isVertical)1354 void FilmstripFrames::setOrientation(bool isVertical) {
1355 m_isVertical = isVertical;
1356 if (m_isVertical) {
1357 setFixedWidth(m_iconSize.width() + fs_leftMargin + fs_rightMargin +
1358 fs_iconMarginLR * 2);
1359 setFixedHeight(parentWidget()->height());
1360 } else {
1361 setFixedHeight(parentWidget()->height());
1362 setFixedWidth(parentWidget()->width());
1363 }
1364 if (m_isVertical)
1365 updateContentHeight();
1366 else
1367 updateContentWidth();
1368 TApp *app = TApp::instance();
1369 TFrameHandle *fh = app->getCurrentFrame();
1370 TFrameId fid = getCurrentFrameId();
1371
1372 int index = fid2index(fid);
1373 if (index >= 0) {
1374 showFrame(index);
1375 }
1376 update();
1377 }
1378
1379 //-----------------------------------------------------------------------------
1380
setNavigator(bool showNavigator)1381 void FilmstripFrames::setNavigator(bool showNavigator) {
1382 m_showNavigator = showNavigator;
1383 }
1384
1385 //-----------------------------------------------------------------------------
1386
setComboBox(bool showComboBox)1387 void FilmstripFrames::setComboBox(bool showComboBox) {
1388 m_showComboBox = showComboBox;
1389 }
1390
1391 //-----------------------------------------------------------------------------
1392
onLevelChanged()1393 void FilmstripFrames::onLevelChanged() {
1394 if (m_isVertical)
1395 updateContentHeight();
1396 else
1397 updateContentWidth();
1398 update();
1399 }
1400
1401 //-----------------------------------------------------------------------------
1402
onLevelSwitched(TXshLevel *)1403 void FilmstripFrames::onLevelSwitched(TXshLevel *) {
1404 if (m_isVertical)
1405 updateContentHeight(0);
1406 else
1407 updateContentWidth(0);
1408 onFrameSwitched(); // deve visualizzare il frame corrente nella levelstrip
1409 }
1410
1411 //-----------------------------------------------------------------------------
1412
onFrameSwitched()1413 void FilmstripFrames::onFrameSwitched() {
1414 // no. interferische con lo shift-click per la selezione.
1415 // m_selection->selectNone();
1416 TApp *app = TApp::instance();
1417 TFrameHandle *fh = app->getCurrentFrame();
1418 TFrameId fid = getCurrentFrameId();
1419
1420 int index = fid2index(fid);
1421 if (index >= 0) {
1422 showFrame(index);
1423
1424 TFilmstripSelection *fsSelection =
1425 dynamic_cast<TFilmstripSelection *>(TSelection::getCurrent());
1426
1427 // don't select if already selected - may be part of a group selection
1428 if (!m_selection->isSelected(index2fid(index)) && fsSelection) {
1429 select(index, ONLY_SELECT);
1430 m_justStartedSelection = true;
1431 }
1432 }
1433 update();
1434 }
1435
1436 //-----------------------------------------------------------------------------
1437
startDragDrop()1438 void FilmstripFrames::startDragDrop() {
1439 TRepetitionGuard guard;
1440 if (!guard.hasLock()) return;
1441
1442 TXshSimpleLevel *sl = getLevel();
1443 if (!sl) return;
1444 const std::set<TFrameId> &fids = m_selection->getSelectedFids();
1445 if (fids.empty()) return;
1446 QByteArray byteArray;
1447
1448 QMimeData *mimeData = new QMimeData;
1449 mimeData->setData("application/vnd.toonz.drawings", byteArray);
1450 QDrag *drag = new QDrag(this);
1451 QPixmap dropThumbnail = IconGenerator::instance()->getIcon(sl, *fids.begin());
1452 if (!dropThumbnail.isNull()) drag->setPixmap(dropThumbnail);
1453 drag->setMimeData(mimeData);
1454 Qt::DropAction dropAction = drag->exec(Qt::CopyAction | Qt::MoveAction);
1455 }
1456
1457 //-----------------------------------------------------------------------------
1458
inbetween()1459 void FilmstripFrames::inbetween() {
1460 TFilmstripSelection::InbetweenRange range = m_selection->getInbetweenRange();
1461 if (range.first >= range.second || !getLevel()) return;
1462
1463 QSettings settings;
1464 QString keyName("InbetweenInterpolation");
1465 QString currentItem = settings.value(keyName, tr("Linear")).toString();
1466 int index;
1467
1468 {
1469 if (!m_inbetweenDialog) m_inbetweenDialog = new InbetweenDialog(this);
1470
1471 // Default -> l'ultimo valore usato
1472
1473 m_inbetweenDialog->setValue(currentItem);
1474
1475 int ret = m_inbetweenDialog->exec();
1476 if (!ret) return;
1477
1478 currentItem = m_inbetweenDialog->getValue();
1479 if (currentItem.isEmpty()) return;
1480 index = m_inbetweenDialog->getIndex(currentItem);
1481 if (index < 0) return;
1482
1483 // registro il nuovo valore
1484 }
1485 settings.setValue(keyName, currentItem);
1486
1487 // lo converto nella notazione di FilmstripCmd
1488 const FilmstripCmd::InbetweenInterpolation codes[] = {
1489 FilmstripCmd::II_Linear, FilmstripCmd::II_EaseIn,
1490 FilmstripCmd::II_EaseOut, FilmstripCmd::II_EaseInOut};
1491
1492 FilmstripCmd::InbetweenInterpolation interpolation = codes[index];
1493
1494 // inbetween
1495 FilmstripCmd::inbetween(getLevel(), range.first, range.second, interpolation);
1496 }
1497
1498 //-----------------------------------------------------------------------------
1499
onViewerAboutToBeDestroyed()1500 void FilmstripFrames::onViewerAboutToBeDestroyed() {
1501 if (m_viewer) {
1502 disconnect(m_viewer, SIGNAL(onZoomChanged()), this, SLOT(update()));
1503 disconnect(m_viewer, SIGNAL(refreshNavi()), this, SLOT(update()));
1504 m_viewer = nullptr;
1505 }
1506 }
1507
1508 //=============================================================================
1509 // Filmstrip
1510 //-----------------------------------------------------------------------------
1511
1512 #if QT_VERSION >= 0x050500
Filmstrip(QWidget * parent,Qt::WindowFlags flags)1513 Filmstrip::Filmstrip(QWidget *parent, Qt::WindowFlags flags)
1514 #else
1515 Filmstrip::Filmstrip(QWidget *parent, Qt::WFlags flags)
1516 #endif
1517 : QWidget(parent) {
1518 setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
1519
1520 m_frameArea = new QScrollArea(this);
1521 m_chooseLevelCombo = new QComboBox(this);
1522 m_frames = new FilmstripFrames(m_frameArea);
1523
1524 //----
1525 m_frames->m_isVertical = m_isVertical;
1526 m_frameArea->setObjectName("filmScrollArea");
1527 m_frameArea->setFrameStyle(QFrame::StyledPanel);
1528 setOrientation(m_isVertical);
1529
1530 m_frameArea->setWidget(m_frames);
1531
1532 m_chooseLevelCombo->setMaxVisibleItems(50);
1533 m_chooseLevelCombo->setObjectName("filmLevelCombo");
1534
1535 // layout
1536 QVBoxLayout *mainLayout = new QVBoxLayout();
1537 mainLayout->setMargin(0);
1538 mainLayout->setSpacing(0);
1539 {
1540 mainLayout->addWidget(m_chooseLevelCombo, 0);
1541 mainLayout->addWidget(m_frameArea, 1);
1542 }
1543 setLayout(mainLayout);
1544
1545 setFocusProxy(m_frames);
1546
1547 onLevelSwitched(0);
1548
1549 // signal-slot connections
1550 // switch the current level when the current index of m_chooseLevelCombo is
1551 // changed
1552 connect(m_chooseLevelCombo, SIGNAL(activated(int)), this,
1553 SLOT(onChooseLevelComboChanged(int)));
1554 connect(m_frames, SIGNAL(orientationToggledSignal(bool)), this,
1555 SLOT(orientationToggled(bool)));
1556 connect(m_frames, SIGNAL(comboBoxToggledSignal()), this,
1557 SLOT(comboBoxToggled()));
1558 connect(m_frames, SIGNAL(navigatorToggledSignal()), this,
1559 SLOT(navigatorToggled()));
1560 connect(m_frames, SIGNAL(levelSelectedSignal(int)), this,
1561 SLOT(onChooseLevelComboChanged(int)));
1562 }
1563
1564 //-----------------------------------------------------------------------------
1565 /*! switch the current level when the current index of m_chooseLevelCombo is
1566 * changed
1567 */
onChooseLevelComboChanged(int index)1568 void Filmstrip::onChooseLevelComboChanged(int index) {
1569 TApp *tapp = TApp::instance();
1570 // empty level
1571 if (index == m_chooseLevelCombo->findText(tr("- No Current Level -")))
1572 tapp->getCurrentLevel()->setLevel(0);
1573 else {
1574 std::vector<TFrameId> fids;
1575 m_levels[index]->getFids(fids);
1576 tapp->getCurrentFrame()->setFrameIds(fids);
1577
1578 // retrieve to the current working frame of the level
1579 TFrameId WF;
1580 std::map<TXshSimpleLevel *, TFrameId>::iterator WFit;
1581 WFit = m_workingFrames.find(m_levels[index]);
1582 if (WFit != m_workingFrames.end())
1583 WF = WFit->second;
1584 else
1585 WF = fids[0];
1586
1587 // this function emits xshLevelSwitched() signal and eventually calls
1588 // FlipConsole::UpdateRange
1589 // it may move the current frame so we need to keep the current frameId
1590 // before calling setLevel.
1591 tapp->getCurrentLevel()->setLevel(m_levels[index]);
1592
1593 if (tapp->getCurrentSelection()->getSelection())
1594 tapp->getCurrentSelection()->getSelection()->selectNone();
1595
1596 // move to the current working frame
1597 tapp->getCurrentFrame()->setFid(WF);
1598
1599 QApplication::setOverrideCursor(Qt::WaitCursor);
1600
1601 invalidateIcons(m_levels[index], fids);
1602
1603 QApplication::restoreOverrideCursor();
1604 }
1605 }
1606
1607 //-----------------------------------------------------------------------------
1608 /*! update combo items when the contents of scene cast are changed
1609 */
updateChooseLevelComboItems()1610 void Filmstrip::updateChooseLevelComboItems() {
1611 // clear items
1612 m_chooseLevelCombo->clear();
1613 for (auto oldLevel : m_levels) oldLevel->release();
1614 m_levels.clear();
1615
1616 std::map<TXshSimpleLevel *, TFrameId> new_workingFrames;
1617
1618 // correct and register items
1619 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
1620 if (scene) {
1621 std::vector<TXshLevel *> levels;
1622 scene->getLevelSet()->listLevels(levels);
1623 std::vector<TXshLevel *>::iterator it;
1624
1625 for (it = levels.begin(); it != levels.end(); ++it) {
1626 // register only TLV and PLI
1627 TXshSimpleLevel *sl = (*it)->getSimpleLevel();
1628 if (sl) {
1629 // register only used level in xsheet
1630 if (!scene->getTopXsheet()->isLevelUsed(sl)) continue;
1631
1632 sl->addRef();
1633 m_levels.push_back(sl);
1634
1635 // create new m_workingFrames map with the new levelset
1636 TFrameId fId;
1637 std::map<TXshSimpleLevel *, TFrameId>::iterator WFit =
1638 m_workingFrames.find(sl);
1639
1640 if (WFit != m_workingFrames.end())
1641 fId = WFit->second;
1642 else
1643 fId = sl->getFirstFid();
1644
1645 new_workingFrames.insert(std::make_pair(sl, fId));
1646
1647 QString levelName = QString::fromStdWString(sl->getName());
1648 if (sl->getProperties()->getDirtyFlag()) levelName += " *";
1649
1650 // append the current working frame number to the item name
1651 if (fId != sl->getFirstFid() && fId.getNumber() >= 0)
1652 levelName +=
1653 QString(" [#") + QString::number(fId.getNumber()) + QString("]");
1654
1655 m_chooseLevelCombo->addItem(levelName);
1656 }
1657 }
1658 }
1659
1660 if (m_chooseLevelCombo->count() == 0)
1661 m_chooseLevelCombo->addItem(tr("- No Current Level -"));
1662
1663 // swap the list
1664 m_workingFrames.clear();
1665 m_workingFrames = new_workingFrames;
1666
1667 // synchronize the current index of combo to the current level
1668 updateCurrentLevelComboItem();
1669 }
1670
1671 //-----------------------------------------------------------------------------
1672 /*! synchronize the current index of combo to the current level
1673 */
updateCurrentLevelComboItem()1674 void Filmstrip::updateCurrentLevelComboItem() {
1675 if (m_chooseLevelCombo->count() == 1 &&
1676 m_chooseLevelCombo->itemText(0) == tr("- No Current Level -")) {
1677 m_chooseLevelCombo->setCurrentIndex(0);
1678 return;
1679 }
1680
1681 TXshSimpleLevel *currentLevel =
1682 TApp::instance()->getCurrentLevel()->getSimpleLevel();
1683 if (!currentLevel) {
1684 int noLevelIndex = m_chooseLevelCombo->findText(tr("- No Current Level -"));
1685 if (noLevelIndex == -1) {
1686 noLevelIndex = m_chooseLevelCombo->count();
1687 m_chooseLevelCombo->addItem(tr("- No Current Level -"));
1688 }
1689 m_chooseLevelCombo->setCurrentIndex(noLevelIndex);
1690 return;
1691 }
1692
1693 for (int i = 0; i < m_levels.size(); i++) {
1694 if (currentLevel->getName() == m_levels[i]->getName()) {
1695 m_chooseLevelCombo->setCurrentIndex(i);
1696 int noLevelIndex =
1697 m_chooseLevelCombo->findText(tr("- No Current Level -"));
1698 if (noLevelIndex != -1) m_chooseLevelCombo->removeItem(noLevelIndex);
1699 return;
1700 }
1701 }
1702
1703 int noLevelIndex = m_chooseLevelCombo->findText(tr("- No Current Level -"));
1704 if (noLevelIndex == -1) {
1705 noLevelIndex = m_chooseLevelCombo->count();
1706 m_chooseLevelCombo->addItem(tr("- No Current Level -"));
1707 }
1708 m_chooseLevelCombo->setCurrentIndex(noLevelIndex);
1709 }
1710
1711 //-----------------------------------------------------------------------------
1712
~Filmstrip()1713 Filmstrip::~Filmstrip() {
1714 for (auto level : m_levels) level->release();
1715 m_levels.clear();
1716 }
1717
1718 //-----------------------------------------------------------------------------
1719
showEvent(QShowEvent *)1720 void Filmstrip::showEvent(QShowEvent *) {
1721 TApp *app = TApp::instance();
1722 TXshLevelHandle *levelHandle = app->getCurrentLevel();
1723 bool ret = connect(levelHandle, SIGNAL(xshLevelSwitched(TXshLevel *)),
1724 SLOT(onLevelSwitched(TXshLevel *)));
1725 ret = ret &&
1726 connect(levelHandle, SIGNAL(xshLevelChanged()), SLOT(onLevelChanged()));
1727
1728 // updateWindowTitle is called in the onLevelChanged
1729 ret = ret && connect(app->getPaletteController()->getCurrentLevelPalette(),
1730 SIGNAL(colorStyleChangedOnMouseRelease()),
1731 SLOT(onLevelChanged()));
1732 ret = ret && connect(levelHandle, SIGNAL(xshLevelTitleChanged()),
1733 SLOT(onLevelChanged()));
1734
1735 ret =
1736 ret && connect(m_frameArea->verticalScrollBar(),
1737 SIGNAL(valueChanged(int)), this, SLOT(onSliderMoved(int)));
1738
1739 TSceneHandle *sceneHandle = TApp::instance()->getCurrentScene();
1740 ret = ret && connect(sceneHandle, SIGNAL(sceneSwitched()), this,
1741 SLOT(updateChooseLevelComboItems()));
1742 ret = ret && connect(sceneHandle, SIGNAL(castChanged()), this,
1743 SLOT(updateChooseLevelComboItems()));
1744
1745 ret = ret &&
1746 connect(TApp::instance()->getCurrentXsheet(), SIGNAL(xsheetChanged()),
1747 this, SLOT(updateChooseLevelComboItems()));
1748
1749 ret = ret && connect(app->getCurrentFrame(), SIGNAL(frameSwitched()), this,
1750 SLOT(onFrameSwitched()));
1751
1752 assert(ret);
1753
1754 updateChooseLevelComboItems();
1755 onFrameSwitched();
1756 onLevelSwitched(0);
1757 }
1758
1759 //-----------------------------------------------------------------------------
1760
hideEvent(QHideEvent *)1761 void Filmstrip::hideEvent(QHideEvent *) {
1762 TApp *app = TApp::instance();
1763 TXshLevelHandle *levelHandle = app->getCurrentLevel();
1764 disconnect(levelHandle, SIGNAL(xshLevelSwitched(TXshLevel *)), this,
1765 SLOT(onLevelSwitched(TXshLevel *)));
1766 disconnect(levelHandle, SIGNAL(xshLevelChanged()), this,
1767 SLOT(onLevelChanged()));
1768 disconnect(TApp::instance()->getPaletteController()->getCurrentLevelPalette(),
1769 SIGNAL(colorStyleChangedOnMouseRelease()), this,
1770 SLOT(onLevelChanged()));
1771
1772 disconnect(levelHandle, SIGNAL(xshLevelTitleChanged()), this,
1773 SLOT(onLevelChanged()));
1774
1775 disconnect(m_frameArea->verticalScrollBar(), SIGNAL(valueChanged(int)), this,
1776 SLOT(onSliderMoved(int)));
1777
1778 TSceneHandle *sceneHandle = TApp::instance()->getCurrentScene();
1779 disconnect(sceneHandle, SIGNAL(sceneSwitched()), this,
1780 SLOT(updateChooseLevelComboItems()));
1781 disconnect(sceneHandle, SIGNAL(castChanged()), this,
1782 SLOT(updateChooseLevelComboItems()));
1783
1784 disconnect(TApp::instance()->getCurrentXsheet(), SIGNAL(xsheetChanged()),
1785 this, SLOT(updateChooseLevelComboItems()));
1786
1787 disconnect(TApp::instance()->getCurrentFrame(), SIGNAL(frameSwitched()), this,
1788 SLOT(onFrameSwitched()));
1789 }
1790
1791 //-----------------------------------------------------------------------------
1792
resizeEvent(QResizeEvent * e)1793 void Filmstrip::resizeEvent(QResizeEvent *e) {
1794 if (m_isVertical) {
1795 m_frames->updateContentHeight();
1796 m_frameArea->verticalScrollBar()->setSingleStep(
1797 m_frames->getOneFrameHeight());
1798 } else {
1799 m_frames->updateContentWidth();
1800 m_frameArea->horizontalScrollBar()->setSingleStep(
1801 m_frames->getOneFrameWidth());
1802 }
1803 }
1804
1805 //-----------------------------------------------------------------------------
1806
onLevelChanged()1807 void Filmstrip::onLevelChanged() { updateWindowTitle(); }
1808
1809 //-----------------------------------------------------------------------------
1810
updateWindowTitle()1811 void Filmstrip::updateWindowTitle() {
1812 updateCurrentLevelComboItem();
1813
1814 TXshSimpleLevel *level = m_frames->getLevel();
1815
1816 QString levelName;
1817
1818 if (!level) {
1819 parentWidget()->setWindowTitle(tr("Level Strip"));
1820 return;
1821 } else {
1822 levelName = QString::fromStdWString(level->getName());
1823 if (level->getProperties()->getDirtyFlag()) levelName += " *";
1824 }
1825
1826 // parentWidget() is TPanel
1827 parentWidget()->setWindowTitle(tr("Level: ") + levelName);
1828
1829 TFrameHandle *fh = TApp::instance()->getCurrentFrame();
1830 if (fh->isEditingLevel() && fh->getFid().getNumber() >= 0)
1831 levelName += QString(" [#") + QString::number(fh->getFid().getNumber()) +
1832 QString("]");
1833
1834 m_chooseLevelCombo->setItemText(m_chooseLevelCombo->currentIndex(),
1835 levelName);
1836 }
1837
1838 //-----------------------------------------------------------------------------
1839
onLevelSwitched(TXshLevel * oldLevel)1840 void Filmstrip::onLevelSwitched(TXshLevel *oldLevel) {
1841 updateWindowTitle();
1842
1843 int tc = ToonzCheck::instance()->getChecks();
1844 if (tc & (ToonzCheck::eInk | ToonzCheck::ePaint)) {
1845 TXshLevel *sl = TApp::instance()->getCurrentLevel()->getLevel();
1846 if (!sl) return;
1847 std::vector<TFrameId> fids;
1848 sl->getFids(fids);
1849 removeIcons(sl, fids, true);
1850 }
1851 update();
1852 }
1853
1854 //-----------------------------------------------------------------------------
1855
onSliderMoved(int val)1856 void Filmstrip::onSliderMoved(int val) {
1857 int oneFrameHeight = m_frames->getIconSize().height() + fs_frameSpacing +
1858 fs_iconMarginTop + fs_iconMarginBottom;
1859 int oneFrameWidth =
1860 m_frames->getIconSize().width() + fs_frameSpacing + fs_iconMarginLR;
1861 if (m_isVertical) {
1862 int tmpVal =
1863 (int)((float)val / (float)oneFrameHeight + 0.5f) * oneFrameHeight;
1864 m_frameArea->verticalScrollBar()->setValue(tmpVal);
1865 } else {
1866 int tmpVal =
1867 (int)((float)val / (float)oneFrameWidth + 0.5f) * oneFrameWidth;
1868 m_frameArea->horizontalScrollBar()->setValue(tmpVal);
1869 }
1870 }
1871
1872 //-----------------------------------------------------------------------------
1873
onFrameSwitched()1874 void Filmstrip::onFrameSwitched() {
1875 TFrameHandle *fh = TApp::instance()->getCurrentFrame();
1876 if (!fh->isEditingLevel()) return;
1877
1878 TXshSimpleLevel *level = m_frames->getLevel();
1879
1880 std::map<TXshSimpleLevel *, TFrameId>::iterator WFit;
1881 WFit = m_workingFrames.find(level);
1882 if (WFit == m_workingFrames.end()) return;
1883
1884 WFit->second = fh->getFid();
1885
1886 QString levelName = QString::fromStdWString(level->getName());
1887 if (level->getProperties()->getDirtyFlag()) levelName += " *";
1888 if (fh->getFid().getNumber() >= 0)
1889 levelName += QString(" [#") + QString::number(fh->getFid().getNumber()) +
1890 QString("]");
1891
1892 m_chooseLevelCombo->setItemText(m_chooseLevelCombo->currentIndex(),
1893 levelName);
1894 }
1895
1896 //-----------------------------------------------------------------------------
1897
orientationToggled(bool isVertical)1898 void Filmstrip::orientationToggled(bool isVertical) {
1899 setOrientation(isVertical);
1900 }
1901
1902 //-----------------------------------------------------------------------------
1903
comboBoxToggled()1904 void Filmstrip::comboBoxToggled() {
1905 if (m_chooseLevelCombo->isHidden())
1906 m_chooseLevelCombo->show();
1907 else
1908 m_chooseLevelCombo->hide();
1909 m_showComboBox = !m_chooseLevelCombo->isHidden();
1910 m_frames->setComboBox(m_showComboBox);
1911 }
1912
1913 //-----------------------------------------------------------------------------
1914
navigatorToggled()1915 void Filmstrip::navigatorToggled() {
1916 m_showNavigator = !m_showNavigator;
1917 m_frames->setNavigator(m_showNavigator);
1918 }
1919
1920 //-----------------------------------------------------------------------------
1921
setOrientation(bool isVertical)1922 void Filmstrip::setOrientation(bool isVertical) {
1923 m_isVertical = isVertical;
1924 if (isVertical) {
1925 m_frameArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1926 m_frameArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
1927 m_frameArea->verticalScrollBar()->setObjectName("LevelStripScrollBar");
1928 } else {
1929 m_frameArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
1930 m_frameArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1931 m_frameArea->horizontalScrollBar()->setObjectName("LevelStripScrollBar");
1932 }
1933 m_frames->setOrientation(m_isVertical);
1934 dynamic_cast<TPanel *>(parentWidget())->setCanFixWidth(m_isVertical);
1935 }
1936
1937 // SaveLoadQSettings
save(QSettings & settings) const1938 void Filmstrip::save(QSettings &settings) const {
1939 UINT orientation = 0;
1940 orientation = m_isVertical ? 1 : 0;
1941 settings.setValue("vertical", orientation);
1942
1943 UINT showCombo = 0;
1944 showCombo = m_chooseLevelCombo->isHidden() ? 0 : 1;
1945 settings.setValue("showCombo", showCombo);
1946
1947 UINT navigator = 0;
1948 navigator = m_showNavigator ? 1 : 0;
1949 settings.setValue("navigator", navigator);
1950 }
1951
load(QSettings & settings)1952 void Filmstrip::load(QSettings &settings) {
1953 UINT orientation = settings.value("vertical", 1).toUInt();
1954 m_isVertical = orientation == 1;
1955 setOrientation(m_isVertical);
1956
1957 UINT navigator = settings.value("navigator", 1).toUInt();
1958 m_showNavigator = navigator == 1;
1959 m_frames->setNavigator(m_showNavigator);
1960
1961 UINT showCombo = settings.value("showCombo", 1).toUInt();
1962 m_showComboBox = showCombo == 1;
1963 if (showCombo == 1) {
1964 m_chooseLevelCombo->show();
1965 } else {
1966 m_chooseLevelCombo->hide();
1967 }
1968 m_frames->setComboBox(m_showComboBox);
1969 }
1970
1971 //=============================================================================
1972 // inbetweenDialog
1973 //-----------------------------------------------------------------------------
1974
InbetweenDialog(QWidget * parent)1975 InbetweenDialog::InbetweenDialog(QWidget *parent)
1976 : Dialog(TApp::instance()->getMainWindow(), true, "InBeetween") {
1977 setWindowTitle(tr("Inbetween"));
1978
1979 QString linear(tr("Linear"));
1980 QString easeIn(tr("Ease In"));
1981 QString easeOut(tr("Ease Out"));
1982 QString easeInOut(tr("Ease In / Ease Out"));
1983 QStringList items;
1984 items << linear << easeIn << easeOut << easeInOut;
1985
1986 beginHLayout();
1987 m_comboBox = new QComboBox(this);
1988 m_comboBox->addItems(items);
1989 addWidget(tr("Interpolation:"), m_comboBox);
1990 endHLayout();
1991
1992 QPushButton *okBtn = new QPushButton(tr("Inbetween"), this);
1993 QPushButton *cancelBtn = new QPushButton(tr("Cancel"), this);
1994 connect(okBtn, SIGNAL(clicked()), this, SLOT(accept()));
1995 connect(cancelBtn, SIGNAL(clicked()), this, SLOT(reject()));
1996
1997 addButtonBarWidget(okBtn, cancelBtn);
1998 }
1999
2000 //-----------------------------------------------------------------------------
2001
getValue()2002 QString InbetweenDialog::getValue() { return m_comboBox->currentText(); }
2003
2004 //-----------------------------------------------------------------------------
2005
setValue(const QString & value)2006 void InbetweenDialog::setValue(const QString &value) {
2007 int currentIndex = m_comboBox->findText(value);
2008 if (currentIndex < 0) currentIndex = 0;
2009 m_comboBox->setCurrentIndex(currentIndex);
2010 }
2011
2012 //-----------------------------------------------------------------------------
2013
getIndex(const QString & text)2014 int InbetweenDialog::getIndex(const QString &text) {
2015 return m_comboBox->findText(text);
2016 }
2017
2018 //=============================================================================
2019
2020 OpenFloatingPanel openFilmstripCommand(MI_OpenFilmStrip, "FilmStrip",
2021 QObject::tr("Level: "));
2022