1 
2 
3 #include "xsheetviewer.h"
4 #include "sceneviewerevents.h"
5 #include "tapp.h"
6 #include "floatingpanelcommand.h"
7 #include "menubarcommandids.h"
8 #include "toonz/tcolumnhandle.h"
9 #include "toonz/txsheethandle.h"
10 #include "toonz/tfxhandle.h"
11 #include "toonz/tscenehandle.h"
12 #include "toonz/tframehandle.h"
13 #include "toonz/tobjecthandle.h"
14 #include "toonz/txshpalettelevel.h"
15 #include "toonz/preferences.h"
16 #include "toonz/sceneproperties.h"
17 #include "toonzqt/tselectionhandle.h"
18 #include "toonzqt/icongenerator.h"
19 #include "cellselection.h"
20 #include "keyframeselection.h"
21 #include "cellkeyframeselection.h"
22 #include "columnselection.h"
23 #include "xsheetdragtool.h"
24 #include "toonzqt/gutil.h"
25 
26 #include "toonz/txsheet.h"
27 #include "toonz/txshcell.h"
28 #include "toonz/txshleveltypes.h"
29 #include "toonz/txshzeraryfxcolumn.h"
30 #include "toonz/toonzscene.h"
31 #include "toonz/columnfan.h"
32 #include "toonz/txshnoteset.h"
33 #include "toonz/childstack.h"
34 #include "toonz/txshlevelhandle.h"
35 #include "toonz/tproject.h"
36 #include "tconvert.h"
37 
38 #include "tenv.h"
39 
40 #include <QPainter>
41 #include <QScrollBar>
42 #include <QMouseEvent>
43 
44 TEnv::IntVar FrameDisplayStyleInXsheetRowArea(
45     "FrameDisplayStyleInXsheetRowArea", 0);
46 
47 //=============================================================================
48 namespace XsheetGUI {
49 //-----------------------------------------------------------------------------
50 
51 const int ColumnWidth     = 74;
52 const int RowHeight       = 20;
53 const int SCROLLBAR_WIDTH = 16;
54 const int TOOLBAR_HEIGHT  = 29;
55 const int ZOOM_FACTOR_MAX = 100;
56 const int ZOOM_FACTOR_MIN = 20;
57 }  // namespace XsheetGUI
58 
59 //=============================================================================
60 // XsheetViewer
61 //-----------------------------------------------------------------------------
62 
getCellTypeAndColors(int & ltype,QColor & cellColor,QColor & sideColor,const TXshCell & cell,bool isSelected)63 void XsheetViewer::getCellTypeAndColors(int &ltype, QColor &cellColor,
64                                         QColor &sideColor, const TXshCell &cell,
65                                         bool isSelected) {
66   if (cell.isEmpty())
67     ltype = NO_XSHLEVEL;
68   else {
69     ltype = cell.m_level->getType();
70     switch (ltype) {
71     case TZI_XSHLEVEL:
72     case OVL_XSHLEVEL:
73       cellColor = (isSelected) ? getSelectedFullcolorColumnColor()
74                                : getFullcolorColumnColor();
75       sideColor = getFullcolorColumnBorderColor();
76       break;
77     case PLI_XSHLEVEL:
78       cellColor = (isSelected) ? getSelectedVectorColumnColor()
79                                : getVectorColumnColor();
80       sideColor = getVectorColumnBorderColor();
81       break;
82     case TZP_XSHLEVEL:
83       cellColor =
84           (isSelected) ? getSelectedLevelColumnColor() : getLevelColumnColor();
85       sideColor = getLevelColumnBorderColor();
86       break;
87     case ZERARYFX_XSHLEVEL:
88       cellColor =
89           (isSelected) ? getSelectedFxColumnColor() : getFxColumnColor();
90       sideColor = getFxColumnBorderColor();
91       break;
92     case CHILD_XSHLEVEL:
93       cellColor =
94           (isSelected) ? getSelectedChildColumnColor() : getChildColumnColor();
95       sideColor = getChildColumnBorderColor();
96       break;
97     case SND_XSHLEVEL:
98       cellColor =
99           (isSelected) ? m_selectedSoundColumnColor : m_soundColumnColor;
100       sideColor = m_soundColumnBorderColor;
101       break;
102     case SND_TXT_XSHLEVEL:
103       cellColor = (isSelected) ? getSelectedSoundTextColumnColor()
104                                : getSoundTextColumnColor();
105       sideColor = getSoundTextColumnBorderColor();
106       break;
107     case MESH_XSHLEVEL:
108       cellColor =
109           (isSelected) ? getSelectedMeshColumnColor() : getMeshColumnColor();
110       sideColor = getMeshColumnBorderColor();
111       break;
112     case UNKNOWN_XSHLEVEL:
113     case NO_XSHLEVEL:
114     default:
115       // non dovrebbe succedere
116       cellColor = grey210;
117       sideColor = grey150;
118     }
119   }
120 }
121 
122 //-----------------------------------------------------------------------------
123 
getColumnColor(QColor & color,QColor & sideColor,int index,TXsheet * xsh)124 void XsheetViewer::getColumnColor(QColor &color, QColor &sideColor, int index,
125                                   TXsheet *xsh) {
126   if (index < 0 || xsh->isColumnEmpty(index)) return;
127   int r0, r1;
128   xsh->getCellRange(index, r0, r1);
129   if (0 <= r0 && r0 <= r1) {
130     // column color depends on the level type in the top-most occupied cell
131     if (xsh->getColumn(index)->getSoundColumn()) {
132       color     = m_soundColumnColor;
133       sideColor = m_soundColumnBorderColor;
134     } else {
135       TXshCell cell = xsh->getCell(r0, index);
136       int ltype;
137       getCellTypeAndColors(ltype, color, sideColor, cell);
138     }
139   }
140   if (xsh->getColumn(index)->isMask()) color = QColor(255, 0, 255);
141 }
142 
143 //-----------------------------------------------------------------------------
144 
getButton(int & btype,QColor & bgColor,QImage & iconImage,bool isTimeline)145 void XsheetViewer::getButton(int &btype, QColor &bgColor, QImage &iconImage,
146                              bool isTimeline) {
147   switch (btype) {
148   case PREVIEW_ON_XSHBUTTON:
149     bgColor = (isTimeline) ? getTimelinePreviewButtonBgOnColor()
150                            : getXsheetPreviewButtonBgOnColor();
151     iconImage = (isTimeline) ? getTimelinePreviewButtonOnImage()
152                              : getXsheetPreviewButtonOnImage();
153     break;
154   case PREVIEW_OFF_XSHBUTTON:
155     bgColor = (isTimeline) ? getTimelinePreviewButtonBgOffColor()
156                            : getXsheetPreviewButtonBgOffColor();
157     iconImage = (isTimeline) ? getTimelinePreviewButtonOffImage()
158                              : getXsheetPreviewButtonOffImage();
159     break;
160   case CAMSTAND_ON_XSHBUTTON:
161     bgColor = (isTimeline) ? getTimelineCamstandButtonBgOnColor()
162                            : getXsheetCamstandButtonBgOnColor();
163     iconImage = (isTimeline) ? getTimelineCamstandButtonOnImage()
164                              : getXsheetCamstandButtonOnImage();
165     break;
166   case CAMSTAND_TRANSP_XSHBUTTON:
167     bgColor = (isTimeline) ? getTimelineCamstandButtonBgOnColor()
168                            : getXsheetCamstandButtonBgOnColor();
169     iconImage = (isTimeline) ? getTimelineCamstandButtonTranspImage()
170                              : getXsheetCamstandButtonTranspImage();
171     break;
172   case CAMSTAND_OFF_XSHBUTTON:
173     bgColor = (isTimeline) ? getTimelineCamstandButtonBgOffColor()
174                            : getXsheetCamstandButtonBgOffColor();
175     iconImage = (isTimeline) ? getTimelineCamstandButtonOffImage()
176                              : getXsheetCamstandButtonOffImage();
177     break;
178   case LOCK_ON_XSHBUTTON:
179     bgColor = (isTimeline) ? getTimelineLockButtonBgOnColor()
180                            : getXsheetLockButtonBgOnColor();
181     iconImage = (isTimeline) ? getTimelineLockButtonOnImage()
182                              : getXsheetLockButtonOnImage();
183     break;
184   case LOCK_OFF_XSHBUTTON:
185     bgColor = (isTimeline) ? getTimelineLockButtonBgOffColor()
186                            : getXsheetLockButtonBgOffColor();
187     iconImage = (isTimeline) ? getTimelineLockButtonOffImage()
188                              : getXsheetLockButtonOffImage();
189     break;
190   case CONFIG_XSHBUTTON:
191     bgColor = (isTimeline) ? getTimelineConfigButtonBgColor()
192                            : getXsheetConfigButtonBgColor();
193     iconImage = (isTimeline) ? getTimelineConfigButtonImage()
194                              : getXsheetConfigButtonImage();
195     break;
196   default:
197     bgColor = grey210;
198     static QImage iconignored;
199     iconImage = iconignored;
200   }
201 }
202 
203 //-----------------------------------------------------------------------------
204 
205 #if QT_VERSION >= 0x050500
XsheetViewer(QWidget * parent,Qt::WindowFlags flags)206 XsheetViewer::XsheetViewer(QWidget *parent, Qt::WindowFlags flags)
207 #else
208 XsheetViewer::XsheetViewer(QWidget *parent, Qt::WFlags flags)
209 #endif
210     : QFrame(parent)
211     , m_timerId(0)
212     , m_autoPanSpeed(0, 0)
213     , m_dragTool(0)
214     , m_columnSelection(new TColumnSelection())
215     , m_cellKeyframeSelection(new TCellKeyframeSelection(
216           new TCellSelection(), new TKeyframeSelection()))
217     , m_scrubCol(-1)
218     , m_scrubRow0(-1)
219     , m_scrubRow1(-1)
220     , m_isCurrentFrameSwitched(false)
221     , m_isCurrentColumnSwitched(false)
222     , m_isComputingSize(false)
223     , m_currentNoteIndex(0)
224     , m_qtModifiers(0)
225     , m_frameDisplayStyle(to_enum(FrameDisplayStyleInXsheetRowArea))
226     , m_orientation(nullptr)
227     , m_xsheetLayout("Classic")
228     , m_frameZoomFactor(100) {
229 
230   m_xsheetLayout = Preferences::instance()->getLoadedXsheetLayout();
231 
232   setFocusPolicy(Qt::StrongFocus);
233 
234   setFrameStyle(QFrame::StyledPanel);
235   setObjectName("XsheetViewer");
236 
237   m_orientation = Orientations::topToBottom();
238 
239   m_cellKeyframeSelection->setXsheetHandle(
240       TApp::instance()->getCurrentXsheet());
241 
242   m_toolbarScrollArea = new XsheetScrollArea(this);
243   m_toolbarScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
244   m_toolbarScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
245   m_toolbar = new XsheetGUI::XSheetToolbar(this, 0, true);
246   m_toolbarScrollArea->setWidget(m_toolbar);
247 
248   QRect noteArea(0, 0, 75, 120);
249   m_noteArea       = new XsheetGUI::NoteArea(this);
250   m_noteScrollArea = new XsheetScrollArea(this);
251   m_noteScrollArea->setObjectName("xsheetArea");
252   m_noteScrollArea->setWidget(m_noteArea);
253   m_noteScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
254   m_noteScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
255 
256   m_cellArea       = new XsheetGUI::CellArea(this);
257   m_cellScrollArea = new XsheetScrollArea(this);
258   m_cellScrollArea->setObjectName("xsheetArea");
259   m_cellScrollArea->setWidget(m_cellArea);
260   m_cellScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
261   m_cellScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
262 
263   m_columnArea       = new XsheetGUI::ColumnArea(this);
264   m_columnScrollArea = new XsheetScrollArea(this);
265   m_columnScrollArea->setObjectName("xsheetArea");
266   m_columnScrollArea->setWidget(m_columnArea);
267   m_columnScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
268   m_columnScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
269 
270   m_rowArea       = new XsheetGUI::RowArea(this);
271   m_rowScrollArea = new XsheetScrollArea(this);
272   m_rowScrollArea->setObjectName("xsheetArea");
273   m_rowScrollArea->setWidget(m_rowArea);
274   m_rowScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
275   m_rowScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
276 
277   m_layerFooterPanel = new LayerFooterPanel(this, this);
278 
279   m_frameScroller.setFrameScrollArea(m_cellScrollArea);
280   connect(&m_frameScroller, &Spreadsheet::FrameScroller::prepareToScrollOffset,
281           this, &XsheetViewer::onPrepareToScrollOffset);
282   connect(&m_frameScroller, &Spreadsheet::FrameScroller::zoomScrollAdjust, this,
283           &XsheetViewer::onZoomScrollAdjust);
284 
285   connectScrollBars();
286 
287   connect(this, &XsheetViewer::orientationChanged, this,
288           &XsheetViewer::onOrientationChanged);
289   connect(m_toolbar, SIGNAL(updateVisibility()), this,
290           SLOT(positionSections()));
291 
292   emit orientationChanged(orientation());
293 
294   onPreferenceChanged("XsheetCamera");
295 }
296 
297 //-----------------------------------------------------------------------------
298 
~XsheetViewer()299 XsheetViewer::~XsheetViewer() {
300   delete m_cellKeyframeSelection;
301   delete m_dragTool;
302 }
303 
304 //-----------------------------------------------------------------------------
305 
setDragTool(XsheetGUI::DragTool * dragTool)306 void XsheetViewer::setDragTool(XsheetGUI::DragTool *dragTool) {
307   assert(m_dragTool == 0);
308   m_dragTool = dragTool;
309 }
310 
311 //-----------------------------------------------------------------------------
312 
dragToolClick(QMouseEvent * e)313 void XsheetViewer::dragToolClick(QMouseEvent *e) {
314   if (m_dragTool) m_dragTool->onClick(e);
315 }
316 
dragToolDrag(QMouseEvent * e)317 void XsheetViewer::dragToolDrag(QMouseEvent *e) {
318   if (m_dragTool) m_dragTool->onDrag(e);
319 }
320 
dragToolRelease(QMouseEvent * e)321 void XsheetViewer::dragToolRelease(QMouseEvent *e) {
322   if (m_dragTool) {
323     m_dragTool->onRelease(e);
324     delete getDragTool();
325     m_dragTool = 0;
326   }
327 }
328 
329 //-----------------------------------------------------------------------------
330 
dragToolClick(QDropEvent * e)331 void XsheetViewer::dragToolClick(QDropEvent *e) {
332   if (m_dragTool) m_dragTool->onClick(e);
333 }
334 
dragToolDrag(QDropEvent * e)335 void XsheetViewer::dragToolDrag(QDropEvent *e) {
336   if (m_dragTool) m_dragTool->onDrag(e);
337 }
338 
dragToolRelease(QDropEvent * e)339 void XsheetViewer::dragToolRelease(QDropEvent *e) {
340   if (m_dragTool) {
341     m_dragTool->onRelease(e);
342     delete getDragTool();
343     m_dragTool = 0;
344   }
345 }
346 
dragToolLeave(QEvent * e)347 void XsheetViewer::dragToolLeave(QEvent *e) {
348   if (m_dragTool) {
349     delete getDragTool();
350     m_dragTool = 0;
351   }
352 }
353 
354 //-----------------------------------------------------------------------------
355 
orientation() const356 const Orientation *XsheetViewer::orientation() const {
357   if (!m_orientation) throw std::runtime_error("!m_orientation");
358   return m_orientation;
359 }
360 
flipOrientation()361 void XsheetViewer::flipOrientation() {
362   m_orientation = orientation()->next();
363   emit orientationChanged(orientation());
364 }
365 
onOrientationChanged(const Orientation * newOrientation)366 void XsheetViewer::onOrientationChanged(const Orientation *newOrientation) {
367   disconnectScrollBars();
368 
369   positionSections();
370   m_frameScroller.setOrientation(newOrientation);
371   refreshContentSize(0, 0);
372 
373   connectScrollBars();
374 
375   update();
376 }
377 
positionSections()378 void XsheetViewer::positionSections() {
379   if (!isVisible()) return;
380   const Orientation *o = orientation();
381   QRect size           = QRect(QPoint(0, 0), geometry().size());
382   NumberRange allLayer = o->layerSide(size);
383   NumberRange allFrame = o->frameSide(size);
384 
385   NumberRange headerLayer = o->range(PredefinedRange::HEADER_LAYER);
386   NumberRange headerFrame = o->range(PredefinedRange::HEADER_FRAME);
387   NumberRange bodyLayer(headerLayer.to(), allLayer.to());
388   NumberRange bodyFrame(headerFrame.to(), allFrame.to());
389 
390   if (Preferences::instance()->isShowXSheetToolbarEnabled()) {
391     m_toolbar->showToolbar(true);
392     int w = visibleRegion().boundingRect().width();
393     m_toolbarScrollArea->setGeometry(0, 0, w, XsheetGUI::TOOLBAR_HEIGHT);
394     m_toolbar->setFixedWidth(w);
395     if (o->isVerticalTimeline()) {
396       headerFrame = headerFrame.adjusted(XsheetGUI::TOOLBAR_HEIGHT,
397                                          XsheetGUI::TOOLBAR_HEIGHT);
398       bodyFrame   = bodyFrame.adjusted(XsheetGUI::TOOLBAR_HEIGHT, 0);
399     } else {
400       headerLayer = headerLayer.adjusted(XsheetGUI::TOOLBAR_HEIGHT,
401                                          XsheetGUI::TOOLBAR_HEIGHT);
402       bodyLayer   = bodyLayer.adjusted(XsheetGUI::TOOLBAR_HEIGHT, 0);
403     }
404   } else {
405     m_toolbar->showToolbar(false);
406   }
407 
408   m_noteScrollArea->setGeometry(o->frameLayerRect(headerFrame, headerLayer));
409   m_cellScrollArea->setGeometry(o->frameLayerRect(bodyFrame, bodyLayer));
410   m_columnScrollArea->setGeometry(
411       o->frameLayerRect(headerFrame.adjusted(-1, -1),
412                         bodyLayer.adjusted(0, -XsheetGUI::SCROLLBAR_WIDTH)));
413   m_rowScrollArea->setGeometry(o->frameLayerRect(
414       bodyFrame.adjusted(0, -XsheetGUI::SCROLLBAR_WIDTH), headerLayer));
415 
416   m_layerFooterPanel->setGeometry(0,
417                                   m_columnScrollArea->geometry().bottom() + 1,
418                                   m_columnScrollArea->width(), 14);
419 
420   m_layerFooterPanel->showOrHide(o);
421 }
422 
disconnectScrollBars()423 void XsheetViewer::disconnectScrollBars() {
424   connectOrDisconnectScrollBars(false);
425 }
connectScrollBars()426 void XsheetViewer::connectScrollBars() { connectOrDisconnectScrollBars(true); }
427 
connectOrDisconnectScrollBars(bool toConnect)428 void XsheetViewer::connectOrDisconnectScrollBars(bool toConnect) {
429   const Orientation *o = orientation();
430   bool isVertical      = o->isVerticalTimeline();
431   QWidget *scrolledVertically =
432       (isVertical ? m_rowScrollArea : m_columnScrollArea)->verticalScrollBar();
433   QWidget *scrolledHorizontally =
434       (isVertical ? m_columnScrollArea : m_rowScrollArea)
435           ->horizontalScrollBar();
436 
437   connectOrDisconnect(toConnect, scrolledVertically, SIGNAL(valueChanged(int)),
438                       m_cellScrollArea->verticalScrollBar(),
439                       SLOT(setValue(int)));
440   connectOrDisconnect(toConnect, m_cellScrollArea->verticalScrollBar(),
441                       SIGNAL(valueChanged(int)), scrolledVertically,
442                       SLOT(setValue(int)));
443 
444   connectOrDisconnect(
445       toConnect, scrolledHorizontally, SIGNAL(valueChanged(int)),
446       m_cellScrollArea->horizontalScrollBar(), SLOT(setValue(int)));
447   connectOrDisconnect(toConnect, m_cellScrollArea->horizontalScrollBar(),
448                       SIGNAL(valueChanged(int)), scrolledHorizontally,
449                       SLOT(setValue(int)));
450 
451   connectOrDisconnect(
452       toConnect, m_cellScrollArea->verticalScrollBar(),
453       SIGNAL(valueChanged(int)), this,
454       isVertical ? SLOT(updateCellRowAree()) : SLOT(updateCellColumnAree()));
455   connectOrDisconnect(
456       toConnect, m_cellScrollArea->horizontalScrollBar(),
457       SIGNAL(valueChanged(int)), this,
458       isVertical ? SLOT(updateCellColumnAree()) : SLOT(updateCellRowAree()));
459 }
460 
connectOrDisconnect(bool toConnect,QWidget * sender,const char * signal,QWidget * receiver,const char * slot)461 void XsheetViewer::connectOrDisconnect(bool toConnect, QWidget *sender,
462                                        const char *signal, QWidget *receiver,
463                                        const char *slot) {
464   if (toConnect)
465     connect(sender, signal, receiver, slot);
466   else
467     disconnect(sender, signal, receiver, slot);
468 }
469 
470 //-----------------------------------------------------------------------------
471 
getXsheet() const472 TXsheet *XsheetViewer::getXsheet() const {
473   return TApp::instance()->getCurrentXsheet()->getXsheet();
474 }
475 
476 //-----------------------------------------------------------------------------
477 
getCurrentColumn() const478 int XsheetViewer::getCurrentColumn() const {
479   return TApp::instance()->getCurrentColumn()->getColumnIndex();
480 }
481 
482 //-----------------------------------------------------------------------------
483 
getCurrentRow() const484 int XsheetViewer::getCurrentRow() const {
485   return TApp::instance()->getCurrentFrame()->getFrame();
486 }
487 
488 //-----------------------------------------------------------------------------
489 
getObjectId(int col) const490 TStageObjectId XsheetViewer::getObjectId(int col) const {
491   TXsheet *xsh = getXsheet();
492   if (col < 0) return TStageObjectId::CameraId(xsh->getCameraColumnIndex());
493   return TStageObjectId::ColumnId(col);
494 }
495 //-----------------------------------------------------------------------------
496 
setCurrentColumn(int col)497 void XsheetViewer::setCurrentColumn(int col) {
498   TColumnHandle *columnHandle = TApp::instance()->getCurrentColumn();
499   if (col != columnHandle->getColumnIndex()) {
500     columnHandle->setColumnIndex(col);
501     // E' necessario per il caso in cui si passa da colonna di camera a altra
502     // colonna
503     // o nel caso in cui si passa da una spline a una colonna.
504     TObjectHandle *objectHandle = TApp::instance()->getCurrentObject();
505     if (col >= 0 && objectHandle->isSpline()) objectHandle->setIsSpline(false);
506     updateCellColumnAree();
507     if (col >= 0) {
508       objectHandle->setObjectId(TStageObjectId::ColumnId(col));
509       TXsheet *xsh       = getXsheet();
510       TXshColumn *column = xsh->getColumn(col);
511       if (!column || !column->getZeraryFxColumn()) return;
512       TFx *fx = column->getZeraryFxColumn()->getZeraryColumnFx();
513       TApp::instance()->getCurrentFx()->setFx(fx);
514     }
515     return;
516   }
517 }
518 
519 //-----------------------------------------------------------------------------
520 
setCurrentRow(int row)521 void XsheetViewer::setCurrentRow(int row) {
522   // POTREBBE NON ESSER PIU' NECESSARIO CON LE NUOVE MODIFICHE PER CLEANUP A
523   // COLORI
524   /*TFrameHandle* frameHandle = TApp::instance()->getCurrentFrame();
525 if(row == frameHandle->getFrameIndex() && frameHandle->getFrameType() ==
526 TFrameHandle::SceneFrame)
527 {
528 //E' necessario per il caso in cui la paletta corrente e' la paletta di cleanup.
529 TPaletteHandle* levelPaletteHandle =
530 TApp::instance()->getPaletteController()->getCurrentLevelPalette();
531 TXshLevel *xl = TApp::instance()->getCurrentLevel()->getLevel();
532 if(xl && xl->getSimpleLevel())
533                   levelPaletteHandle->setPalette(xl->getSimpleLevel()->getPalette());
534 else if(xl && xl->getPaletteLevel())
535                   levelPaletteHandle->setPalette(xl->getPaletteLevel()->getPalette());
536 else
537 levelPaletteHandle->setPalette(0);
538 return;
539 }
540 frameHandle->setFrame(row);*/
541   TApp::instance()->getCurrentFrame()->setFrame(row);
542 }
543 
544 //-----------------------------------------------------------------------------
545 
scroll(QPoint delta)546 void XsheetViewer::scroll(QPoint delta) {
547   int x = delta.x();
548   int y = delta.y();
549 
550   int valueH    = m_cellScrollArea->horizontalScrollBar()->value() + x;
551   int valueV    = m_cellScrollArea->verticalScrollBar()->value() + y;
552   int maxValueH = m_cellScrollArea->horizontalScrollBar()->maximum();
553   int maxValueV = m_cellScrollArea->verticalScrollBar()->maximum();
554 
555   bool notUpdateSizeH = maxValueH > valueH && x >= 0;
556   bool notUpdateSizeV = maxValueV > valueV && y >= 0;
557   if (!notUpdateSizeH && !notUpdateSizeV)  // Resize orizzontale e verticale
558     refreshContentSize(x, y);
559   else if (notUpdateSizeH && !notUpdateSizeV)  // Resize verticale
560     refreshContentSize(0, y);
561   else if (!notUpdateSizeH && notUpdateSizeV)  // Resize orizzontale
562     refreshContentSize(x, 0);
563 
564   // Recheck in case refreshContentSize changed the max
565   if (!notUpdateSizeH)
566     maxValueH = m_cellScrollArea->horizontalScrollBar()->maximum();
567   if (!notUpdateSizeV)
568     maxValueV = m_cellScrollArea->verticalScrollBar()->maximum();
569 
570   if (valueH > maxValueH && x > 0)  // Se il valore e' maggiore del max e x>0
571                                     // scrollo al massimo valore orizzontale
572     valueH = m_cellScrollArea->horizontalScrollBar()->maximum();
573 
574   if (valueV > maxValueV && y > 0)  // Se il valore e' maggiore del max e y>0
575                                     // scrollo al massimo valore verticale
576     valueV = m_cellScrollArea->verticalScrollBar()->maximum();
577 
578   m_cellScrollArea->horizontalScrollBar()->setValue(valueH);
579   m_cellScrollArea->verticalScrollBar()->setValue(valueV);
580 }
581 
582 //-----------------------------------------------------------------------------
583 
onPrepareToScrollOffset(const QPoint & offset)584 void XsheetViewer::onPrepareToScrollOffset(const QPoint &offset) {
585   refreshContentSize(offset.x(), offset.y());
586 }
587 
588 //-----------------------------------------------------------------------------
589 
onZoomScrollAdjust(QPoint & offset,bool toZoom)590 void XsheetViewer::onZoomScrollAdjust(QPoint &offset, bool toZoom) {
591   int frameZoomFactor = getFrameZoomFactor();
592 
593   // toZoom = true: Adjust standardized offset down to zoom factor
594   // toZoom = false: Adjust zoomed offset up to standardized offset
595   int newX;
596   if (toZoom)
597     newX = (offset.x() * frameZoomFactor) / 100;
598   else
599     newX = (offset.x() * 100) / frameZoomFactor;
600 
601   offset.setX(newX);
602 }
603 
604 //-----------------------------------------------------------------------------
605 
setAutoPanSpeed(const QPoint & speed)606 void XsheetViewer::setAutoPanSpeed(const QPoint &speed) {
607   bool wasAutoPanning = isAutoPanning();
608   m_autoPanSpeed      = speed;
609   if (isAutoPanning() && !wasAutoPanning && m_timerId == 0)
610     m_timerId = startTimer(40);
611   else if (!isAutoPanning() && wasAutoPanning && m_timerId != 0) {
612     killTimer(m_timerId);
613     m_timerId = 0;
614   }
615 }
616 
617 //-----------------------------------------------------------------------------
618 
getAutoPanSpeed(int pixels)619 static int getAutoPanSpeed(int pixels) {
620   int f = 40;
621   return std::min(100, (f - 1 + pixels * f) / 100);
622 }
623 
624 //-----------------------------------------------------------------------------
625 
setAutoPanSpeed(const QRect & widgetBounds,const QPoint & mousePos)626 void XsheetViewer::setAutoPanSpeed(const QRect &widgetBounds,
627                                    const QPoint &mousePos) {
628   QPoint speed;
629   int limit = 100, factor = 30;
630   if (mousePos.x() < widgetBounds.left())
631     speed.setX(-getAutoPanSpeed(widgetBounds.left() - mousePos.x()));
632   else if (mousePos.x() > widgetBounds.right())
633     speed.setX(getAutoPanSpeed(mousePos.x() - widgetBounds.right()));
634   if (mousePos.y() < widgetBounds.top())
635     speed.setY(-getAutoPanSpeed(widgetBounds.top() - mousePos.y()));
636   else if (mousePos.y() > widgetBounds.bottom())
637     speed.setY(getAutoPanSpeed(mousePos.y() - widgetBounds.bottom()));
638   setAutoPanSpeed(speed);
639   m_lastAutoPanPos = mousePos;
640 }
641 
642 //-----------------------------------------------------------------------------
643 
timerEvent(QTimerEvent *)644 void XsheetViewer::timerEvent(QTimerEvent *) {
645   if (!isAutoPanning()) return;
646   scroll(m_autoPanSpeed);
647   if (!m_dragTool) return;
648   QMouseEvent mouseEvent(QEvent::MouseMove, m_lastAutoPanPos - m_autoPanSpeed,
649                          Qt::NoButton, 0, m_qtModifiers);
650   m_dragTool->onDrag(&mouseEvent);
651   m_lastAutoPanPos += m_autoPanSpeed;
652 }
653 
654 //-----------------------------------------------------------------------------
655 
656 // adjust sizes after scrolling event
refreshContentSize(int dx,int dy)657 bool XsheetViewer::refreshContentSize(int dx, int dy) {
658   QSize viewportSize = m_cellScrollArea->viewport()->size();
659   QPoint offset      = m_cellArea->pos();
660   offset             = QPoint(std::min(0, offset.x() - dx),
661                   std::min(0, offset.y() - dy));  // what?
662 
663   TXsheet *xsh    = getXsheet();
664   int frameCount  = xsh ? xsh->getFrameCount() : 0;
665   int columnCount = xsh ? xsh->getColumnCount() : 0;
666   QPoint contentSize;
667 
668   if (m_orientation->isVerticalTimeline())
669     contentSize = positionToXY(CellPosition(frameCount + 1, columnCount + 1));
670   else {
671     int firstCol =
672         Preferences::instance()->isXsheetCameraColumnVisible() ? -1 : 0;
673     contentSize = positionToXY(CellPosition(frameCount + 1, firstCol));
674 
675     ColumnFan *fan = xsh->getColumnFan(m_orientation);
676     contentSize.setY(contentSize.y() + 1 +
677                      (fan->isActive(firstCol)
678                           ? m_orientation->cellHeight()
679                           : m_orientation->foldedCellSize()));
680   }
681 
682   QSize actualSize(contentSize.x(), contentSize.y());
683   int x = viewportSize.width() - offset.x();  // wtf is going on
684   int y = viewportSize.height() - offset.y();
685   if (x > actualSize.width()) actualSize.setWidth(x);
686   if (m_orientation->isVerticalTimeline() && y > actualSize.height())
687     actualSize.setHeight(y);
688 
689   if (actualSize == m_cellArea->size())
690     return false;
691   else {
692     const Orientation *o    = orientation();
693     NumberRange allLayer    = o->layerSide(QRect(QPoint(0, 0), actualSize));
694     NumberRange allFrame    = o->frameSide(QRect(QPoint(0, 0), actualSize));
695     NumberRange headerLayer = o->range(PredefinedRange::HEADER_LAYER);
696     NumberRange headerFrame = o->range(PredefinedRange::HEADER_FRAME);
697 
698     m_isComputingSize = true;
699     m_noteArea->setFixedSize(o->rect(PredefinedRect::NOTE_AREA).size());
700     m_cellArea->setFixedSize(actualSize);
701     m_rowArea->setFixedSize(o->frameLayerRect(allFrame, headerLayer).size());
702     m_columnArea->setFixedSize(o->frameLayerRect(headerFrame, allLayer).size());
703     m_isComputingSize = false;
704     return true;
705   }
706 }
707 
708 //-----------------------------------------------------------------------------
709 
710 // call when in doubt
updateAreeSize()711 void XsheetViewer::updateAreeSize() {
712   const Orientation *o = orientation();
713   QRect viewArea(QPoint(0, 0), m_cellScrollArea->geometry()
714                                    .adjusted(0, 0, -XsheetGUI::SCROLLBAR_WIDTH,
715                                              -XsheetGUI::SCROLLBAR_WIDTH)
716                                    .size());
717 
718   QPoint areaFilled(0, 0);
719   TXsheet *xsh = getXsheet();
720   if (xsh) {
721     if (o->isVerticalTimeline())
722       areaFilled = positionToXY(
723           CellPosition(xsh->getFrameCount() + 1, xsh->getColumnCount() + 1));
724     else {
725       int firstCol =
726           Preferences::instance()->isXsheetCameraColumnVisible() ? -1 : 0;
727       areaFilled =
728           positionToXY(CellPosition(xsh->getFrameCount() + 1, firstCol));
729 
730       ColumnFan *fan = xsh->getColumnFan(m_orientation);
731       areaFilled.setY(
732           areaFilled.y() + 1 +
733           (fan->isActive(firstCol) ? o->cellHeight() : o->foldedCellSize()));
734     }
735   }
736   if (viewArea.width() < areaFilled.x()) viewArea.setWidth(areaFilled.x());
737   if (viewArea.height() < areaFilled.y() ||
738       (!o->isVerticalTimeline() && viewArea.height() != areaFilled.y()))
739     viewArea.setHeight(areaFilled.y());
740 
741   NumberRange allLayer    = o->layerSide(viewArea);
742   NumberRange allFrame    = o->frameSide(viewArea);
743   NumberRange headerLayer = o->range(PredefinedRange::HEADER_LAYER);
744   NumberRange headerFrame = o->range(PredefinedRange::HEADER_FRAME);
745 
746   m_cellArea->setFixedSize(viewArea.size());
747   m_rowArea->setFixedSize(o->frameLayerRect(allFrame, headerLayer).size());
748   m_columnArea->setFixedSize(o->frameLayerRect(headerFrame, allLayer).size());
749 }
750 
751 //-----------------------------------------------------------------------------
752 
colToTimelineLayerAxis(int layer) const753 int XsheetViewer::colToTimelineLayerAxis(int layer) const {
754   const Orientation *o = orientation();
755   TXsheet *xsh         = getXsheet();
756   if (!xsh) return 0;
757   ColumnFan *fan = xsh->getColumnFan(o);
758 
759   int yBottom = o->colToLayerAxis(layer, fan) +
760                 (fan->isActive(layer) ? o->cellHeight() : o->foldedCellSize()) -
761                 1;
762   int columnCount = std::max(1, xsh->getColumnCount());
763   int layerHeightActual =
764       m_columnArea->height() - 2;  // o->colToLayerAxis(columnCount, fan) - 1;
765 
766   return layerHeightActual - yBottom;
767 }
768 
769 //-----------------------------------------------------------------------------
770 
xyToPosition(const QPoint & point) const771 CellPosition XsheetViewer::xyToPosition(const QPoint &point) const {
772   const Orientation *o = orientation();
773   QPoint usePoint      = point;
774   TXsheet *xsh         = getXsheet();
775 
776   if (!xsh) return CellPosition(0, 0);
777 
778   ColumnFan *fan = xsh->getColumnFan(o);
779 
780   if (!o->isVerticalTimeline())
781     usePoint.setX((usePoint.x() * 100) / getFrameZoomFactor());
782 
783   if (o->isVerticalTimeline()) return o->xyToPosition(usePoint, fan);
784 
785   // For timeline mode, we need to base the Y axis on the bottom of the column
786   // area
787   // since the layers are flipped
788   int columnCount   = std::max(1, xsh->getColumnCount());
789   int colAreaHeight = o->colToLayerAxis(columnCount, fan);
790 
791   usePoint.setY(colAreaHeight - usePoint.y());
792 
793   CellPosition resultCP = o->xyToPosition(usePoint, fan);
794   if (point.y() > colAreaHeight) {
795     int colsBelow = ((point.y() - colAreaHeight) / o->cellHeight()) + 1;
796     resultCP.setLayer(-colsBelow);
797   }
798   return resultCP;
799 }
xyToPosition(const TPoint & point) const800 CellPosition XsheetViewer::xyToPosition(const TPoint &point) const {
801   return xyToPosition(QPoint(point.x, point.y));
802 }
xyToPosition(const TPointD & point) const803 CellPosition XsheetViewer::xyToPosition(const TPointD &point) const {
804   return xyToPosition(QPoint((int)point.x, (int)point.y));
805 }
806 
807 //-----------------------------------------------------------------------------
808 
positionToXY(const CellPosition & pos) const809 QPoint XsheetViewer::positionToXY(const CellPosition &pos) const {
810   const Orientation *o = orientation();
811   TXsheet *xsh         = getXsheet();
812   if (!xsh) return QPoint(0, 0);
813   ColumnFan *fan  = xsh->getColumnFan(o);
814   QPoint usePoint = o->positionToXY(pos, fan);
815 
816   if (!o->isVerticalTimeline())
817     usePoint.setX((usePoint.x() * getFrameZoomFactor()) / 100);
818 
819   if (o->isVerticalTimeline()) return usePoint;
820 
821   // For timeline mode, we need to base the Y axis on the bottom of the column
822   // area
823   // since the layers are flipped
824 
825   usePoint.setY(
826       usePoint.y() - o->cellHeight() +
827       (fan->isActive(pos.layer()) ? o->cellHeight() : o->foldedCellSize()));
828   int columnCount = std::max(1, xsh->getColumnCount());
829   int colsHeight  = o->colToLayerAxis(columnCount, fan);
830 
831   if (colsHeight)
832     usePoint.setY(colsHeight - usePoint.y() - o->cellHeight());
833   else
834     usePoint.setY(0);
835 
836   return usePoint;
837 }
838 
columnToLayerAxis(int layer) const839 int XsheetViewer::columnToLayerAxis(int layer) const {
840   const Orientation *o = orientation();
841   TXsheet *xsh         = getXsheet();
842   if (!xsh) return 0;
843   if (o->isVerticalTimeline())
844     return o->colToLayerAxis(layer, xsh->getColumnFan(o));
845   else
846     return colToTimelineLayerAxis(layer);
847 }
rowToFrameAxis(int frame) const848 int XsheetViewer::rowToFrameAxis(int frame) const {
849   int result = orientation()->rowToFrameAxis(frame);
850   if (!orientation()->isVerticalTimeline())
851     result = (result * getFrameZoomFactor()) / 100;
852   return result;
853 }
854 
855 //-----------------------------------------------------------------------------
856 
xyRectToRange(const QRect & rect) const857 CellRange XsheetViewer::xyRectToRange(const QRect &rect) const {
858   CellPosition topLeft     = xyToPosition(rect.topLeft());
859   CellPosition bottomRight = xyToPosition(rect.bottomRight());
860   return CellRange(topLeft, bottomRight);
861 }
862 
863 //-----------------------------------------------------------------------------
864 
rangeToXYRect(const CellRange & range) const865 QRect XsheetViewer::rangeToXYRect(const CellRange &range) const {
866   QPoint from = positionToXY(range.from());
867   QPoint to   = positionToXY(range.to());
868   QPoint topLeft =
869       QPoint(std::min(from.x(), to.x()), std::min(from.y(), to.y()));
870   QPoint bottomRight =
871       QPoint(std::max(from.x(), to.x()), std::max(from.y(), to.y()));
872   return QRect(topLeft, bottomRight);
873 }
874 
875 //-----------------------------------------------------------------------------
876 
drawPredefinedPath(QPainter & p,PredefinedPath which,const CellPosition & pos,optional<QColor> fill,optional<QColor> outline) const877 void XsheetViewer::drawPredefinedPath(QPainter &p, PredefinedPath which,
878                                       const CellPosition &pos,
879                                       optional<QColor> fill,
880                                       optional<QColor> outline) const {
881   QPoint xy         = positionToXY(pos);
882   QPainterPath path = orientation()->path(which).translated(xy);
883   if (fill) p.fillPath(path, QBrush(*fill));
884   if (outline) {
885     p.setPen(*outline);
886     p.drawPath(path);
887   }
888 }
889 
890 //-----------------------------------------------------------------------------
891 
drawPredefinedPath(QPainter & p,PredefinedPath which,QPoint xy,optional<QColor> fill,optional<QColor> outline) const892 void XsheetViewer::drawPredefinedPath(QPainter &p, PredefinedPath which,
893                                       QPoint xy, optional<QColor> fill,
894                                       optional<QColor> outline) const {
895   QPainterPath path = orientation()->path(which).translated(xy);
896   if (fill) p.fillPath(path, QBrush(*fill));
897   if (outline) {
898     p.setPen(*outline);
899     p.drawPath(path);
900   }
901 }
902 
903 //-----------------------------------------------------------------------------
904 
areCellsSelectedEmpty()905 bool XsheetViewer::areCellsSelectedEmpty() {
906   int r0, c0, r1, c1;
907   getCellSelection()->getSelectedCells(r0, c0, r1, c1);
908   int i, j;
909   for (i = r0; i <= r1; i++)
910     for (j = c0; j <= c1; j++)
911       if (!getXsheet()->getCell(i, j).isEmpty()) return false;
912   return true;
913 }
914 
915 //-----------------------------------------------------------------------------
916 
areSoundCellsSelected()917 bool XsheetViewer::areSoundCellsSelected() {
918   int r0, c0, r1, c1;
919   getCellSelection()->getSelectedCells(r0, c0, r1, c1);
920   if (c0 < 0) return false;
921   int i, j;
922   for (i = r0; i <= r1; i++)
923     for (j = c0; j <= c1; j++) {
924       TXshCell cell = getXsheet()->getCell(i, j);
925       if (cell.isEmpty() || cell.getSoundLevel()) continue;
926       return false;
927     }
928   return !areCellsSelectedEmpty();
929 }
930 
931 //-----------------------------------------------------------------------------
932 
areSoundTextCellsSelected()933 bool XsheetViewer::areSoundTextCellsSelected() {
934   int r0, c0, r1, c1;
935   getCellSelection()->getSelectedCells(r0, c0, r1, c1);
936   if (c0 < 0) return false;
937   int i, j;
938   for (i = r0; i <= r1; i++)
939     for (j = c0; j <= c1; j++) {
940       TXshCell cell = getXsheet()->getCell(i, j);
941       if (cell.isEmpty() || cell.getSoundTextLevel()) continue;
942       return false;
943     }
944   return !areCellsSelectedEmpty();
945 }
946 
947 //-----------------------------------------------------------------------------
948 
areCameraCellsSelected()949 bool XsheetViewer::areCameraCellsSelected() {
950   int r0, c0, r1, c1;
951   getCellSelection()->getSelectedCells(r0, c0, r1, c1);
952   return c0 < 0;
953 }
954 
955 //-----------------------------------------------------------------------------
956 
setScrubHighlight(int row,int startRow,int col)957 void XsheetViewer::setScrubHighlight(int row, int startRow, int col) {
958   if (m_scrubCol == -1) m_scrubCol = col;
959   m_scrubRow0 = std::min(row, startRow);
960   m_scrubRow1 = std::max(row, startRow);
961   return;
962 }
963 
964 //-----------------------------------------------------------------------------
965 
resetScrubHighlight()966 void XsheetViewer::resetScrubHighlight() {
967   m_scrubCol = m_scrubRow0 = m_scrubRow1 = -1;
968   return;
969 }
970 
971 //-----------------------------------------------------------------------------
972 
getScrubHeighlight(int & R0,int & R1)973 void XsheetViewer::getScrubHeighlight(int &R0, int &R1) {
974   R0 = m_scrubRow0;
975   R1 = m_scrubRow1;
976   return;
977 }
978 
979 //-----------------------------------------------------------------------------
980 
isScrubHighlighted(int row,int col)981 bool XsheetViewer::isScrubHighlighted(int row, int col) {
982   if (m_scrubCol == col && m_scrubRow0 <= row && row <= m_scrubRow1)
983     return true;
984   return false;
985 }
986 
987 //-----------------------------------------------------------------------------
988 
showEvent(QShowEvent *)989 void XsheetViewer::showEvent(QShowEvent *) {
990   m_frameScroller.registerFrameScroller();
991   if (m_isCurrentFrameSwitched) onCurrentFrameSwitched();
992   if (m_isCurrentColumnSwitched) onCurrentColumnSwitched();
993   m_isCurrentFrameSwitched = false;
994 
995   TApp *app = TApp::instance();
996 
997   bool ret = connect(app->getCurrentColumn(), SIGNAL(columnIndexSwitched()),
998                      this, SLOT(onCurrentColumnSwitched()));
999   ret = ret && connect(app->getCurrentFrame(), SIGNAL(frameSwitched()), this,
1000                        SLOT(onCurrentFrameSwitched()));
1001   ret = ret && connect(app->getCurrentFrame(), SIGNAL(isPlayingStatusChanged()),
1002                        this, SLOT(onPlayingStatusChanged()));
1003   ret = ret && connect(app->getCurrentFrame(), SIGNAL(scrubStopped()), this,
1004                        SLOT(onScrubStopped()));
1005 
1006   ret = ret && connect(app->getCurrentObject(), SIGNAL(objectChanged(bool)),
1007                        this, SLOT(updateAllAree(bool)));
1008 
1009   TSceneHandle *sceneHandle = app->getCurrentScene();
1010   ret = ret && connect(sceneHandle, SIGNAL(sceneSwitched()), this,
1011                        SLOT(onSceneSwitched()));
1012   ret = ret && connect(sceneHandle, SIGNAL(nameSceneChanged()), this,
1013                        SLOT(changeWindowTitle()));
1014   ret = ret && connect(sceneHandle, SIGNAL(preferenceChanged(const QString &)),
1015                        this, SLOT(onPreferenceChanged(const QString &)));
1016 
1017   TXsheetHandle *xsheetHandle = app->getCurrentXsheet();
1018   ret = ret && connect(xsheetHandle, SIGNAL(xsheetSwitched()), this,
1019                        SLOT(updateAllAree()));
1020   ret = ret && connect(xsheetHandle, SIGNAL(xsheetSwitched()), this,
1021                        SLOT(resetXsheetNotes()));
1022   ret = ret && connect(xsheetHandle, SIGNAL(xsheetChanged()), this,
1023                        SLOT(onXsheetChanged()));
1024   ret = ret && connect(xsheetHandle, SIGNAL(xsheetChanged()), this,
1025                        SLOT(changeWindowTitle()));
1026 
1027   ret = ret &&
1028         connect(app->getCurrentSelection(),
1029                 SIGNAL(selectionSwitched(TSelection *, TSelection *)), this,
1030                 SLOT(onSelectionSwitched(TSelection *, TSelection *)));
1031   // update titlebar when the cell selection region is changed
1032   ret = ret && connect(app->getCurrentSelection(),
1033                        SIGNAL(selectionChanged(TSelection *)), this,
1034                        SLOT(onSelectionChanged(TSelection *)));
1035   // show the current level name to title bar
1036   ret = ret &&
1037         connect(app->getCurrentLevel(), SIGNAL(xshLevelSwitched(TXshLevel *)),
1038                 this, SLOT(changeWindowTitle()));
1039 
1040   ret = ret && connect(IconGenerator::instance(), SIGNAL(iconGenerated()), this,
1041                        SLOT(updateColumnArea()));
1042 
1043   assert(ret);
1044   refreshContentSize(0, 0);
1045   changeWindowTitle();
1046 }
1047 
1048 //-----------------------------------------------------------------------------
1049 
hideEvent(QHideEvent *)1050 void XsheetViewer::hideEvent(QHideEvent *) {
1051   m_frameScroller.unregisterFrameScroller();
1052 
1053   TApp *app = TApp::instance();
1054 
1055   disconnect(app->getCurrentColumn(), SIGNAL(columnIndexSwitched()), this,
1056              SLOT(onCurrentColumnSwitched()));
1057   disconnect(app->getCurrentFrame(), SIGNAL(frameSwitched()), this,
1058              SLOT(onCurrentFrameSwitched()));
1059   disconnect(app->getCurrentFrame(), SIGNAL(scrubStopped()), this,
1060              SLOT(onScrubStopped()));
1061 
1062   disconnect(app->getCurrentObject(), SIGNAL(objectChanged(bool)), this,
1063              SLOT(updateAllAree(bool)));
1064 
1065   TSceneHandle *sceneHandle = app->getCurrentScene();
1066   disconnect(sceneHandle, SIGNAL(sceneSwitched()), this,
1067              SLOT(onSceneSwitched()));
1068   disconnect(sceneHandle, SIGNAL(nameSceneChanged()), this,
1069              SLOT(changeWindowTitle()));
1070 
1071   TXsheetHandle *xsheetHandle = app->getCurrentXsheet();
1072   disconnect(xsheetHandle, SIGNAL(xsheetSwitched()), this,
1073              SLOT(updateAllAree()));
1074   disconnect(xsheetHandle, SIGNAL(xsheetChanged()), this,
1075              SLOT(onXsheetChanged()));
1076   disconnect(xsheetHandle, SIGNAL(xsheetChanged()), this,
1077              SLOT(changeWindowTitle()));
1078 
1079   disconnect(app->getCurrentSelection(),
1080              SIGNAL(selectionSwitched(TSelection *, TSelection *)), this,
1081              SLOT(onSelectionSwitched(TSelection *, TSelection *)));
1082 
1083   disconnect(app->getCurrentSelection(), SIGNAL(selectionChanged(TSelection *)),
1084              this, SLOT(onSelectionChanged(TSelection *)));
1085 
1086   disconnect(app->getCurrentLevel(), SIGNAL(xshLevelSwitched(TXshLevel *)),
1087              this, SLOT(changeWindowTitle()));
1088 
1089   disconnect(IconGenerator::instance(), SIGNAL(iconGenerated()), this,
1090              SLOT(updateColumnArea()));
1091 }
1092 
1093 //-----------------------------------------------------------------------------
1094 
resizeEvent(QResizeEvent * event)1095 void XsheetViewer::resizeEvent(QResizeEvent *event) {
1096   positionSections();
1097 
1098   //(New Layout Manager) introduced automatic refresh
1099   refreshContentSize(
1100       0,
1101       0);  // Don't updateAreeSize because you have to account scrollbars
1102   updateAllAree();
1103 }
1104 
1105 //-----------------------------------------------------------------------------
1106 
wheelEvent(QWheelEvent * event)1107 void XsheetViewer::wheelEvent(QWheelEvent *event) {
1108   switch (event->source()) {
1109   case Qt::MouseEventNotSynthesized: {
1110     if (0 != (event->modifiers() & Qt::ControlModifier) &&
1111         event->angleDelta().y() != 0) {
1112       QPoint pos(event->pos().x() - m_columnArea->geometry().width() +
1113                      m_cellArea->visibleRegion().boundingRect().left(),
1114                  event->pos().y());
1115       int targetFrame = xyToPosition(pos).frame();
1116 
1117       int newFactor =
1118           getFrameZoomFactor() + ((event->angleDelta().y() > 0 ? 1 : -1) * 10);
1119       if (newFactor > XsheetGUI::ZOOM_FACTOR_MAX)
1120         newFactor = XsheetGUI::ZOOM_FACTOR_MAX;
1121       else if (newFactor < XsheetGUI::ZOOM_FACTOR_MIN)
1122         newFactor = XsheetGUI::ZOOM_FACTOR_MIN;
1123       zoomOnFrame(targetFrame, newFactor);
1124 
1125       event->accept();
1126       return;
1127     }
1128 
1129     int markerDistance = 0, markerOffset = 0;
1130     TApp::instance()
1131         ->getCurrentScene()
1132         ->getScene()
1133         ->getProperties()
1134         ->getMarkers(markerDistance, markerOffset);
1135 
1136     if (event->angleDelta().x() == 0) {  // vertical scroll
1137       if (!orientation()->isVerticalTimeline()) markerDistance = 1;
1138       int scrollPixels = (event->angleDelta().y() > 0 ? 1 : -1) *
1139                          markerDistance * orientation()->cellHeight();
1140       scroll(QPoint(0, -scrollPixels));
1141     } else {  // horizontal scroll
1142       if (orientation()->isVerticalTimeline()) markerDistance = 1;
1143       int scrollPixels = (event->angleDelta().x() > 0 ? 1 : -1) *
1144                          markerDistance * orientation()->cellWidth();
1145       scroll(QPoint(-scrollPixels, 0));
1146     }
1147     break;
1148   }
1149 
1150   case Qt::MouseEventSynthesizedBySystem:  // macbook touch-pad
1151   {
1152     QPoint numPixels  = event->pixelDelta();
1153     QPoint numDegrees = event->angleDelta() / 8;
1154     if (!numPixels.isNull()) {
1155       scroll(-numPixels);
1156     } else if (!numDegrees.isNull()) {
1157       QPoint numSteps = numDegrees / 15;
1158       scroll(-numSteps);
1159     }
1160     break;
1161   }
1162 
1163   default:  // Qt::MouseEventSynthesizedByQt,
1164             // Qt::MouseEventSynthesizedByApplication
1165   {
1166     std::cout << "not supported event: Qt::MouseEventSynthesizedByQt, "
1167                  "Qt::MouseEventSynthesizedByApplication"
1168               << std::endl;
1169     break;
1170   }
1171 
1172   }  // end switch
1173 }
1174 
1175 //-----------------------------------------------------------------------------
1176 
keyPressEvent(QKeyEvent * event)1177 void XsheetViewer::keyPressEvent(QKeyEvent *event) {
1178   struct Locals {
1179     XsheetViewer *m_this;
1180 
1181     void scrollVertTo(double y, const QRect &visibleRect) {
1182       int deltaY = (y < visibleRect.top()) ? y - visibleRect.top()
1183                                            : y - visibleRect.bottom();
1184 
1185       m_this->scroll(QPoint(0, deltaY));
1186     }
1187 
1188     void scrollHorizTo(double x, const QRect &visibleRect) {
1189       int deltaX = (x < visibleRect.left()) ? x - visibleRect.left()
1190                                             : x - visibleRect.right();
1191 
1192       m_this->scroll(QPoint(deltaX, 0));
1193     }
1194   } locals = {this};
1195 
1196   if (changeFrameSkippingHolds(event)) return;
1197 
1198   int frameCount = getXsheet()->getFrameCount();
1199   CellPosition now(getCurrentRow(), getCurrentColumn());
1200   CellPosition shift = orientation()->arrowShift(event->key());
1201   CellPosition stride(1, 1);  // stride in row and column axes
1202 
1203   TCellSelection *cellSel =
1204       dynamic_cast<TCellSelection *>(TSelection::getCurrent());
1205   int firstCol =
1206       Preferences::instance()->isXsheetCameraColumnVisible() ? -1 : 0;
1207   // Use arrow keys to shift the cell selection. Ctrl + arrow keys to resize the
1208   // selection range.
1209   if (Preferences::instance()->isUseArrowKeyToShiftCellSelectionEnabled() &&
1210       cellSel && !cellSel->isEmpty()) {
1211     int r0, c0, r1, c1;
1212     cellSel->getSelectedCells(r0, c0, r1, c1);
1213     stride.setFrame(cellSel->getSelectedCells().getRowCount());
1214 
1215     if (m_cellArea->isControlPressed()) {  // resize
1216       if (r0 == r1 && shift.frame() < 0) return;
1217       if (c0 == c1 && shift.layer() < firstCol) return;
1218       cellSel->selectCells(r0, c0, r1 + shift.frame(), c1 + shift.layer());
1219       updateCells();
1220       TApp::instance()->getCurrentSelection()->notifySelectionChanged();
1221       return;
1222     } else {  // shift
1223       CellPosition offset(shift * stride);
1224       int movedR0   = std::max(0, r0 + offset.frame());
1225       int movedC0   = std::max(firstCol, c0 + offset.layer());
1226       int diffFrame = movedR0 - r0;
1227       int diffLayer = movedC0 - c0;
1228       cellSel->selectCells(r0 + diffFrame, c0 + diffLayer, r1 + diffFrame,
1229                            c1 + diffLayer);
1230       TApp::instance()->getCurrentSelection()->notifySelectionChanged();
1231     }
1232   }
1233 
1234   if (shift) {
1235     now = now + shift * stride;
1236     now.ensureValid();
1237     if (now.layer() < firstCol) now.setLayer(firstCol);
1238     setCurrentRow(now.frame());
1239     setCurrentColumn(now.layer());
1240     return;
1241   }
1242 
1243   switch (int key = event->key()) {
1244   case Qt::Key_Control:
1245     // display the upper-directional smart tab only when the ctrl key is pressed
1246     m_cellArea->onControlPressed(true);
1247     m_columnArea->onControlPressed(true);
1248     m_layerFooterPanel->onControlPressed(true);
1249     break;
1250 
1251   default: {
1252     QRect visibleRect   = m_cellArea->visibleRegion().boundingRect();
1253     int visibleRowCount = visibleRect.height() / orientation()->cellHeight();
1254 
1255     switch (key) {
1256     case Qt::Key_PageUp:
1257       locals.scrollVertTo(
1258           visibleRect.top() - visibleRowCount * orientation()->cellHeight(),
1259           visibleRect);
1260       break;
1261     case Qt::Key_PageDown:
1262       locals.scrollVertTo(
1263           visibleRect.bottom() + visibleRowCount * orientation()->cellHeight(),
1264           visibleRect);
1265       break;
1266     case Qt::Key_Home:
1267       if (orientation()->isVerticalTimeline())
1268         locals.scrollVertTo(0, visibleRect);
1269       else
1270         locals.scrollHorizTo(0, visibleRect);
1271 
1272       break;
1273     case Qt::Key_End:
1274       if (orientation()->isVerticalTimeline())
1275         locals.scrollVertTo((frameCount + 1) * orientation()->cellHeight(),
1276                             visibleRect);
1277       else {
1278         int x = (((frameCount + 1) * orientation()->cellWidth()) *
1279                  getFrameZoomFactor()) /
1280                 100;
1281         locals.scrollHorizTo(x, visibleRect);
1282       }
1283       break;
1284     }
1285     break;
1286   }
1287   }
1288 }
1289 
1290 //-----------------------------------------------------------------------------
1291 // display the upper-directional smart tab only when the ctrl key is pressed
keyReleaseEvent(QKeyEvent * event)1292 void XsheetViewer::keyReleaseEvent(QKeyEvent *event) {
1293   if (event->key() == Qt::Key_Control) {
1294     m_cellArea->onControlPressed(false);
1295     m_columnArea->onControlPressed(false);
1296     m_layerFooterPanel->onControlPressed(false);
1297   }
1298 }
1299 
enterEvent(QEvent *)1300 void XsheetViewer::enterEvent(QEvent *) {
1301   m_cellArea->onControlPressed(false);
1302   m_columnArea->onControlPressed(false);
1303   TApp *app = TApp::instance();
1304   app->setCurrentXsheetViewer(this);
1305 }
1306 
1307 //-----------------------------------------------------------------------------
1308 /*! scroll the cell area to make a cell at (row,col) visible
1309  */
scrollTo(int row,int col)1310 void XsheetViewer::scrollTo(int row, int col) {
1311   QRect visibleRect = m_cellArea->visibleRegion().boundingRect();
1312   QPoint topLeft    = positionToXY(CellPosition(row, col));
1313   QRect cellRect(
1314       topLeft, QSize(orientation()->cellWidth(), orientation()->cellHeight()));
1315 
1316   int deltaX = 0;
1317   int deltaY = 0;
1318 
1319   if (cellRect.left() < visibleRect.left())
1320     deltaX = cellRect.left() - visibleRect.left();
1321   else if (cellRect.right() > visibleRect.right())
1322     deltaX = cellRect.left() - visibleRect.left();
1323 
1324   if (cellRect.top() < visibleRect.top())
1325     deltaY = cellRect.top() - visibleRect.top();
1326   else if (cellRect.bottom() > visibleRect.bottom())
1327     deltaY = cellRect.bottom() - visibleRect.bottom();
1328 
1329   if (deltaX != 0 || deltaY != 0) {
1330     scroll(QPoint(deltaX, deltaY));
1331   }
1332 }
1333 
1334 //-----------------------------------------------------------------------------
1335 
onSceneSwitched()1336 void XsheetViewer::onSceneSwitched() {
1337   refreshContentSize(0, 0);
1338   updateAreeSize();
1339   updateAllAree();
1340   clearNoteWidgets();
1341   m_noteArea->updateButtons();
1342 }
1343 
1344 //-----------------------------------------------------------------------------
1345 
onXsheetChanged()1346 void XsheetViewer::onXsheetChanged() {
1347   refreshContentSize(0, 0);
1348   updateAllAree();
1349 }
1350 
1351 //-----------------------------------------------------------------------------
1352 
onPreferenceChanged(const QString & prefName)1353 void XsheetViewer::onPreferenceChanged(const QString &prefName) {
1354   if (prefName == "XSheetToolbar") {
1355     positionSections();
1356     refreshContentSize(0, 0);
1357   } else if (prefName == "XsheetCamera") {
1358     refreshContentSize(0, 0);
1359   }
1360 }
1361 
1362 //-----------------------------------------------------------------------------
1363 
onCurrentFrameSwitched()1364 void XsheetViewer::onCurrentFrameSwitched() {
1365   int row           = TApp::instance()->getCurrentFrame()->getFrame();
1366   QRect visibleRect = m_cellArea->visibleRegion().boundingRect();
1367   if (visibleRect.isEmpty()) {
1368     m_isCurrentFrameSwitched = true;
1369     return;
1370   }
1371   m_isCurrentFrameSwitched = false;
1372   scrollToRow(row);
1373 }
1374 
1375 //-----------------------------------------------------------------------------
1376 
onPlayingStatusChanged()1377 void XsheetViewer::onPlayingStatusChanged() {
1378   if (!Preferences::instance()->isXsheetAutopanEnabled())
1379     onCurrentFrameSwitched();
1380 }
1381 
1382 //-----------------------------------------------------------------------------
1383 
onCurrentColumnSwitched()1384 void XsheetViewer::onCurrentColumnSwitched() {
1385   int col           = TApp::instance()->getCurrentColumn()->getColumnIndex();
1386   QRect visibleRect = m_columnArea->visibleRegion().boundingRect();
1387   if (visibleRect.isEmpty()) {
1388     m_isCurrentColumnSwitched = true;
1389     return;
1390   }
1391   m_isCurrentColumnSwitched = false;
1392   scrollToColumn(col);
1393 }
1394 
1395 //-----------------------------------------------------------------------------
1396 
scrollToColumn(int col)1397 void XsheetViewer::scrollToColumn(int col) {
1398   int colNext = col + (m_orientation->isVerticalTimeline() ? 1 : -1);
1399   if (colNext < 0) colNext = -1;
1400   int x0 = columnToLayerAxis(col);
1401   int x1 = columnToLayerAxis(colNext);
1402 
1403   if (orientation()->isVerticalTimeline())
1404     scrollToHorizontalRange(x0, x1);
1405   else {
1406     if (colNext == col) x1 += m_orientation->cellHeight();
1407 
1408     scrollToVerticalRange(x0, x1);
1409   }
1410 }
1411 
1412 //-----------------------------------------------------------------------------
1413 
scrollToHorizontalRange(int x0,int x1)1414 void XsheetViewer::scrollToHorizontalRange(int x0, int x1) {
1415   QRect visibleRect = m_cellArea->visibleRegion().boundingRect();
1416   if (visibleRect.isEmpty()) return;
1417   int visibleLeft  = visibleRect.left();
1418   int visibleRight = visibleRect.right();
1419 
1420   if (visibleLeft > x0) {  // If they are out of left visible region
1421     int deltaX = x0 - visibleLeft;
1422     if (!TApp::instance()->getCurrentFrame()->isPlaying() ||
1423         Preferences::instance()->isXsheetAutopanEnabled()) {
1424       scroll(QPoint(deltaX, 0));
1425       return;
1426     }
1427   }
1428   if (visibleRight < x1) {  // If they are out of right visible region
1429     int deltaX = x1 + 2 - visibleRight;
1430     if (!TApp::instance()->getCurrentFrame()->isPlaying() ||
1431         Preferences::instance()->isXsheetAutopanEnabled()) {
1432       scroll(QPoint(deltaX, 0));
1433       return;
1434     }
1435   }
1436   if (orientation()->isVerticalTimeline())
1437     updateCellColumnAree();
1438   else
1439     updateCellRowAree();
1440 }
1441 
1442 //-----------------------------------------------------------------------------
1443 
scrollToRow(int row)1444 void XsheetViewer::scrollToRow(int row) {
1445   int y0 = rowToFrameAxis(row);
1446   int y1 = rowToFrameAxis(row + 1);
1447 
1448   if (orientation()->isVerticalTimeline())
1449     scrollToVerticalRange(y0, y1);
1450   else
1451     scrollToHorizontalRange(y0, y1);
1452 }
1453 
1454 //-----------------------------------------------------------------------------
1455 
scrollToVerticalRange(int y0,int y1)1456 void XsheetViewer::scrollToVerticalRange(int y0, int y1) {
1457   int yMin          = std::min(y0, y1);
1458   int yMax          = std::max(y0, y1);
1459   QRect visibleRect = m_cellArea->visibleRegion().boundingRect();
1460   if (visibleRect.isEmpty()) return;
1461   int visibleTop    = visibleRect.top();
1462   int visibleBottom = visibleRect.bottom();
1463 
1464   if (visibleTop > yMin) {  // If they are out of top visible region
1465     int deltaY = yMin - visibleTop;
1466     if (!TApp::instance()->getCurrentFrame()->isPlaying() ||
1467         Preferences::instance()->isXsheetAutopanEnabled()) {
1468       scroll(QPoint(0, deltaY));
1469       return;
1470     }
1471   }
1472 
1473   if (visibleBottom < yMax) {  // If they are out of bottom visible region
1474     int deltaY = yMax + 2 - visibleBottom;
1475     if (!TApp::instance()->getCurrentFrame()->isPlaying() ||
1476         Preferences::instance()->isXsheetAutopanEnabled()) {
1477       scroll(QPoint(0, deltaY));
1478       return;
1479     }
1480   }
1481   if (orientation()->isVerticalTimeline())
1482     updateCellRowAree();
1483   else
1484     updateCellColumnAree();
1485 }
1486 
1487 //-----------------------------------------------------------------------------
1488 
onSelectionSwitched(TSelection * oldSelection,TSelection * newSelection)1489 void XsheetViewer::onSelectionSwitched(TSelection *oldSelection,
1490                                        TSelection *newSelection) {
1491   if ((TSelection *)getCellSelection() == oldSelection) {
1492     m_cellArea->update(m_cellArea->visibleRegion());
1493     m_rowArea->update(m_rowArea->visibleRegion());
1494     changeWindowTitle();
1495   } else if ((TSelection *)m_columnSelection == oldSelection)
1496     m_columnArea->update(m_columnArea->visibleRegion());
1497 }
1498 
1499 //-----------------------------------------------------------------------------
1500 /*! update display of the cell selection range in title bar
1501  */
onSelectionChanged(TSelection * selection)1502 void XsheetViewer::onSelectionChanged(TSelection *selection) {
1503   if ((TSelection *)getCellSelection() == selection) {
1504     changeWindowTitle();
1505     if (Preferences::instance()->isInputCellsWithoutDoubleClickingEnabled()) {
1506       TCellSelection *cellSel = getCellSelection();
1507       if (cellSel->isEmpty())
1508         m_cellArea->hideRenameField();
1509       else
1510         m_cellArea->showRenameField(
1511             cellSel->getSelectedCells().m_r0, cellSel->getSelectedCells().m_c0,
1512             cellSel->getSelectedCells().getColCount() > 1);
1513     }
1514   }
1515 }
1516 
1517 //-----------------------------------------------------------------------------
1518 
updateAllAree(bool isDragging)1519 void XsheetViewer::updateAllAree(bool isDragging) {
1520   m_cellArea->update(m_cellArea->visibleRegion());
1521   if (!isDragging) {
1522     m_rowArea->update(m_rowArea->visibleRegion());
1523     m_columnArea->update(m_columnArea->visibleRegion());
1524   }
1525   m_toolbar->update(m_toolbar->visibleRegion());
1526 }
1527 
1528 //-----------------------------------------------------------------------------
1529 
updateColumnArea()1530 void XsheetViewer::updateColumnArea() {
1531   m_columnArea->update(m_columnArea->visibleRegion());
1532 }
1533 
1534 //-----------------------------------------------------------------------------
1535 
updateCellColumnAree()1536 void XsheetViewer::updateCellColumnAree() {
1537   m_columnArea->update(m_columnArea->visibleRegion());
1538   m_cellArea->update(m_cellArea->visibleRegion());
1539 }
1540 
1541 //-----------------------------------------------------------------------------
1542 
updateCellRowAree()1543 void XsheetViewer::updateCellRowAree() {
1544   m_rowArea->update(m_rowArea->visibleRegion());
1545   m_cellArea->update(m_cellArea->visibleRegion());
1546 }
1547 
1548 //-----------------------------------------------------------------------------
1549 
onScrubStopped()1550 void XsheetViewer::onScrubStopped() {
1551   resetScrubHighlight();
1552   updateCells();
1553 }
1554 
1555 //-----------------------------------------------------------------------------
1556 
discardNoteWidget()1557 void XsheetViewer::discardNoteWidget() {
1558   if (m_currentNoteIndex == -1) return;
1559   TXshNoteSet *notes = getXsheet()->getNotes();
1560   int i;
1561   for (i = m_currentNoteIndex + 1; i < m_noteWidgets.size(); i++) {
1562     XsheetGUI::NoteWidget *w = m_noteWidgets.at(i);
1563     int index                = w->getNoteIndex();
1564     w->setNoteIndex(index - 1);
1565     w->update();
1566   }
1567   delete m_noteWidgets.at(m_currentNoteIndex);
1568   m_noteWidgets.removeAt(m_currentNoteIndex);
1569   m_noteArea->updateButtons();
1570   updateCells();
1571 }
1572 
1573 //-----------------------------------------------------------------------------
1574 
getNotesWidget() const1575 QList<XsheetGUI::NoteWidget *> XsheetViewer::getNotesWidget() const {
1576   return m_noteWidgets;
1577 }
1578 
1579 //-----------------------------------------------------------------------------
1580 
addNoteWidget(XsheetGUI::NoteWidget * w)1581 void XsheetViewer::addNoteWidget(XsheetGUI::NoteWidget *w) {
1582   m_noteWidgets.push_back(w);
1583   m_noteArea->updateButtons();
1584 }
1585 
1586 //-----------------------------------------------------------------------------
1587 
getCurrentNoteIndex() const1588 int XsheetViewer::getCurrentNoteIndex() const { return m_currentNoteIndex; }
1589 
1590 //-----------------------------------------------------------------------------
1591 
setCurrentNoteIndex(int currentNoteIndex)1592 void XsheetViewer::setCurrentNoteIndex(int currentNoteIndex) {
1593   m_currentNoteIndex = currentNoteIndex;
1594   m_noteArea->updateButtons();
1595 
1596   if (currentNoteIndex < 0) return;
1597 
1598   TXshNoteSet *notes = getXsheet()->getNotes();
1599   int row            = notes->getNoteRow(currentNoteIndex);
1600   int col            = notes->getNoteCol(currentNoteIndex);
1601   TPointD pos        = notes->getNotePos(currentNoteIndex);
1602 
1603   QPoint topLeft = positionToXY(CellPosition(row, col)) +
1604                    QPoint(pos.x, pos.y);  // actually xy
1605   QSize size(XsheetGUI::NoteWidth, XsheetGUI::NoteHeight);
1606   QRect noteRect(topLeft, size);
1607   scrollToHorizontalRange(noteRect.left(), noteRect.right());
1608   scrollToVerticalRange(noteRect.top(), noteRect.bottom());
1609 }
1610 
1611 //-----------------------------------------------------------------------------
1612 
resetXsheetNotes()1613 void XsheetViewer::resetXsheetNotes() { m_noteArea->updateButtons(); }
1614 
1615 //-----------------------------------------------------------------------------
1616 
updateNoteWidgets()1617 void XsheetViewer::updateNoteWidgets() {
1618   int i;
1619   for (i = 0; i < m_noteWidgets.size(); i++) m_noteWidgets.at(i)->update();
1620   m_noteArea->updatePopup();
1621   updateCells();
1622 }
1623 
1624 //-----------------------------------------------------------------------------
1625 
clearNoteWidgets()1626 void XsheetViewer::clearNoteWidgets() {
1627   int i;
1628   for (i = 0; i < m_noteWidgets.size(); i++) delete m_noteWidgets.at(i);
1629   m_noteWidgets.clear();
1630 }
1631 
1632 //-----------------------------------------------------------------------------
1633 
changeWindowTitle()1634 void XsheetViewer::changeWindowTitle() {
1635   TApp *app         = TApp::instance();
1636   ToonzScene *scene = app->getCurrentScene()->getScene();
1637   if (!scene || !app->getCurrentFrame()->isEditingScene()) return;
1638   TProject *project = scene->getProject();
1639   QString sceneName = QString::fromStdWString(scene->getSceneName());
1640   if (sceneName.isEmpty()) sceneName = tr("Untitled");
1641   if (app->getCurrentScene()->getDirtyFlag()) sceneName += QString("*");
1642   QString name   = tr("Scene: ") + sceneName;
1643   int frameCount = scene->getFrameCount();
1644   name           = name + "   ::   " + tr(std::to_string(frameCount).c_str()) +
1645          (frameCount == 1 ? tr(" Frame") : tr(" Frames"));
1646 
1647   // subXsheet or not
1648   ChildStack *childStack = scene->getChildStack();
1649   if (childStack && childStack->getAncestorCount() > 0) {
1650     name += tr("  (Sub)");
1651   }
1652   // current level name
1653   TXshLevel *level = app->getCurrentLevel()->getLevel();
1654   if (level) {
1655     QString levelName = QString::fromStdWString(level->getName());
1656     name += tr("  Level: ") + levelName;
1657   }
1658   // cell selection range
1659   if ((TSelection *)getCellSelection() ==
1660           app->getCurrentSelection()->getSelection() &&
1661       !getCellSelection()->isEmpty()) {
1662     int r0, r1, c0, c1;
1663     getCellSelection()->getSelectedCells(r0, c0, r1, c1);
1664     name += tr("   Selected: ") + QString::number(r1 - r0 + 1) +
1665             ((r1 - r0 + 1 == 1) ? tr(" frame : ") : tr(" frames * ")) +
1666             QString::number(c1 - c0 + 1) +
1667             ((c1 - c0 + 1 == 1) ? tr(" column") : tr(" columns"));
1668   }
1669 
1670   parentWidget()->setWindowTitle(name);
1671 }
1672 
1673 //-----------------------------------------------------------------------------
1674 /*! convert the last one digit of the frame number to alphabet
1675         Ex.  12 -> 1B    21 -> 2A   30 -> 3
1676  */
getFrameNumberWithLetters(int frame)1677 QString XsheetViewer::getFrameNumberWithLetters(int frame) {
1678   int letterNum = frame % 10;
1679   QChar letter;
1680 
1681   switch (letterNum) {
1682   case 0:
1683     letter = QChar();
1684     break;
1685   case 1:
1686     letter = 'A';
1687     break;
1688   case 2:
1689     letter = 'B';
1690     break;
1691   case 3:
1692     letter = 'C';
1693     break;
1694   case 4:
1695     letter = 'D';
1696     break;
1697   case 5:
1698     letter = 'E';
1699     break;
1700   case 6:
1701     letter = 'F';
1702     break;
1703   case 7:
1704     letter = 'G';
1705     break;
1706   case 8:
1707     letter = 'H';
1708     break;
1709   case 9:
1710     letter = 'I';
1711     break;
1712   default:
1713     letter = QChar();
1714     break;
1715   }
1716 
1717   QString number;
1718   if (frame >= 10) {
1719     number = QString::number(frame);
1720     number.chop(1);
1721   } else
1722     number = "0";
1723 
1724   return (QChar(letter).isNull()) ? number : number.append(letter);
1725 }
1726 //-----------------------------------------------------------------------------
1727 
setFrameDisplayStyle(FrameDisplayStyle style)1728 void XsheetViewer::setFrameDisplayStyle(FrameDisplayStyle style) {
1729   m_frameDisplayStyle              = style;
1730   FrameDisplayStyleInXsheetRowArea = (int)style;
1731 }
1732 
1733 //-----------------------------------------------------------------------------
1734 
save(QSettings & settings) const1735 void XsheetViewer::save(QSettings &settings) const {
1736   settings.setValue("orientation", orientation()->name());
1737   settings.setValue("frameZoomFactor", m_frameZoomFactor);
1738 }
load(QSettings & settings)1739 void XsheetViewer::load(QSettings &settings) {
1740   QVariant zoomFactor = settings.value("frameZoomFactor");
1741   QVariant name       = settings.value("orientation");
1742 
1743   if (zoomFactor.canConvert(QVariant::Int)) {
1744     m_frameZoomFactor = zoomFactor.toInt();
1745     m_layerFooterPanel->setZoomSliderValue(m_frameZoomFactor);
1746   }
1747 
1748   if (name.canConvert(QVariant::String)) {
1749     m_orientation = Orientations::byName(name.toString());
1750     emit orientationChanged(orientation());
1751   }
1752 }
1753 
1754 //-----------------------------------------------------------------------------
1755 /*
1756 TPanel *createXsheetViewer(QWidget *parent)
1757 {
1758   TPanel *panel = new TPanel(parent);
1759   panel->setPanelType("Xsheet");
1760   panel->setWidget(new XsheetViewer(panel));
1761   return panel;
1762 }
1763 */
1764 
1765 //----------------------------------------------------------------
getFrameZoomFactor() const1766 int XsheetViewer::getFrameZoomFactor() const {
1767   if (orientation()->isVerticalTimeline()) return 100;
1768 
1769   return m_frameZoomFactor;
1770 }
1771 
getFrameZoomAdjustment()1772 int XsheetViewer::getFrameZoomAdjustment() {
1773   if (orientation()->isVerticalTimeline()) return 0;
1774 
1775   QRect frameRect = orientation()->rect(PredefinedRect::FRAME_HEADER);
1776   int adj         = frameRect.width() -
1777             ((frameRect.width() * getFrameZoomFactor()) / 100) - 1;
1778 
1779   return std::max(0, adj);
1780 }
1781 
zoomOnFrame(int frame,int factor)1782 void XsheetViewer::zoomOnFrame(int frame, int factor) {
1783   QPoint xyOrig = positionToXY(CellPosition(frame, -1));
1784 
1785   m_frameZoomFactor = factor;
1786   m_layerFooterPanel->setZoomSliderValue(m_frameZoomFactor);
1787 
1788   QPoint xyNew = positionToXY(CellPosition(frame, -1));
1789 
1790   int viewShift = xyNew.x() - xyOrig.x();
1791 
1792   scroll(QPoint(viewShift, 0));
1793 
1794   TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
1795   m_rowArea->update();
1796 }
1797 
getSelectedColumnTextColor() const1798 QColor XsheetViewer::getSelectedColumnTextColor() const {
1799   // get colors
1800   TPixel currentColumnPixel;
1801   Preferences::instance()->getCurrentColumnData(currentColumnPixel);
1802   QColor currentColumnColor((int)currentColumnPixel.r,
1803                             (int)currentColumnPixel.g,
1804                             (int)currentColumnPixel.b, 255);
1805   return currentColumnColor;
1806 }
1807 
1808 //=============================================================================
1809 // XSheetViewerCommand
1810 //-----------------------------------------------------------------------------
1811 
1812 OpenFloatingPanel openXsheetViewerCommand(MI_OpenXshView, "Xsheet",
1813                                           QObject::tr("Xsheet"));
1814 
1815 OpenFloatingPanel openTimelineViewerCommand(MI_OpenTimelineView, "Timeline",
1816                                             QObject::tr("Timeline"));
1817