1 
2 #include "xshcolumnviewer.h"
3 
4 // Tnz6 includes
5 #include "xsheetviewer.h"
6 #include "tapp.h"
7 #include "menubarcommandids.h"
8 #include "columnselection.h"
9 #include "xsheetdragtool.h"
10 
11 // TnzTools includes
12 #include "tools/toolhandle.h"
13 #include "tools/toolcommandids.h"
14 
15 // TnzQt includes
16 #include "toonzqt/tselectionhandle.h"
17 #include "toonzqt/gutil.h"
18 #include "toonzqt/icongenerator.h"
19 #include "toonzqt/intfield.h"
20 
21 // TnzLib includes
22 #include "toonz/txshcolumn.h"
23 #include "toonz/tscenehandle.h"
24 #include "toonz/txsheethandle.h"
25 #include "toonz/txshlevelhandle.h"
26 #include "toonz/tobjecthandle.h"
27 #include "toonz/stage2.h"
28 #include "toonz/txshpalettecolumn.h"
29 #include "toonz/txsheet.h"
30 #include "toonz/toonzscene.h"
31 #include "toonz/txshcell.h"
32 #include "toonz/tstageobject.h"
33 #include "toonz/tstageobjecttree.h"
34 #include "toonz/sceneproperties.h"
35 #include "toonz/txshzeraryfxcolumn.h"
36 #include "toonz/tcolumnfx.h"
37 #include "toonz/txshsoundcolumn.h"
38 #include "toonz/txshsimplelevel.h"
39 #include "toonz/columnfan.h"
40 #include "toonz/tstageobjectcmd.h"
41 #include "toonz/fxcommand.h"
42 #include "toonz/txshleveltypes.h"
43 #include "toonz/levelproperties.h"
44 #include "toonz/preferences.h"
45 #include "toonz/childstack.h"
46 #include "toonz/txshlevelcolumn.h"
47 #include "toonz/txshmeshcolumn.h"
48 #include "toonz/tfxhandle.h"
49 #include "toonz/tcamera.h"
50 #include "toonz/tcolumnhandle.h"
51 
52 // TnzCore includes
53 #include "tconvert.h"
54 
55 #include <QApplication>
56 #include <QMainWindow>
57 #include <QPainter>
58 #include <QMouseEvent>
59 #include <QMenu>
60 #include <QToolTip>
61 #include <QTimer>
62 #include <QLabel>
63 #include <QComboBox>
64 #include <QPushButton>
65 #include <QDesktopWidget>
66 
67 #include <QBitmap>
68 //=============================================================================
69 
70 namespace {
getLevels(TXshColumn * column)71 const QSet<TXshSimpleLevel *> getLevels(TXshColumn *column) {
72   QSet<TXshSimpleLevel *> levels;
73   TXshCellColumn *cellColumn = column->getCellColumn();
74   if (cellColumn) {
75     int i, r0, r1;
76     cellColumn->getRange(r0, r1);
77     for (i = r0; i <= r1; i++) {
78       TXshCell cell       = cellColumn->getCell(i);
79       TXshSimpleLevel *sl = cell.getSimpleLevel();
80       if (sl) levels.insert(sl);
81     }
82   }
83   return levels;
84 }
85 
containsRasterLevel(TColumnSelection * selection)86 bool containsRasterLevel(TColumnSelection *selection) {
87   if (!selection || selection->isEmpty()) return false;
88   std::set<int> indexes = selection->getIndices();
89   TXsheet *xsh          = TApp::instance()->getCurrentXsheet()->getXsheet();
90   for (auto const &e : indexes) {
91     TXshColumn *col = xsh->getColumn(e);
92     if (!col || col->getColumnType() != TXshColumn::eLevelType) continue;
93 
94     TXshCellColumn *cellCol = col->getCellColumn();
95     if (!cellCol) continue;
96 
97     int i;
98     for (i = 0; i < cellCol->getMaxFrame() + 1; i++) {
99       TXshCell cell = cellCol->getCell(i);
100       if (cell.isEmpty()) continue;
101       TXshSimpleLevel *level = cell.getSimpleLevel();
102       if (!level || level->getChildLevel() ||
103           level->getProperties()->getDirtyFlag())
104         continue;
105       int type = level->getType();
106       if (type == OVL_XSHLEVEL || type == TZP_XSHLEVEL) return true;
107     }
108   }
109   return false;
110 }
111 
getColorChipIcon(TPixel32 color)112 const QIcon getColorChipIcon(TPixel32 color) {
113   QColor qCol((int)color.r, (int)color.g, (int)color.b, (int)color.m);
114   QPixmap pixmap(12, 12);
115   pixmap.fill(qCol);
116   return QIcon(pixmap);
117 }
118 
containsVectorLevel(int col)119 bool containsVectorLevel(int col) {
120   TXshColumn *column =
121       TApp::instance()->getCurrentXsheet()->getXsheet()->getColumn(col);
122   TXshColumn::ColumnType type = column->getColumnType();
123   if (type != TXshColumn::eLevelType) return false;
124 
125   const QSet<TXshSimpleLevel *> levels = getLevels(column);
126   QSet<TXshSimpleLevel *>::const_iterator it2;
127   bool isVector = false;
128   for (it2 = levels.begin(); it2 != levels.end(); it2++) {
129     TXshSimpleLevel *sl = *it2;
130     int type            = sl->getType();
131     if (type == PLI_XSHLEVEL) {
132       isVector = true;
133       return true;
134     }
135   }
136   return false;
137 }
138 
139 bool isCtrlPressed = false;
140 }  // namespace
141 
142 //=============================================================================
143 // ColumnMaskUndo
144 //-----------------------------------------------------------------------------
145 class ColumnMaskUndo final : public TUndo {
146   int m_col;
147   bool m_isMask;
148   std::string m_name;
149 
150 public:
ColumnMaskUndo(int column,bool isMask,std::string name)151   ColumnMaskUndo(int column, bool isMask, std::string name)
152       : m_col(column), m_isMask(isMask), m_name(name) {}
~ColumnMaskUndo()153   ~ColumnMaskUndo() {}
154 
undo() const155   void undo() const override {
156     TXshColumn *column =
157         TApp::instance()->getCurrentXsheet()->getXsheet()->getColumn(m_col);
158     TXshColumn::ColumnType type = column->getColumnType();
159     if (type != TXshColumn::eLevelType) return;
160 
161     if (containsVectorLevel(m_col)) {
162       column->setIsMask(m_isMask);
163       TApp::instance()->getCurrentScene()->notifySceneChanged();
164       TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
165       TApp::instance()->getCurrentScene()->setDirtyFlag(true);
166     }
167   }
168 
redo() const169   void redo() const override {
170     TXshColumn *column =
171         TApp::instance()->getCurrentXsheet()->getXsheet()->getColumn(m_col);
172     TXshColumn::ColumnType type = column->getColumnType();
173     if (type != TXshColumn::eLevelType) return;
174 
175     if (containsVectorLevel(m_col)) {
176       column->setIsMask(!m_isMask);
177       TApp::instance()->getCurrentScene()->notifySceneChanged();
178       TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
179       TApp::instance()->getCurrentScene()->setDirtyFlag(true);
180     }
181   }
182 
getSize() const183   int getSize() const override { return sizeof(*this); }
184 
getHistoryString()185   QString getHistoryString() override {
186     QString str = QObject::tr("Toggle vector column as mask. ");
187     return str;
188   }
getHistoryType()189   int getHistoryType() override { return HistoryType::Xsheet; }
190 };
191 
192 //-----------------------------------------------------------------------------
193 
194 namespace XsheetGUI {
195 
196 //-----------------------------------------------------------------------------
197 
getVolumeCursorRect(QRect & out,double volume,const QPoint & origin)198 static void getVolumeCursorRect(QRect &out, double volume,
199                                 const QPoint &origin) {
200   int ly = 60;
201   int v  = tcrop(0, ly, (int)(volume * ly));
202   out.setX(origin.x() + 11);
203   out.setY(origin.y() + 60 - v);
204   out.setWidth(8);
205   out.setHeight(8);
206 }
207 
208 //=============================================================================
209 // MotionPathMenu
210 //-----------------------------------------------------------------------------
211 
212 #if QT_VERSION >= 0x050500
MotionPathMenu(QWidget * parent,Qt::WindowFlags flags)213 MotionPathMenu::MotionPathMenu(QWidget *parent, Qt::WindowFlags flags)
214 #else
215 MotionPathMenu::MotionPathMenu(QWidget *parent, Qt::WFlags flags)
216 #endif
217     : QWidget(parent, flags)
218     , m_mDeleteRect(QRect(0, 0, ColumnWidth - 13, RowHeight))
219     , m_mNormalRect(QRect(0, RowHeight, ColumnWidth - 13, RowHeight))
220     , m_mRotateRect(QRect(0, RowHeight * 2, ColumnWidth - 13, RowHeight))
221     , m_pos(QPoint()) {
222   setMouseTracking(true);
223   setFixedSize(ColumnWidth - 12, 3 * RowHeight);
224   setWindowFlags(Qt::FramelessWindowHint);
225 }
226 
227 //-----------------------------------------------------------------------------
228 
~MotionPathMenu()229 MotionPathMenu::~MotionPathMenu() {}
230 
231 //-----------------------------------------------------------------------------
232 
paintEvent(QPaintEvent *)233 void MotionPathMenu::paintEvent(QPaintEvent *) {
234   QPainter p(this);
235 
236   static QPixmap motionPixmap = QPixmap(":Resources/motionpath.svg");
237   static QPixmap motionDeletePixmap =
238       QPixmap(":Resources/motionpath_delete.svg");
239   static QPixmap motionRotatePixmap = QPixmap(":Resources/motionpath_rot.svg");
240 
241   QColor overColor = QColor(49, 106, 197);
242 
243   p.fillRect(m_mDeleteRect,
244              QBrush((m_mDeleteRect.contains(m_pos)) ? overColor : grey225));
245   p.drawPixmap(m_mDeleteRect, motionDeletePixmap);
246 
247   p.fillRect(m_mNormalRect,
248              QBrush((m_mNormalRect.contains(m_pos)) ? overColor : grey225));
249   p.drawPixmap(m_mNormalRect, motionPixmap);
250 
251   p.fillRect(m_mRotateRect,
252              QBrush((m_mRotateRect.contains(m_pos)) ? overColor : grey225));
253   p.drawPixmap(m_mRotateRect, motionRotatePixmap);
254 }
255 
256 //-----------------------------------------------------------------------------
257 
mousePressEvent(QMouseEvent * event)258 void MotionPathMenu::mousePressEvent(QMouseEvent *event) {
259   m_pos                   = event->pos();
260   TStageObjectId objectId = TApp::instance()->getCurrentObject()->getObjectId();
261   TStageObject *pegbar =
262       TApp::instance()->getCurrentXsheet()->getXsheet()->getStageObject(
263           objectId);
264 
265   if (m_mDeleteRect.contains(m_pos))
266     pegbar->setStatus(TStageObject::XY);
267   else if (m_mNormalRect.contains(m_pos)) {
268     pegbar->setStatus(TStageObject::PATH);
269     TApp::instance()->getCurrentObject()->setIsSpline(true);
270   } else if (m_mRotateRect.contains(m_pos)) {
271     pegbar->setStatus(TStageObject::PATH_AIM);
272     TApp::instance()->getCurrentObject()->setIsSpline(true);
273   }
274   TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
275   hide();
276 }
277 
278 //-----------------------------------------------------------------------------
279 
mouseMoveEvent(QMouseEvent * event)280 void MotionPathMenu::mouseMoveEvent(QMouseEvent *event) {
281   m_pos = event->pos();
282   update();
283 }
284 
285 //-----------------------------------------------------------------------------
286 
mouseReleaseEvent(QMouseEvent * event)287 void MotionPathMenu::mouseReleaseEvent(QMouseEvent *event) {}
288 
289 //-----------------------------------------------------------------------------
290 
leaveEvent(QEvent * event)291 void MotionPathMenu::leaveEvent(QEvent *event) { hide(); }
292 
293 //=============================================================================
294 // ChangeObjectWidget
295 //-----------------------------------------------------------------------------
296 
ChangeObjectWidget(QWidget * parent)297 ChangeObjectWidget::ChangeObjectWidget(QWidget *parent)
298     : QListWidget(parent), m_width(40) {
299   setMouseTracking(true);
300   setObjectName("XshColumnChangeObjectWidget");
301   setAutoFillBackground(true);
302 }
303 
304 //-----------------------------------------------------------------------------
305 
~ChangeObjectWidget()306 ChangeObjectWidget::~ChangeObjectWidget() {}
307 
308 //-----------------------------------------------------------------------------
309 
show(const QPoint & pos)310 void ChangeObjectWidget::show(const QPoint &pos) {
311   refresh();
312   int itemNumber = count();
313   if (itemNumber > 10) {
314     itemNumber = 10;
315     m_width += 15;
316   }
317   setGeometry(pos.x(), pos.y(), m_width, itemNumber * 16 + 2);
318   QListWidget::show();
319   setFocus();
320   scrollToItem(currentItem());
321 }
322 
323 //-----------------------------------------------------------------------------
324 
setObjectHandle(TObjectHandle * objectHandle)325 void ChangeObjectWidget::setObjectHandle(TObjectHandle *objectHandle) {
326   m_objectHandle = objectHandle;
327 }
328 
329 //-----------------------------------------------------------------------------
330 
setXsheetHandle(TXsheetHandle * xsheetHandle)331 void ChangeObjectWidget::setXsheetHandle(TXsheetHandle *xsheetHandle) {
332   m_xsheetHandle = xsheetHandle;
333 }
334 
335 //-----------------------------------------------------------------------------
336 
mouseMoveEvent(QMouseEvent * event)337 void ChangeObjectWidget::mouseMoveEvent(QMouseEvent *event) {
338   QListWidgetItem *currentWidgetItem = itemAt(event->pos());
339   if (!currentWidgetItem) return;
340   clearSelection();
341   currentWidgetItem->setSelected(true);
342 }
343 
344 //-----------------------------------------------------------------------------
345 
focusOutEvent(QFocusEvent * e)346 void ChangeObjectWidget::focusOutEvent(QFocusEvent *e) {
347   if (!isVisible()) return;
348   hide();
349   parentWidget()->update();
350 }
351 
352 //-----------------------------------------------------------------------------
353 
selectCurrent(const QString & text)354 void ChangeObjectWidget::selectCurrent(const QString &text) {
355   QList<QListWidgetItem *> itemList = findItems(text, Qt::MatchExactly);
356   clearSelection();
357   if (itemList.size() < 1) return;
358   QListWidgetItem *currentWidgetItem = itemList.at(0);
359   setCurrentItem(currentWidgetItem);
360 }
361 
362 //=============================================================================
363 // ChangeObjectParent
364 //-----------------------------------------------------------------------------
365 
ChangeObjectParent(QWidget * parent)366 ChangeObjectParent::ChangeObjectParent(QWidget *parent)
367     : ChangeObjectWidget(parent) {
368   bool ret = connect(this, SIGNAL(currentTextChanged(const QString &)), this,
369                      SLOT(onTextChanged(const QString &)));
370   assert(ret);
371 }
372 
373 //-----------------------------------------------------------------------------
374 
~ChangeObjectParent()375 ChangeObjectParent::~ChangeObjectParent() {}
376 
377 //-----------------------------------------------------------------------------
378 
refresh()379 void ChangeObjectParent::refresh() {
380   clear();
381   assert(m_xsheetHandle);
382   assert(m_objectHandle);
383   TXsheet *xsh                   = m_xsheetHandle->getXsheet();
384   TStageObjectId currentObjectId = m_objectHandle->getObjectId();
385   TStageObjectId parentId = xsh->getStageObject(currentObjectId)->getParent();
386   TStageObjectTree *tree  = xsh->getStageObjectTree();
387   int objectCount         = tree->getStageObjectCount();
388   QString text;
389   QList<QString> pegbarList;
390   QList<QString> columnList;
391   QString theLongestTxt;
392   int i;
393   for (i = 0; i < objectCount; i++) {
394     TStageObjectId id = tree->getStageObject(i)->getId();
395     int index         = id.getIndex();
396     QString indexStr(std::to_string(id.getIndex() + 1).c_str());
397     QString newText;
398     if (id == parentId) {
399       if (parentId.isPegbar())
400         text = QString("Peg ") + indexStr;
401       else if (parentId.isColumn())
402         text = QString("Col ") + indexStr;
403     }
404     if (id == currentObjectId) continue;
405     if (id.isPegbar()) {
406       newText = QString("Peg ") + indexStr;
407       pegbarList.append(newText);
408     }
409     if (id.isColumn() && (!xsh->isColumnEmpty(index) || index < 2)) {
410       newText = QString("Col ") + indexStr;
411       columnList.append(newText);
412     }
413     if (newText.length() > theLongestTxt.length()) theLongestTxt = newText;
414   }
415   for (i = 0; i < columnList.size(); i++) addItem(columnList.at(i));
416   for (i = 0; i < pegbarList.size(); i++) addItem(pegbarList.at(i));
417 
418   QString fontName = Preferences::instance()->getInterfaceFont();
419   if (fontName == "") {
420 #ifdef _WIN32
421     fontName = "Arial";
422 #else
423     fontName = "Helvetica";
424 #endif
425   }
426   static QFont font(fontName, -1, QFont::Normal);
427   // set font size in pixel
428   font.setPixelSize(XSHEET_FONT_PX_SIZE);
429 
430   m_width = QFontMetrics(font).width(theLongestTxt) + 2;
431   selectCurrent(text);
432 }
433 
434 //-----------------------------------------------------------------------------
435 
onTextChanged(const QString & text)436 void ChangeObjectParent::onTextChanged(const QString &text) {
437   assert(m_xsheetHandle);
438   assert(m_objectHandle);
439   if (text.isEmpty()) {
440     hide();
441     return;
442   }
443   bool isPegbar = false;
444   if (text.startsWith("Peg")) isPegbar = true;
445   QString number = text;
446   number.remove(0, 4);
447   int index = number.toInt() - 1;
448   if (index < 0) {
449     hide();
450     return;
451   }
452   TStageObjectId currentObjectId = m_objectHandle->getObjectId();
453   TStageObjectId newStageObjectId;
454   if (isPegbar)
455     newStageObjectId = TStageObjectId::PegbarId(index);
456   else
457     newStageObjectId = TStageObjectId::ColumnId(index);
458 
459   if (newStageObjectId == currentObjectId) return;
460 
461   TStageObject *stageObject =
462       m_xsheetHandle->getXsheet()->getStageObject(currentObjectId);
463   TStageObjectCmd::setParent(currentObjectId, newStageObjectId, "B",
464                              m_xsheetHandle);
465 
466   hide();
467   m_objectHandle->notifyObjectIdChanged(false);
468   m_xsheetHandle->notifyXsheetChanged();
469 }
470 
471 //=============================================================================
472 // ChangeObjectHandle
473 //-----------------------------------------------------------------------------
474 
ChangeObjectHandle(QWidget * parent)475 ChangeObjectHandle::ChangeObjectHandle(QWidget *parent)
476     : ChangeObjectWidget(parent) {
477   bool ret = connect(this, SIGNAL(currentTextChanged(const QString &)), this,
478                      SLOT(onTextChanged(const QString &)));
479   assert(ret);
480 }
481 
482 //-----------------------------------------------------------------------------
483 
~ChangeObjectHandle()484 ChangeObjectHandle::~ChangeObjectHandle() {}
485 
486 //-----------------------------------------------------------------------------
487 
refresh()488 void ChangeObjectHandle::refresh() {
489   clear();
490   assert(m_xsheetHandle);
491   assert(m_objectHandle);
492   TXsheet *xsh = m_xsheetHandle->getXsheet();
493   assert(xsh);
494   TStageObjectId currentObjectId = m_objectHandle->getObjectId();
495   TStageObject *stageObject      = xsh->getStageObject(currentObjectId);
496   m_width                        = 28;
497 
498   int i;
499   QString str;
500   if (stageObject->getParent().isColumn()) {
501     for (i = 0; i < 20; i++) addItem(str.number(20 - i));
502   }
503   for (i = 0; i < 26; i++) addItem(QString(char('A' + i)));
504 
505   std::string handle = stageObject->getParentHandle();
506   if (handle[0] == 'H' && handle.length() > 1) handle = handle.substr(1);
507 
508   selectCurrent(QString::fromStdString(handle));
509 }
510 
511 //-----------------------------------------------------------------------------
512 
onTextChanged(const QString & text)513 void ChangeObjectHandle::onTextChanged(const QString &text) {
514   assert(m_xsheetHandle);
515   assert(m_objectHandle);
516   TStageObjectId currentObjectId = m_objectHandle->getObjectId();
517   QString handle                 = text;
518   if (text.toInt() != 0) handle = QString("H") + handle;
519   if (handle.isEmpty()) return;
520   std::vector<TStageObjectId> ids;
521   ids.push_back(currentObjectId);
522   TStageObjectCmd::setParentHandle(ids, handle.toStdString(), m_xsheetHandle);
523   hide();
524   m_objectHandle->notifyObjectIdChanged(false);
525   m_xsheetHandle->notifyXsheetChanged();
526 }
527 
528 //=============================================================================
529 // RenameColumnField
530 //-----------------------------------------------------------------------------
531 
RenameColumnField(QWidget * parent,XsheetViewer * viewer)532 RenameColumnField::RenameColumnField(QWidget *parent, XsheetViewer *viewer)
533     : QLineEdit(parent), m_col(-1) {
534   setFixedSize(20, 20);
535   connect(this, SIGNAL(returnPressed()), SLOT(renameColumn()));
536 }
537 
538 //-----------------------------------------------------------------------------
539 
show(const QRect & rect,int col)540 void RenameColumnField::show(const QRect &rect, int col) {
541   move(rect.topLeft());
542   setFixedSize(rect.size());
543   QString fontName = Preferences::instance()->getInterfaceFont();
544   if (fontName == "") {
545 #ifdef _WIN32
546     fontName = "Arial";
547 #else
548     fontName = "Helvetica";
549 #endif
550   }
551   static QFont font(fontName, -1, QFont::Normal);
552   font.setPixelSize(XSHEET_FONT_PX_SIZE);
553   setFont(font);
554   m_col = col;
555 
556   TXsheet *xsh    = m_xsheetHandle->getXsheet();
557   int cameraIndex = xsh->getCameraColumnIndex();
558   std::string name =
559       col >= 0 ? xsh->getStageObject(TStageObjectId::ColumnId(col))->getName()
560                : xsh->getStageObject(TStageObjectId::CameraId(cameraIndex))
561                      ->getName();
562   TXshColumn *column          = xsh->getColumn(col);
563   TXshZeraryFxColumn *zColumn = dynamic_cast<TXshZeraryFxColumn *>(column);
564   if (zColumn)
565     name = ::to_string(zColumn->getZeraryColumnFx()->getZeraryFx()->getName());
566   setText(QString(name.c_str()));
567   selectAll();
568 
569   QWidget::show();
570   raise();
571   setFocus();
572 }
573 
574 //-----------------------------------------------------------------------------
575 
renameColumn()576 void RenameColumnField::renameColumn() {
577   std::string newName     = text().toStdString();
578   int cameraIndex         = m_xsheetHandle->getXsheet()->getCameraColumnIndex();
579   TStageObjectId columnId = m_col >= 0 ? TStageObjectId::ColumnId(m_col)
580                                        : TStageObjectId::CameraId(cameraIndex);
581   TXshColumn *column =
582       m_xsheetHandle->getXsheet()->getColumn(columnId.getIndex());
583   TXshZeraryFxColumn *zColumn = dynamic_cast<TXshZeraryFxColumn *>(column);
584   if (zColumn)
585     TFxCommand::renameFx(zColumn->getZeraryColumnFx(), ::to_wstring(newName),
586                          m_xsheetHandle);
587   else
588     TStageObjectCmd::rename(columnId, newName, m_xsheetHandle);
589   m_xsheetHandle->notifyXsheetChanged();
590   m_col = -1;
591   setText("");
592   hide();
593 }
594 
595 //-----------------------------------------------------------------------------
596 
focusOutEvent(QFocusEvent * e)597 void RenameColumnField::focusOutEvent(QFocusEvent *e) {
598   std::wstring newName = text().toStdWString();
599   if (!newName.empty())
600     renameColumn();
601   else
602     hide();
603 
604   QLineEdit::focusOutEvent(e);
605 }
606 
607 //=============================================================================
608 // ColumnArea
609 //-----------------------------------------------------------------------------
610 
onControlPressed(bool pressed)611 void ColumnArea::onControlPressed(bool pressed) {
612   isCtrlPressed = pressed;
613   update();
614 }
615 
isControlPressed()616 const bool ColumnArea::isControlPressed() { return isCtrlPressed; }
617 
618 //-----------------------------------------------------------------------------
619 
DrawHeader(ColumnArea * nArea,QPainter & nP,int nCol)620 ColumnArea::DrawHeader::DrawHeader(ColumnArea *nArea, QPainter &nP, int nCol)
621     : area(nArea), p(nP), col(nCol) {
622   m_viewer = area->m_viewer;
623   o        = m_viewer->orientation();
624   app      = TApp::instance();
625   xsh      = m_viewer->getXsheet();
626   column   = xsh->getColumn(col);
627   isEmpty  = col >= 0 ? xsh->isColumnEmpty(col) : false;
628 
629   TStageObjectId currentColumnId = app->getCurrentObject()->getObjectId();
630 
631   // check if the column is current
632   isCurrent = false;
633   if (currentColumnId ==
634       TStageObjectId::CameraId(xsh->getCameraColumnIndex()))  // CAMERA
635     isCurrent = col == -1;
636   else
637     isCurrent = m_viewer->getCurrentColumn() == col;
638 
639   orig = m_viewer->positionToXY(CellPosition(0, std::max(col, -1)));
640 }
641 
prepare() const642 void ColumnArea::DrawHeader::prepare() const {
643   // Preparing painter
644   QString fontName = Preferences::instance()->getInterfaceFont();
645   if (fontName == "") {
646 #ifdef _WIN32
647     fontName = "Arial";
648 #else
649     fontName = "Helvetica";
650 #endif
651   }
652   static QFont font(fontName, -1, QFont::Normal);
653   font.setPixelSize(XSHEET_FONT_PX_SIZE);
654 
655   p.setFont(font);
656   p.setRenderHint(QPainter::SmoothPixmapTransform, true);
657 }
658 
659 //-----------------------------------------------------------------------------
sound()660 const QPixmap &ColumnArea::Pixmaps::sound() {
661   static QPixmap sound =
662       svgToPixmap(getIconThemePath("actions/30/sound_header.svg"));
663   return sound;
664 }
soundPlaying()665 const QPixmap &ColumnArea::Pixmaps::soundPlaying() {
666   static QPixmap soundPlaying =
667       svgToPixmap(getIconThemePath("actions/30/sound_header_on.svg"));
668   return soundPlaying;
669 }
670 
671 //-----------------------------------------------------------------------------
672 
levelColors(QColor & columnColor,QColor & dragColor) const673 void ColumnArea::DrawHeader::levelColors(QColor &columnColor,
674                                          QColor &dragColor) const {
675   if (col < 0) {
676     TStageObjectId cameraId =
677         m_viewer->getXsheet()->getStageObjectTree()->getCurrentCameraId();
678     bool isActive =
679         cameraId.getIndex() == m_viewer->getXsheet()->getCameraColumnIndex();
680     columnColor = isActive ? m_viewer->getActiveCameraColor()
681                            : m_viewer->getOtherCameraColor();
682     dragColor = isActive ? m_viewer->getActiveCameraColor()
683                          : m_viewer->getOtherCameraColor();
684     return;
685   }
686   enum { Normal, Reference, Control } usage = Reference;
687   if (column) {
688     if (column->isControl()) usage = Control;
689     if (column->isRendered() || column->getMeshColumn()) usage = Normal;
690   }
691 
692   if (usage == Reference) {
693     columnColor = m_viewer->getReferenceColumnColor();
694     dragColor   = m_viewer->getReferenceColumnBorderColor();
695   } else
696     m_viewer->getColumnColor(columnColor, dragColor, col, xsh);
697 }
soundColors(QColor & columnColor,QColor & dragColor) const698 void ColumnArea::DrawHeader::soundColors(QColor &columnColor,
699                                          QColor &dragColor) const {
700   m_viewer->getColumnColor(columnColor, dragColor, col, xsh);
701 }
paletteColors(QColor & columnColor,QColor & dragColor) const702 void ColumnArea::DrawHeader::paletteColors(QColor &columnColor,
703                                            QColor &dragColor) const {
704   enum { Normal, Reference, Control } usage = Reference;
705   if (column) {  // Check if column is a mask
706     if (column->isControl()) usage = Control;
707     if (column->isRendered()) usage = Normal;
708   }
709 
710   if (usage == Reference) {
711     columnColor = m_viewer->getReferenceColumnColor();
712     dragColor   = m_viewer->getReferenceColumnBorderColor();
713   } else {
714     columnColor = m_viewer->getPaletteColumnColor();
715     dragColor   = m_viewer->getPaletteColumnBorderColor();
716   }
717 }
718 
drawBaseFill(const QColor & columnColor,const QColor & dragColor) const719 void ColumnArea::DrawHeader::drawBaseFill(const QColor &columnColor,
720                                           const QColor &dragColor) const {
721   // check if the column is reference
722   bool isEditingSpline = app->getCurrentObject()->isSpline();
723 
724   QRect rect = o->rect((col < 0) ? PredefinedRect::CAMERA_LAYER_HEADER
725                                  : PredefinedRect::LAYER_HEADER)
726                    .translated(orig);
727 
728   int x0 = rect.left();
729   int x1 = rect.right();
730   int y0 = rect.top();
731   int y1 = rect.bottom();
732 
733   // Fill base color, in timeline view adjust it right upto thumbnail so column
734   // head color doesn't show under icon switches.
735   if (isEmpty)
736     p.fillRect(o->isVerticalTimeline() ? rect : rect.adjusted(80, 0, 0, 0),
737                m_viewer->getEmptyColumnHeadColor());
738   else if (col < 0)
739     p.fillRect(o->isVerticalTimeline() ? rect : rect.adjusted(80, 0, 0, 0),
740                columnColor);
741   else {
742     p.fillRect(o->isVerticalTimeline() ? rect : rect.adjusted(80, 0, 0, 0),
743                columnColor);
744 
745     if (o->flag(PredefinedFlag::DRAG_LAYER_VISIBLE)) {
746       // column handle
747       QRect sideBar = o->rect(PredefinedRect::DRAG_LAYER).translated(x0, y0);
748 
749       if (o->flag(PredefinedFlag::DRAG_LAYER_BORDER)) {
750         p.setPen(m_viewer->getVerticalLineColor());
751         p.drawRect(sideBar);
752       }
753 
754       p.fillRect(sideBar, sideBar.contains(area->m_pos)
755                               ? m_viewer->getXsheetDragBarHighlightColor()
756                               : dragColor);
757     }
758   }
759 
760   p.setPen(m_viewer->getVerticalLineHeadColor());
761   QLine vertical =
762       o->verticalLine(m_viewer->columnToLayerAxis(col), o->frameSide(rect));
763   if (isEmpty || o->isVerticalTimeline()) p.drawLine(vertical);
764 
765   // highlight selection
766   bool isSelected =
767       m_viewer->getColumnSelection()->isColumnSelected(col) && !isEditingSpline;
768   bool isCameraSelected = col == -1 && isCurrent && !isEditingSpline;
769 
770   QColor pastelizer(m_viewer->getColumnHeadPastelizer());
771 
772   QColor colorSelection(m_viewer->getSelectedColumnHead());
773   p.fillRect(o->isVerticalTimeline() ? rect : rect.adjusted(80, 0, 0, 0),
774              isSelected ? colorSelection : pastelizer);
775 }
776 
drawEye() const777 void ColumnArea::DrawHeader::drawEye() const {
778   if (isEmpty || !o->flag(PredefinedFlag::EYE_AREA_VISIBLE)) return;
779   if (col < 0 && o->isVerticalTimeline())
780     return;  // no preview eye in the camera column
781   QColor bgColor;
782   QImage icon;
783   int buttonType = !column->isPreviewVisible() ? PREVIEW_OFF_XSHBUTTON
784                                                : PREVIEW_ON_XSHBUTTON;
785   m_viewer->getButton(buttonType, bgColor, icon, !o->isVerticalTimeline());
786 
787   QRect prevViewRect = o->rect(PredefinedRect::EYE_AREA).translated(orig);
788   QRect eyeRect      = o->rect(PredefinedRect::EYE).translated(orig);
789   // preview visible toggle
790   if (o->isVerticalTimeline())
791     p.setPen(m_viewer->getColumnIconLineColor());  // Preview border color
792   else
793     p.setPen(m_viewer->getTimelineIconLineColor());  // Preview border color
794 
795   if (col < 0 || column->getSoundTextColumn()) {
796     if (o->flag(PredefinedFlag::EYE_AREA_BORDER)) p.drawRect(prevViewRect);
797     return;
798   }
799 
800   p.fillRect(prevViewRect, bgColor);  //   PreviewVisibleColor);
801   if (o->flag(PredefinedFlag::EYE_AREA_BORDER)) p.drawRect(prevViewRect);
802 
803   // For Legacy (layout=1), Preview Off button is not displayed in Xsheet mode
804   if (o->isVerticalTimeline() &&
805       m_viewer->getXsheetLayout() == QString("Classic") &&
806       buttonType == PREVIEW_OFF_XSHBUTTON)
807     return;
808 
809   p.drawImage(eyeRect, icon);
810 }
811 
drawPreviewToggle(int opacity) const812 void ColumnArea::DrawHeader::drawPreviewToggle(int opacity) const {
813   if (isEmpty || !o->flag(PredefinedFlag::PREVIEW_LAYER_AREA_VISIBLE)) return;
814   if (col < 0 && o->isVerticalTimeline())
815     return;  // no camstand toggle in the camera column
816   // camstand visible toggle
817   QColor bgColor;
818   QImage icon;
819   int buttonType =
820       !column->isCamstandVisible()
821           ? CAMSTAND_OFF_XSHBUTTON
822           : opacity < 255 ? CAMSTAND_TRANSP_XSHBUTTON : CAMSTAND_ON_XSHBUTTON;
823   m_viewer->getButton(buttonType, bgColor, icon, !o->isVerticalTimeline());
824 
825   QRect tableViewRect =
826       o->rect(PredefinedRect::PREVIEW_LAYER_AREA).translated(orig);
827   QRect tableViewImgRect =
828       o->rect(PredefinedRect::PREVIEW_LAYER).translated(orig);
829 
830   if (o->isVerticalTimeline())
831     p.setPen(m_viewer->getColumnIconLineColor());  // Camstand border color
832   else
833     p.setPen(m_viewer->getTimelineIconLineColor());  // Camstand border color
834 
835   if (col < 0 || column->getPaletteColumn() || column->getSoundTextColumn()) {
836     if (o->flag(PredefinedFlag::PREVIEW_LAYER_AREA_BORDER))
837       p.drawRect(tableViewRect);
838     return;
839   }
840 
841   p.fillRect(tableViewRect, bgColor);  //   CamStandVisibleColor);
842   if (o->flag(PredefinedFlag::PREVIEW_LAYER_AREA_BORDER))
843     p.drawRect(tableViewRect);
844 
845   // For Legacy (layout=1), Camstand Off button is not displayed in Xsheet mode
846   if (o->isVerticalTimeline() &&
847       m_viewer->getXsheetLayout() == QString("Classic") &&
848       buttonType == CAMSTAND_OFF_XSHBUTTON)
849     return;
850   p.drawImage(tableViewImgRect, icon);
851 }
852 
drawLock() const853 void ColumnArea::DrawHeader::drawLock() const {
854   if (isEmpty || !o->flag(PredefinedFlag::LOCK_AREA_VISIBLE)) return;
855   QColor bgColor;
856   QImage icon;
857   int buttonType = !column->isLocked() ? LOCK_OFF_XSHBUTTON : LOCK_ON_XSHBUTTON;
858   m_viewer->getButton(buttonType, bgColor, icon, !o->isVerticalTimeline());
859 
860   QRect lockModeRect = o->rect((col < 0) ? PredefinedRect::CAMERA_LOCK_AREA
861                                          : PredefinedRect::LOCK_AREA)
862                            .translated(orig);
863   QRect lockModeImgRect =
864       o->rect((col < 0) ? PredefinedRect::CAMERA_LOCK : PredefinedRect::LOCK)
865           .translated(orig);
866 
867   if (o->isVerticalTimeline() &&
868       m_viewer->getXsheetLayout() == QString("Classic") &&
869       buttonType == LOCK_OFF_XSHBUTTON && !bgColor.alpha())
870     bgColor = QColor(255, 255, 255, 128);
871 
872   // lock button
873   if (o->isVerticalTimeline())
874     p.setPen(m_viewer->getColumnIconLineColor());  // Lock border color
875   else
876     p.setPen(m_viewer->getTimelineIconLineColor());  // Lock border color
877 
878   p.fillRect(lockModeRect, bgColor);
879   if (o->flag(PredefinedFlag::LOCK_AREA_BORDER)) p.drawRect(lockModeRect);
880 
881   // For Legacy (layout=1), Lock Off button is not displayed in Xsheet mode
882   if (o->isVerticalTimeline() &&
883       m_viewer->getXsheetLayout() == QString("Classic") &&
884       buttonType == LOCK_OFF_XSHBUTTON)
885     return;
886   p.drawImage(lockModeImgRect, icon);
887 }
888 
drawConfig() const889 void ColumnArea::DrawHeader::drawConfig() const {
890   if (isEmpty || (col >= 0 && !o->flag(PredefinedFlag::CONFIG_AREA_VISIBLE)) ||
891       (col < 0 && !o->flag(PredefinedFlag::CAMERA_CONFIG_AREA_VISIBLE)))
892     return;
893   QColor bgColor;
894   QImage icon;
895   int buttonType = CONFIG_XSHBUTTON;
896   m_viewer->getButton(buttonType, bgColor, icon, !o->isVerticalTimeline());
897 
898   QRect configRect = o->rect((col < 0) ? PredefinedRect::CAMERA_CONFIG_AREA
899                                        : PredefinedRect::CONFIG_AREA)
900                          .translated(orig);
901   QRect configImgRect = o->rect((col < 0) ? PredefinedRect::CAMERA_CONFIG
902                                           : PredefinedRect::CONFIG)
903                             .translated(orig);
904 
905   // config button
906   if (o->isVerticalTimeline())
907     p.setPen(m_viewer->getColumnIconLineColor());
908   else
909     p.setPen(m_viewer->getTimelineIconLineColor());
910   p.fillRect(configRect, bgColor);
911   if (o->flag((col < 0) ? PredefinedFlag::CAMERA_CONFIG_AREA_BORDER
912                         : PredefinedFlag::CONFIG_AREA_BORDER))
913     p.drawRect(configRect);
914 
915   TXshZeraryFxColumn *zColumn = dynamic_cast<TXshZeraryFxColumn *>(column);
916 
917   if (zColumn || column->getPaletteColumn() || column->getSoundTextColumn())
918     return;
919 
920   p.drawImage(configImgRect, icon);
921 }
922 
drawColumnNumber() const923 void ColumnArea::DrawHeader::drawColumnNumber() const {
924   if (col < 0 || isEmpty || !o->flag(PredefinedFlag::LAYER_NUMBER_VISIBLE) ||
925       !Preferences::instance()->isShowColumnNumbersEnabled())
926     return;
927 
928   QRect pos = o->rect(PredefinedRect::LAYER_NUMBER).translated(orig);
929 
930   p.setPen(m_viewer->getVerticalLineColor());
931   if (o->flag(PredefinedFlag::LAYER_NUMBER_BORDER)) p.drawRect(pos);
932 
933   p.setPen((isCurrent) ? m_viewer->getSelectedColumnTextColor()
934                        : m_viewer->getTextColor());
935 
936   int valign = o->isVerticalTimeline() ? Qt::AlignVCenter : Qt::AlignBottom;
937 
938   p.drawText(pos, Qt::AlignHCenter | valign | Qt::TextSingleLine,
939              QString::number(col + 1));
940 }
941 
drawColumnName() const942 void ColumnArea::DrawHeader::drawColumnName() const {
943   if (!o->flag(PredefinedFlag::LAYER_NAME_VISIBLE)) return;
944 
945   TStageObjectId columnId    = m_viewer->getObjectId(col);
946   TStageObject *columnObject = xsh->getStageObject(columnId);
947 
948   // Build column name
949   std::string name(columnObject->getName());
950   //  if (col < 0) name = std::string("Camera");
951 
952   // ZeraryFx columns store name elsewhere
953   TXshZeraryFxColumn *zColumn = dynamic_cast<TXshZeraryFxColumn *>(column);
954   if (zColumn)
955     name = ::to_string(zColumn->getZeraryColumnFx()->getZeraryFx()->getName());
956 
957   QRect columnName = o->rect((col < 0) ? PredefinedRect::CAMERA_LAYER_NAME
958                                        : PredefinedRect::LAYER_NAME)
959                          .translated(orig);
960 
961   bool nameBacklit = false;
962   int rightadj     = -2;
963   int leftadj      = 3;
964   int valign = o->isVerticalTimeline() ? Qt::AlignVCenter : Qt::AlignBottom;
965 
966   if (!isEmpty) {
967     if (o->isVerticalTimeline() &&
968         m_viewer->getXsheetLayout() !=
969             QString("Classic"))  // Legacy - No background
970     {
971       if (columnName.contains(area->m_pos) && col >= 0) {
972         p.fillRect(columnName.adjusted(0, -1, 0, 0),
973                    m_viewer->getXsheetDragBarHighlightColor());  // Qt::yellow);
974         nameBacklit = true;
975       } else
976         p.fillRect(columnName, m_viewer->getXsheetColumnNameBgColor());
977     }
978 
979     if (o->flag(PredefinedFlag::LAYER_NAME_BORDER))
980       p.drawRect(columnName.adjusted(0, 0, 2, 0));
981 
982     if (o->isVerticalTimeline() &&
983         m_viewer->getXsheetLayout() == QString("Classic")) {
984       rightadj = -20;
985 
986       if (column->isPreviewVisible() && !column->getSoundTextColumn() &&
987           !column->getPaletteColumn() && col >= 0)
988         nameBacklit = true;
989     } else if (Preferences::instance()->isShowColumnNumbersEnabled()) {
990       if (o->isVerticalTimeline())
991         rightadj = -20;
992       else
993         leftadj = 24;
994     }
995 
996     p.setPen((isCurrent) ? m_viewer->getSelectedColumnTextColor()
997                          : nameBacklit ? Qt::black : m_viewer->getTextColor());
998   } else
999     p.setPen((isCurrent) ? m_viewer->getSelectedColumnTextColor()
1000                          : m_viewer->getTextColor());
1001 
1002   if (o->isVerticalTimeline() && col < 0) {
1003     QString cameraName = QString::fromStdString(name);
1004     p.save();
1005     p.translate(columnName.topRight());
1006     p.rotate(90);
1007     p.drawText(columnName.translated(-columnName.topLeft())
1008                    .transposed()
1009                    .adjusted(5, 0, 0, 0),
1010                Qt::AlignLeft | valign, cameraName);
1011     p.restore();
1012     return;
1013   }
1014 
1015   p.drawText(columnName.adjusted(leftadj, 0, rightadj, 0),
1016              Qt::AlignLeft | valign | Qt::TextSingleLine,
1017              QString(name.c_str()));
1018 }
1019 
drawThumbnail(QPixmap & iconPixmap) const1020 void ColumnArea::DrawHeader::drawThumbnail(QPixmap &iconPixmap) const {
1021   if (isEmpty) return;
1022 
1023   QRect thumbnailRect = o->rect((col < 0) ? PredefinedRect::CAMERA_ICON_AREA
1024                                           : PredefinedRect::THUMBNAIL_AREA)
1025                             .translated(orig);
1026   p.setPen(m_viewer->getVerticalLineColor());
1027   if (o->flag(PredefinedFlag::THUMBNAIL_AREA_BORDER)) p.drawRect(thumbnailRect);
1028 
1029   // sound thumbnail
1030   if (column->getSoundColumn()) {
1031     TXshSoundColumn *sc =
1032         xsh->getColumn(col) ? xsh->getColumn(col)->getSoundColumn() : 0;
1033 
1034     drawSoundIcon(sc->isPlaying());
1035     // Volume control now in config button. If no config button
1036     // draw control
1037     if (!o->flag(PredefinedFlag::CONFIG_AREA_VISIBLE))
1038       drawVolumeControl(sc->getVolume());
1039     return;
1040   }
1041 
1042   if (!o->flag((col < 0) ? PredefinedFlag::CAMERA_ICON_VISIBLE
1043                          : PredefinedFlag::THUMBNAIL_AREA_VISIBLE))
1044     return;
1045   QRect thumbnailImageRect = o->rect((col < 0) ? PredefinedRect::CAMERA_ICON
1046                                                : PredefinedRect::THUMBNAIL)
1047                                  .translated(orig);
1048 
1049   // pallete thumbnail
1050   if (column->getPaletteColumn()) {
1051     p.drawPixmap(thumbnailImageRect, iconPixmap);
1052     return;
1053   }
1054 
1055   // soundtext thumbnail
1056   if (column->getSoundTextColumn()) {
1057     p.drawPixmap(thumbnailImageRect, iconPixmap);
1058     return;
1059   }
1060 
1061   // All other thumbnails
1062   p.setPen(m_viewer->getTextColor());
1063 
1064   // for zerary fx, display fxId here instead of thumbnail
1065   TXshZeraryFxColumn *zColumn = dynamic_cast<TXshZeraryFxColumn *>(column);
1066   if (zColumn) {
1067     QFont lastfont = p.font();
1068     QFont font("Verdana", 8);
1069     p.setFont(font);
1070 
1071     TFx *fx        = zColumn->getZeraryColumnFx()->getZeraryFx();
1072     QString fxName = QString::fromStdWString(fx->getFxId());
1073     p.drawText(thumbnailImageRect, Qt::TextWrapAnywhere | Qt::TextWordWrap,
1074                fxName);
1075     p.setFont(lastfont);
1076   } else {
1077     TXshLevelColumn *levelColumn = column->getLevelColumn();
1078     TXshMeshColumn *meshColumn   = column->getMeshColumn();
1079 
1080     if (Preferences::instance()->getColumnIconLoadingPolicy() ==
1081             Preferences::LoadOnDemand &&
1082         ((levelColumn && !levelColumn->isIconVisible()) ||
1083          (meshColumn && !meshColumn->isIconVisible())) &&
1084         col >= 0) {
1085       // display nothing
1086     } else {
1087       if (!iconPixmap.isNull()) {
1088         p.drawPixmap(thumbnailImageRect, iconPixmap);
1089       }
1090       // notify that the column icon is already shown
1091       if (levelColumn)
1092         levelColumn->setIconVisible(true);
1093       else if (meshColumn)
1094         meshColumn->setIconVisible(true);
1095     }
1096   }
1097 }
1098 
drawPegbarName() const1099 void ColumnArea::DrawHeader::drawPegbarName() const {
1100   if (isEmpty || !o->flag(PredefinedFlag::PEGBAR_NAME_VISIBLE)) return;
1101   // the camera column may have parent pegbar, but it is not displayed for now
1102   if (col < 0) return;
1103 
1104   TStageObjectId columnId = m_viewer->getObjectId(col);
1105   TStageObjectId parentId = xsh->getStageObjectParent(columnId);
1106 
1107   // pegbar name
1108   QRect pegbarnamerect = o->rect(PredefinedRect::PEGBAR_NAME).translated(orig);
1109   p.setPen(m_viewer->getVerticalLineColor());
1110   if (o->flag(PredefinedFlag::PEGBAR_NAME_BORDER)) p.drawRect(pegbarnamerect);
1111 
1112   if (column->getSoundColumn() || column->getSoundTextColumn() ||
1113       column->getPaletteColumn())
1114     return;
1115 
1116   p.setPen(m_viewer->getTextColor());
1117 
1118   p.drawText(pegbarnamerect.adjusted(3, 0, 0, 0),
1119              Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine,
1120              QString(parentId.toString().c_str()));
1121 }
1122 
drawParentHandleName() const1123 void ColumnArea::DrawHeader::drawParentHandleName() const {
1124   if (col < 0 || isEmpty ||
1125       !o->flag(PredefinedFlag::PARENT_HANDLE_NAME_VISIBILE) ||
1126       column->getSoundColumn() || column->getSoundTextColumn() ||
1127       column->getPaletteColumn())
1128     return;
1129 
1130   QRect parenthandleRect =
1131       o->rect(PredefinedRect::PARENT_HANDLE_NAME).translated(orig);
1132   p.setPen(Qt::yellow);  // m_viewer->getVerticalLineColor());
1133   if (o->flag(PredefinedFlag::PARENT_HANDLE_NAME_BORDER))
1134     p.drawRect(parenthandleRect);
1135 
1136   TStageObjectId columnId = m_viewer->getObjectId(col);
1137   TStageObjectId parentId = xsh->getStageObjectParent(columnId);
1138 
1139   p.setPen(m_viewer->getTextColor());
1140 
1141   std::string handle = xsh->getStageObject(columnId)->getParentHandle();
1142   if (handle[0] == 'H' && handle.length() > 1) handle = handle.substr(1);
1143   if (parentId != TStageObjectId::TableId)
1144     p.drawText(parenthandleRect,
1145                Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextSingleLine,
1146                QString::fromStdString(handle));
1147 }
1148 
drawFilterColor() const1149 void ColumnArea::DrawHeader::drawFilterColor() const {
1150   if (col < 0 || isEmpty || !column->getFilterColorId() ||
1151       column->getSoundColumn() || column->getSoundTextColumn() ||
1152       column->getPaletteColumn())
1153     return;
1154 
1155   QRect filterColorRect =
1156       o->rect(PredefinedRect::FILTER_COLOR).translated(orig);
1157   p.drawPixmap(filterColorRect,
1158                getColorChipIcon(column->getFilterColor()).pixmap(12, 12));
1159 }
1160 
drawSoundIcon(bool isPlaying) const1161 void ColumnArea::DrawHeader::drawSoundIcon(bool isPlaying) const {
1162   QRect rect = m_viewer->orientation()
1163                    ->rect(PredefinedRect::SOUND_ICON)
1164                    .translated(orig);
1165   p.drawPixmap(rect, isPlaying ? Pixmaps::soundPlaying() : Pixmaps::sound());
1166 }
1167 
drawVolumeControl(double volume) const1168 void ColumnArea::DrawHeader::drawVolumeControl(double volume) const {
1169   // slider subdivisions
1170   p.setPen(m_viewer->getTextColor());
1171   QPoint divisionsTopLeft =
1172       o->point(PredefinedPoint::VOLUME_DIVISIONS_TOP_LEFT) + orig;
1173   int layerAxis = o->layerAxis(divisionsTopLeft);
1174   int frameAxis = o->frameAxis(divisionsTopLeft);
1175   if (o->isVerticalTimeline()) {
1176     if (m_viewer->getXsheetLayout() == QString("Classic")) {
1177       for (int i = 0; i <= 20; i++, frameAxis += 3)
1178         if ((i % 10) == 0)
1179           p.drawLine(o->horizontalLine(frameAxis,
1180                                        NumberRange(layerAxis - 3, layerAxis)));
1181         else if (i & 1)
1182           p.drawLine(
1183               o->horizontalLine(frameAxis, NumberRange(layerAxis, layerAxis)));
1184         else
1185           p.drawLine(o->horizontalLine(frameAxis,
1186                                        NumberRange(layerAxis - 2, layerAxis)));
1187     } else {
1188       for (int i = 0; i <= 20; i++, layerAxis += 3)
1189         if ((i % 10) == 0)
1190           p.drawLine(o->verticalLine(layerAxis,
1191                                      NumberRange(frameAxis, frameAxis + 3)));
1192         else if (i & 1)
1193           p.drawLine(
1194               o->verticalLine(layerAxis, NumberRange(frameAxis, frameAxis)));
1195         else
1196           p.drawLine(o->verticalLine(layerAxis,
1197                                      NumberRange(frameAxis, frameAxis + 2)));
1198     }
1199   } else {
1200     for (int i = 0; i <= 20; i++, frameAxis += 3)
1201       if ((i % 10) == 0)
1202         p.drawLine(o->horizontalLine(frameAxis,
1203                                      NumberRange(layerAxis, layerAxis + 3)));
1204       else if (i & 1)
1205         p.drawLine(
1206             o->horizontalLine(frameAxis, NumberRange(layerAxis, layerAxis)));
1207       else
1208         p.drawLine(o->horizontalLine(frameAxis,
1209                                      NumberRange(layerAxis, layerAxis + 2)));
1210   }
1211 
1212   // slider track
1213   QPainterPath track =
1214       o->path(PredefinedPath::VOLUME_SLIDER_TRACK).translated(orig);
1215   p.drawPath(track);
1216 
1217   // cursor
1218   QRect trackRect = o->rect(PredefinedRect::VOLUME_TRACK).translated(orig);
1219   if (o->flag(PredefinedFlag::VOLUME_AREA_VERTICAL)) volume = 1 - volume;
1220 
1221   layerAxis = o->layerSide(trackRect).middle();
1222   frameAxis = o->frameSide(trackRect).weight(volume);
1223   if (o->isVerticalTimeline() &&
1224       !o->flag(PredefinedFlag::VOLUME_AREA_VERTICAL)) {
1225     layerAxis = o->frameSide(trackRect).middle();
1226     frameAxis = o->layerSide(trackRect).weight(volume);
1227   }
1228   QPoint cursor = o->frameLayerToXY(frameAxis, layerAxis) + QPoint(1, 0);
1229   if (o->isVerticalTimeline() &&
1230       !o->flag(PredefinedFlag::VOLUME_AREA_VERTICAL)) {
1231     cursor = o->frameLayerToXY(layerAxis, frameAxis) + QPoint(1, 0);
1232   }
1233   QPainterPath head =
1234       o->path(PredefinedPath::VOLUME_SLIDER_HEAD).translated(cursor);
1235   p.fillPath(head, QBrush(Qt::white));
1236   p.setPen(m_viewer->getLightLineColor());
1237   p.drawPath(head);
1238 }
1239 
1240 //=============================================================================
1241 // ColumnArea
1242 //-----------------------------------------------------------------------------
1243 #if QT_VERSION >= 0x050500
ColumnArea(XsheetViewer * parent,Qt::WindowFlags flags)1244 ColumnArea::ColumnArea(XsheetViewer *parent, Qt::WindowFlags flags)
1245 #else
1246 ColumnArea::ColumnArea(XsheetViewer *parent, Qt::WFlags flags)
1247 #endif
1248     : QWidget(parent, flags)
1249     , m_viewer(parent)
1250     , m_pos(-1, -1)
1251     , m_tooltip(tr(""))
1252     , m_col(-1)
1253     , m_columnTransparencyPopup(0)
1254     , m_transparencyPopupTimer(0)
1255     , m_isPanning(false)
1256     , m_soundColumnPopup(0) {
1257   TXsheetHandle *xsheetHandle = TApp::instance()->getCurrentXsheet();
1258   TObjectHandle *objectHandle = TApp::instance()->getCurrentObject();
1259   m_changeObjectParent        = new ChangeObjectParent(0);
1260   m_changeObjectParent->setObjectHandle(objectHandle);
1261   m_changeObjectParent->setXsheetHandle(xsheetHandle);
1262   m_changeObjectParent->hide();
1263 
1264   m_changeObjectHandle = new ChangeObjectHandle(0);
1265   m_changeObjectHandle->setObjectHandle(objectHandle);
1266   m_changeObjectHandle->setXsheetHandle(xsheetHandle);
1267   m_changeObjectHandle->hide();
1268 
1269 #ifdef LINETEST
1270   // linetest had options around a motion path
1271   // you could configure from the column header
1272   m_motionPathMenu = new MotionPathMenu(0);
1273 #endif
1274 
1275   m_renameColumnField = new RenameColumnField(this, m_viewer);
1276   m_renameColumnField->setXsheetHandle(xsheetHandle);
1277   m_renameColumnField->hide();
1278 
1279   QActionGroup *actionGroup = new QActionGroup(this);
1280   m_subsampling1            = new QAction(tr("&Subsampling 1"), actionGroup);
1281   m_subsampling2            = new QAction(tr("&Subsampling 2"), actionGroup);
1282   m_subsampling3            = new QAction(tr("&Subsampling 3"), actionGroup);
1283   m_subsampling4            = new QAction(tr("&Subsampling 4"), actionGroup);
1284   actionGroup->addAction(m_subsampling1);
1285   actionGroup->addAction(m_subsampling2);
1286   actionGroup->addAction(m_subsampling3);
1287   actionGroup->addAction(m_subsampling4);
1288 
1289   connect(actionGroup, SIGNAL(triggered(QAction *)), this,
1290           SLOT(onSubSampling(QAction *)));
1291   connect(xsheetHandle, SIGNAL(xsheetCameraChange(int)), this,
1292           SLOT(onXsheetCameraChange(int)));
1293   setMouseTracking(true);
1294 }
1295 
1296 //-----------------------------------------------------------------------------
1297 
~ColumnArea()1298 ColumnArea::~ColumnArea() {}
1299 
1300 //-----------------------------------------------------------------------------
1301 
getDragTool() const1302 DragTool *ColumnArea::getDragTool() const { return m_viewer->getDragTool(); }
setDragTool(DragTool * dragTool)1303 void ColumnArea::setDragTool(DragTool *dragTool) {
1304   m_viewer->setDragTool(dragTool);
1305 }
1306 
1307 //-----------------------------------------------------------------------------
drawFoldedColumnHead(QPainter & p,int col)1308 void ColumnArea::drawFoldedColumnHead(QPainter &p, int col) {
1309   const Orientation *o = m_viewer->orientation();
1310 
1311   QPoint orig = m_viewer->positionToXY(CellPosition(0, col));
1312   QRect rect  = o->rect(PredefinedRect::FOLDED_LAYER_HEADER).translated(orig);
1313 
1314   int x0, y0, x, y;
1315 
1316   if (o->isVerticalTimeline()) {
1317     x0 = rect.topLeft().x() + 1;
1318     y0 = 0;
1319 
1320     p.setPen(m_viewer->getDarkLineColor());
1321     p.fillRect(x0, y0 + 1, rect.width(), 18,
1322                QBrush(m_viewer->getFoldedColumnBGColor()));
1323     p.fillRect(x0, y0 + 17, 2, rect.height() - 34,
1324                QBrush(m_viewer->getFoldedColumnBGColor()));
1325     p.fillRect(x0 + 3, y0 + 20, 2, rect.height() - 36,
1326                QBrush(m_viewer->getFoldedColumnBGColor()));
1327     p.fillRect(x0 + 6, y0 + 17, 2, rect.height() - 34,
1328                QBrush(m_viewer->getFoldedColumnBGColor()));
1329 
1330     p.setPen(m_viewer->getFoldedColumnLineColor());
1331     p.drawLine(x0 - 1, y0 + 17, x0 - 1, rect.height());
1332     p.setPen(m_viewer->getFoldedColumnLineColor());
1333     p.drawLine(x0 + 2, y0 + 17, x0 + 2, rect.height());
1334     p.drawLine(x0 + 5, y0 + 17, x0 + 5, rect.height());
1335     p.drawLine(x0, y0 + 17, x0 + 1, 17);
1336     p.drawLine(x0 + 3, y0 + 20, x0 + 4, 20);
1337     p.drawLine(x0 + 6, y0 + 17, x0 + 7, 17);
1338 
1339     // triangolini
1340     p.setPen(Qt::black);
1341     x = x0;
1342     y = 12;
1343     p.drawPoint(QPointF(x, y));
1344     x++;
1345     p.drawLine(x, y - 1, x, y + 1);
1346     x++;
1347     p.drawLine(x, y - 2, x, y + 2);
1348     x += 3;
1349     p.drawLine(x, y - 2, x, y + 2);
1350     x++;
1351     p.drawLine(x, y - 1, x, y + 1);
1352     x++;
1353     p.drawPoint(x, y);
1354   } else {
1355     x0 = 0;
1356     y0 = rect.topLeft().y() + 1;
1357 
1358     p.setPen(m_viewer->getFoldedColumnLineColor());
1359     p.fillRect(x0 + 1, y0, 18, rect.height(),
1360                QBrush(m_viewer->getFoldedColumnBGColor()));
1361     p.fillRect(x0 + 17, y0, rect.width() - 34, 2,
1362                QBrush(m_viewer->getFoldedColumnBGColor()));
1363     p.fillRect(x0 + 20, y0 + 3, rect.width() - 36, 2,
1364                QBrush(m_viewer->getFoldedColumnBGColor()));
1365     p.fillRect(x0 + 17, y0 + 6, rect.width() - 34, 2,
1366                QBrush(m_viewer->getFoldedColumnBGColor()));
1367 
1368     p.setPen(m_viewer->getFoldedColumnLineColor());
1369     p.drawLine(x0 + 17, y0 - 1, rect.width(), y0 - 1);
1370     p.setPen(m_viewer->getFoldedColumnLineColor());
1371     p.drawLine(x0 + 17, y0 + 2, rect.width(), y0 + 2);
1372     p.drawLine(x0 + 17, y0 + 5, rect.width(), y0 + 5);
1373     p.drawLine(x0 + 17, y0, 17, y0 + 1);
1374     p.drawLine(x0 + 20, y0 + 3, 20, y0 + 4);
1375     p.drawLine(x0 + 17, y0 + 6, 17, y0 + 7);
1376 
1377     // triangolini
1378     p.setPen(Qt::black);
1379     x = 12;
1380     y = y0;
1381     p.drawPoint(QPointF(x, y));
1382     y++;
1383     p.drawLine(x - 1, y, x + 1, y);
1384     y++;
1385     p.drawLine(x - 2, y, x + 2, y);
1386     y += 3;
1387     p.drawLine(x - 2, y, x + 2, y);
1388     y++;
1389     p.drawLine(x - 1, y, x + 1, y);
1390     y++;
1391     p.drawPoint(x, y);
1392   }
1393 }
1394 
drawLevelColumnHead(QPainter & p,int col)1395 void ColumnArea::drawLevelColumnHead(QPainter &p, int col) {
1396   TColumnSelection *selection = m_viewer->getColumnSelection();
1397   const Orientation *o        = m_viewer->orientation();
1398 
1399   // Preparing painter
1400   QString fontName = Preferences::instance()->getInterfaceFont();
1401   if (fontName == "") {
1402 #ifdef _WIN32
1403     fontName = "Arial";
1404 #else
1405     fontName = "Helvetica";
1406 #endif
1407   }
1408   static QFont font(fontName, -1, QFont::Normal);
1409   font.setPixelSize(XSHEET_FONT_PX_SIZE);
1410 
1411   p.setFont(font);
1412   p.setRenderHint(QPainter::SmoothPixmapTransform, true);
1413 
1414   // Retrieve reference coordinates
1415   int currentColumnIndex = m_viewer->getCurrentColumn();
1416   int layerAxis          = m_viewer->columnToLayerAxis(col);
1417 
1418   QPoint orig = m_viewer->positionToXY(CellPosition(0, col));
1419   QRect rect  = o->rect(PredefinedRect::LAYER_HEADER).translated(orig);
1420 
1421   TApp *app    = TApp::instance();
1422   TXsheet *xsh = m_viewer->getXsheet();
1423 
1424   TStageObjectId columnId        = m_viewer->getObjectId(col);
1425   TStageObjectId currentColumnId = app->getCurrentObject()->getObjectId();
1426   TStageObjectId parentId        = xsh->getStageObjectParent(columnId);
1427 
1428   // Retrieve column properties
1429   // Check if the column is empty
1430   bool isEmpty       = col >= 0 && xsh->isColumnEmpty(col);
1431   TXshColumn *column = col >= 0 ? xsh->getColumn(col) : 0;
1432 
1433   bool isEditingSpline = app->getCurrentObject()->isSpline();
1434 
1435   // check if the column is current
1436   bool isCurrent = false;
1437   if (currentColumnId ==
1438       TStageObjectId::CameraId(xsh->getCameraColumnIndex()))  // CAMERA
1439     isCurrent = col == -1;
1440   else
1441     isCurrent = m_viewer->getCurrentColumn() == col;
1442 
1443   bool isSelected =
1444       m_viewer->getColumnSelection()->isColumnSelected(col) && !isEditingSpline;
1445   bool isCameraSelected = col == -1 && isCurrent && !isEditingSpline;
1446 
1447   // Draw column
1448   DrawHeader drawHeader(this, p, col);
1449   drawHeader.prepare();
1450   QColor columnColor, dragColor;
1451   drawHeader.levelColors(columnColor, dragColor);
1452   drawHeader.drawBaseFill(columnColor, dragColor);
1453   drawHeader.drawEye();
1454   drawHeader.drawPreviewToggle(column ? column->getOpacity() : 0);
1455   drawHeader.drawLock();
1456   drawHeader.drawConfig();
1457   drawHeader.drawColumnName();
1458   drawHeader.drawColumnNumber();
1459   QPixmap iconPixmap = getColumnIcon(col);
1460   drawHeader.drawThumbnail(iconPixmap);
1461   drawHeader.drawPegbarName();
1462   drawHeader.drawParentHandleName();
1463   drawHeader.drawFilterColor();
1464 }
1465 
1466 //-----------------------------------------------------------------------------
1467 
drawSoundColumnHead(QPainter & p,int col)1468 void ColumnArea::drawSoundColumnHead(QPainter &p, int col) {  // AREA
1469   TColumnSelection *selection = m_viewer->getColumnSelection();
1470   const Orientation *o        = m_viewer->orientation();
1471 
1472   int x = m_viewer->columnToLayerAxis(col);
1473 
1474   p.setRenderHint(QPainter::SmoothPixmapTransform, true);
1475   QString fontName = Preferences::instance()->getInterfaceFont();
1476   if (fontName == "") {
1477 #ifdef _WIN32
1478     fontName = "Arial";
1479 #else
1480     fontName = "Helvetica";
1481 #endif
1482   }
1483   static QFont font(fontName, -1, QFont::Normal);
1484   font.setPixelSize(XSHEET_FONT_PX_SIZE);
1485   p.setFont(font);
1486 
1487   TXsheet *xsh = m_viewer->getXsheet();
1488   TXshSoundColumn *sc =
1489       xsh->getColumn(col) ? xsh->getColumn(col)->getSoundColumn() : 0;
1490 
1491   QPoint orig = m_viewer->positionToXY(CellPosition(0, col));
1492   QRect rect  = m_viewer->orientation()
1493                    ->rect(PredefinedRect::LAYER_HEADER)
1494                    .translated(orig);
1495 
1496   QPoint columnNamePos = orig + QPoint(12, o->cellHeight());
1497 
1498   bool isCurrent = m_viewer->getCurrentColumn() == col;
1499 
1500   DrawHeader drawHeader(this, p, col);
1501   drawHeader.prepare();
1502   QColor columnColor, dragColor;
1503   //  drawHeader.soundColors(columnColor, dragColor);
1504   drawHeader.levelColors(columnColor, dragColor);
1505   drawHeader.drawBaseFill(columnColor, dragColor);
1506   drawHeader.drawEye();
1507   drawHeader.drawPreviewToggle(sc ? (troundp(255.0 * sc->getVolume())) : 0);
1508   drawHeader.drawLock();
1509   drawHeader.drawConfig();
1510   drawHeader.drawColumnName();
1511   drawHeader.drawColumnNumber();
1512   // Sound columns don't have an image. Passing in an image
1513   // for arguement, but it will be ignored.
1514   static QPixmap iconignored;
1515   drawHeader.drawThumbnail(iconignored);
1516   drawHeader.drawPegbarName();
1517   drawHeader.drawParentHandleName();
1518   drawHeader.drawFilterColor();
1519 }
1520 
1521 //-----------------------------------------------------------------------------
1522 
drawPaletteColumnHead(QPainter & p,int col)1523 void ColumnArea::drawPaletteColumnHead(QPainter &p, int col) {  // AREA
1524   TColumnSelection *selection = m_viewer->getColumnSelection();
1525   const Orientation *o        = m_viewer->orientation();
1526 
1527   QPoint orig = m_viewer->positionToXY(CellPosition(0, std::max(col, -1)));
1528 
1529   QString fontName = Preferences::instance()->getInterfaceFont();
1530   if (fontName == "") {
1531 #ifdef _WIN32
1532     fontName = "Arial";
1533 #else
1534     fontName = "Helvetica";
1535 #endif
1536   }
1537   static QFont font(fontName, -1, QFont::Normal);
1538   font.setPixelSize(XSHEET_FONT_PX_SIZE);
1539 
1540   p.setFont(font);
1541   p.setRenderHint(QPainter::SmoothPixmapTransform, true);
1542 
1543   int currentColumnIndex = m_viewer->getCurrentColumn();
1544   int x                  = m_viewer->columnToLayerAxis(col);
1545 
1546   QRect rect(x, 0, o->cellWidth(), height());
1547 
1548   TXsheet *xsh = m_viewer->getXsheet();
1549 
1550   bool isEmpty = false;
1551   if (col >= 0)  // Verifico se la colonna e' vuota
1552     isEmpty = xsh->isColumnEmpty(col);
1553 
1554   DrawHeader drawHeader(this, p, col);
1555   drawHeader.prepare();
1556   QColor columnColor, dragColor;
1557   drawHeader.paletteColors(columnColor, dragColor);
1558   drawHeader.drawBaseFill(columnColor, dragColor);
1559   drawHeader.drawEye();
1560   drawHeader.drawPreviewToggle(0);
1561   drawHeader.drawLock();
1562   drawHeader.drawConfig();
1563   drawHeader.drawColumnName();
1564   drawHeader.drawColumnNumber();
1565   static QPixmap iconPixmap(svgToPixmap(":Resources/palette_header.svg"));
1566   drawHeader.drawThumbnail(iconPixmap);
1567   drawHeader.drawPegbarName();
1568   drawHeader.drawParentHandleName();
1569   drawHeader.drawFilterColor();
1570 }
1571 
1572 //-----------------------------------------------------------------------------
1573 
drawSoundTextColumnHead(QPainter & p,int col)1574 void ColumnArea::drawSoundTextColumnHead(QPainter &p, int col) {  // AREA
1575   TColumnSelection *selection = m_viewer->getColumnSelection();
1576   const Orientation *o        = m_viewer->orientation();
1577 
1578   int x = m_viewer->columnToLayerAxis(col);
1579 
1580   p.setRenderHint(QPainter::SmoothPixmapTransform, true);
1581   QString fontName = Preferences::instance()->getInterfaceFont();
1582   if (fontName == "") {
1583 #ifdef _WIN32
1584     fontName = "Arial";
1585 #else
1586     fontName = "Helvetica";
1587 #endif
1588   }
1589   static QFont font(fontName, -1, QFont::Normal);
1590   font.setPixelSize(XSHEET_FONT_PX_SIZE);
1591   p.setFont(font);
1592 
1593   QRect rect(x, 0, o->cellWidth(), height());
1594 
1595   TApp *app    = TApp::instance();
1596   TXsheet *xsh = m_viewer->getXsheet();
1597 
1598   TStageObjectId columnId = m_viewer->getObjectId(col);
1599   std::string name        = xsh->getStageObject(columnId)->getName();
1600 
1601   bool isEditingSpline = app->getCurrentObject()->isSpline();
1602 
1603   // Check if column is locked and selected
1604   TXshColumn *column = col >= 0 ? xsh->getColumn(col) : 0;
1605   bool isLocked      = column != 0 && column->isLocked();
1606   bool isCurrent     = m_viewer->getCurrentColumn() == col;
1607   bool isSelected =
1608       m_viewer->getColumnSelection()->isColumnSelected(col) && !isEditingSpline;
1609 
1610   DrawHeader drawHeader(this, p, col);
1611   drawHeader.prepare();
1612   QColor columnColor, dragColor;
1613   drawHeader.paletteColors(columnColor, dragColor);
1614   drawHeader.drawBaseFill(columnColor, dragColor);
1615   drawHeader.drawEye();
1616   drawHeader.drawPreviewToggle(255);
1617   drawHeader.drawLock();
1618   drawHeader.drawConfig();
1619   drawHeader.drawColumnName();
1620   drawHeader.drawColumnNumber();
1621   static QPixmap iconPixmap(
1622       recolorPixmap(svgToPixmap(getIconThemePath("actions/74/notelevel.svg"))));
1623   drawHeader.drawThumbnail(iconPixmap);
1624   drawHeader.drawPegbarName();
1625   drawHeader.drawParentHandleName();
1626   drawHeader.drawFilterColor();
1627 }
1628 
1629 //-----------------------------------------------------------------------------
1630 
getColumnIcon(int columnIndex)1631 QPixmap ColumnArea::getColumnIcon(int columnIndex) {
1632   const Orientation *o = m_viewer->orientation();
1633 
1634   if (columnIndex == -1) {  // Indice colonna = -1 -> CAMERA
1635     if (o->isVerticalTimeline()) {
1636       static QPixmap camera = svgToPixmap(":Resources/camera_small.svg");
1637       return camera;
1638     } else {
1639       static QPixmap camera = svgToPixmap(":Resources/camera.svg");
1640       return camera;
1641     }
1642   }
1643   TXsheet *xsh = m_viewer->getXsheet();
1644   if (!xsh) return QPixmap();
1645   if (xsh->isColumnEmpty(columnIndex)) return QPixmap();
1646   int r0, r1;
1647   xsh->getCellRange(columnIndex, r0, r1);
1648   if (r0 > r1) return QPixmap();
1649   TXshCell cell = xsh->getCell(r0, columnIndex);
1650   TXshLevel *xl = cell.m_level.getPointer();
1651   if (!xl)
1652     return QPixmap();
1653   else {
1654     bool onDemand = false;
1655     if (Preferences::instance()->getColumnIconLoadingPolicy() ==
1656         Preferences::LoadOnDemand) {
1657       onDemand = m_viewer->getCurrentColumn() != columnIndex;
1658       if (!onDemand) {
1659         TXshColumn *column           = xsh->getColumn(columnIndex);
1660         TXshLevelColumn *levelColumn = column->getLevelColumn();
1661         TXshMeshColumn *meshColumn   = column->getMeshColumn();
1662         if ((levelColumn && !levelColumn->isIconVisible()) ||
1663             (meshColumn && !meshColumn->isIconVisible()))
1664           return QPixmap();
1665       }
1666     }
1667     QPixmap icon =
1668         IconGenerator::instance()->getIcon(xl, cell.m_frameId, false, onDemand);
1669     QRect thumbnailImageRect = o->rect(PredefinedRect::THUMBNAIL);
1670     if (thumbnailImageRect.isEmpty()) return QPixmap();
1671     return scalePixmapKeepingAspectRatio(icon, thumbnailImageRect.size());
1672   }
1673 }
1674 
1675 //-----------------------------------------------------------------------------
1676 
paintEvent(QPaintEvent * event)1677 void ColumnArea::paintEvent(QPaintEvent *event) {  // AREA
1678   QRect toBeUpdated = event->rect();
1679 
1680   QPainter p(this);
1681   p.setClipRect(toBeUpdated);
1682 
1683   TXsheet *xsh        = m_viewer->getXsheet();
1684   CellRange cellRange = m_viewer->xyRectToRange(toBeUpdated);
1685   int c0, c1;  // range of visible columns
1686   c0 = cellRange.from().layer();
1687   c1 = cellRange.to().layer();
1688   if (!m_viewer->orientation()->isVerticalTimeline()) {
1689     int colCount = std::max(1, xsh->getColumnCount());
1690     c1           = std::min(c1, colCount - 1);
1691   }
1692 
1693   ColumnFan *columnFan = xsh->getColumnFan(m_viewer->orientation());
1694   int col;
1695   for (col = c0; col <= c1; col++) {
1696     // draw column fan (collapsed columns)
1697     if (!columnFan->isActive(col)) {
1698       drawFoldedColumnHead(p, col);
1699     } else {
1700       TXshColumn *column = m_viewer->getXsheet()->getColumn(col);
1701 
1702       int colType = (column && !column->isEmpty()) ? column->getColumnType()
1703                                                    : TXshColumn::eLevelType;
1704 
1705       switch (colType) {
1706       case TXshColumn::ePaletteType:
1707         drawPaletteColumnHead(p, col);
1708         break;
1709       case TXshColumn::eSoundType:
1710         drawSoundColumnHead(p, col);
1711         break;
1712       case TXshColumn::eSoundTextType:
1713         drawSoundTextColumnHead(p, col);
1714         break;
1715       default:
1716         drawLevelColumnHead(p, col);  // camera column is also painted here
1717         break;
1718       }
1719     }
1720   }
1721 
1722   p.setPen(m_viewer->getVerticalLineHeadColor());
1723   p.setBrush(Qt::NoBrush);
1724   if (m_viewer->orientation()->isVerticalTimeline())
1725     p.drawRect(toBeUpdated.adjusted(-1, 0, -1, -3));
1726   else
1727     p.drawRect(toBeUpdated.adjusted(0, 0, -2, -1));
1728 
1729   if (getDragTool()) getDragTool()->drawColumnsArea(p);
1730 }
1731 
1732 //-----------------------------------------------------------------------------
1733 using namespace DVGui;
1734 
ColumnTransparencyPopup(QWidget * parent)1735 ColumnTransparencyPopup::ColumnTransparencyPopup(QWidget *parent)
1736     : QWidget(parent, Qt::Popup) {
1737   setFixedWidth(8 + 78 + 8 + 100 + 8 + 8 + 8 + 7);
1738 
1739   m_slider = new QSlider(Qt::Horizontal, this);
1740   m_slider->setMinimum(1);
1741   m_slider->setMaximum(100);
1742   m_slider->setFixedHeight(14);
1743   m_slider->setFixedWidth(100);
1744 
1745   m_value = new DVGui::IntLineEdit(this, 1, 1, 100);
1746   /*m_value->setValidator(new QIntValidator (1, 100, m_value));
1747 m_value->setFixedHeight(16);
1748 m_value->setFixedWidth(30);
1749 static QFont font("Helvetica", 7, QFont::Normal);
1750 m_value->setFont(font);*/
1751 
1752   m_filterColorCombo = new QComboBox(this);
1753   for (int f = 0; f < (int)TXshColumn::FilterAmount; f++) {
1754     QPair<QString, TPixel32> info =
1755         TXshColumn::getFilterInfo((TXshColumn::FilterColor)f);
1756     if ((TXshColumn::FilterColor)f == TXshColumn::FilterNone)
1757       m_filterColorCombo->addItem(info.first, f);
1758     else
1759       m_filterColorCombo->addItem(getColorChipIcon(info.second), info.first, f);
1760   }
1761 
1762   QLabel *filterLabel = new QLabel(tr("Filter:"), this);
1763   QLabel *sliderLabel = new QLabel(tr("Opacity:"), this);
1764 
1765   QVBoxLayout *mainLayout = new QVBoxLayout();
1766   mainLayout->setMargin(3);
1767   mainLayout->setSpacing(3);
1768   {
1769     QHBoxLayout *hlayout = new QHBoxLayout;
1770     // hlayout->setContentsMargins(0, 3, 0, 3);
1771     hlayout->setMargin(0);
1772     hlayout->setSpacing(3);
1773     hlayout->addWidget(sliderLabel, 0);
1774     hlayout->addWidget(m_slider);
1775     hlayout->addWidget(m_value);
1776     hlayout->addWidget(new QLabel("%"));
1777     mainLayout->addLayout(hlayout, 0);
1778 
1779     QHBoxLayout *filterColorLay = new QHBoxLayout();
1780     filterColorLay->setMargin(0);
1781     filterColorLay->setSpacing(2);
1782     {
1783       filterColorLay->addWidget(filterLabel, 0);
1784       filterColorLay->addWidget(m_filterColorCombo, 1);
1785     }
1786     mainLayout->addLayout(filterColorLay, 0);
1787   }
1788   setLayout(mainLayout);
1789 
1790   bool ret = connect(m_slider, SIGNAL(sliderReleased()), this,
1791                      SLOT(onSliderReleased()));
1792   ret      = ret && connect(m_slider, SIGNAL(sliderMoved(int)), this,
1793                        SLOT(onSliderChange(int)));
1794   ret      = ret && connect(m_slider, SIGNAL(valueChanged(int)), this,
1795                        SLOT(onSliderValueChanged(int)));
1796   ret      = ret && connect(m_value, SIGNAL(textChanged(const QString &)), this,
1797                        SLOT(onValueChanged(const QString &)));
1798 
1799   ret = ret && connect(m_filterColorCombo, SIGNAL(activated(int)), this,
1800                        SLOT(onFilterColorChanged(int)));
1801   assert(ret);
1802 }
1803 
1804 //----------------------------------------------------------------
1805 
onSliderValueChanged(int val)1806 void ColumnTransparencyPopup::onSliderValueChanged(int val) {
1807   if (m_slider->isSliderDown()) return;
1808   m_value->setText(QString::number(val));
1809   onSliderReleased();
1810 }
1811 
onSliderReleased()1812 void ColumnTransparencyPopup::onSliderReleased() {
1813   m_column->setOpacity(troundp(255.0 * m_slider->value() / 100.0));
1814   TApp::instance()->getCurrentScene()->notifySceneChanged();
1815   TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
1816   ((ColumnArea *)parent())->update();
1817 }
1818 
1819 //-----------------------------------------------------------------------
1820 
onSliderChange(int val)1821 void ColumnTransparencyPopup::onSliderChange(int val) {
1822   disconnect(m_value, SIGNAL(textChanged(const QString &)), 0, 0);
1823   m_value->setText(QString::number(val));
1824   connect(m_value, SIGNAL(textChanged(const QString &)), this,
1825           SLOT(onValueChanged(const QString &)));
1826 }
1827 
1828 //----------------------------------------------------------------
1829 
onValueChanged(const QString & str)1830 void ColumnTransparencyPopup::onValueChanged(const QString &str) {
1831   int val = str.toInt();
1832   m_slider->setValue(val);
1833   m_column->setOpacity(troundp(255.0 * val / 100.0));
1834 
1835   TApp::instance()->getCurrentScene()->notifySceneChanged();
1836   TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
1837   ((ColumnArea *)parent())->update();
1838 }
1839 
1840 //----------------------------------------------------------------
1841 
onFilterColorChanged(int id)1842 void ColumnTransparencyPopup::onFilterColorChanged(int id) {
1843   m_column->setFilterColorId((TXshColumn::FilterColor)id);
1844   TApp::instance()->getCurrentScene()->notifySceneChanged();
1845   TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
1846   ((ColumnArea *)parent())->update();
1847 }
1848 
1849 //----------------------------------------------------------------
1850 
setColumn(TXshColumn * column)1851 void ColumnTransparencyPopup::setColumn(TXshColumn *column) {
1852   m_column = column;
1853   assert(m_column);
1854   int val = (int)troundp(100.0 * m_column->getOpacity() / 255.0);
1855   m_slider->setValue(val);
1856   disconnect(m_value, SIGNAL(textChanged(const QString &)), 0, 0);
1857   m_value->setText(QString::number(val));
1858   connect(m_value, SIGNAL(textChanged(const QString &)), this,
1859           SLOT(onValueChanged(const QString &)));
1860 
1861   m_filterColorCombo->setCurrentIndex(m_column->getFilterColorId());
1862 }
1863 
1864 /*void ColumnTransparencyPopup::mouseMoveEvent ( QMouseEvent * e )
1865 {
1866         int val = tcrop((e->pos().x()+10)/(this->width()/(99-1+1)), 1, 99);
1867         m_value->setText(QString::number(val));
1868         m_slider->setValue(val);
1869 }*/
1870 
mouseReleaseEvent(QMouseEvent * e)1871 void ColumnTransparencyPopup::mouseReleaseEvent(QMouseEvent *e) {
1872   // hide();
1873 }
1874 
1875 //------------------------------------------------------------------------------
1876 
SoundColumnPopup(QWidget * parent)1877 SoundColumnPopup::SoundColumnPopup(QWidget *parent)
1878     : QWidget(parent, Qt::Popup) {
1879   setFixedWidth(8 + 78 + 8 + 100 + 8 + 8 + 8 + 7);
1880 
1881   m_slider = new QSlider(Qt::Horizontal, this);
1882   m_slider->setMinimum(0);
1883   m_slider->setMaximum(100);
1884   m_slider->setFixedHeight(14);
1885   m_slider->setFixedWidth(100);
1886 
1887   m_value = new DVGui::IntLineEdit(this, 1, 1, 100);
1888 
1889   QLabel *sliderLabel = new QLabel(tr("Volume:"), this);
1890 
1891   QVBoxLayout *mainLayout = new QVBoxLayout();
1892   mainLayout->setMargin(3);
1893   mainLayout->setSpacing(3);
1894   {
1895     QHBoxLayout *hlayout = new QHBoxLayout;
1896     // hlayout->setContentsMargins(0, 3, 0, 3);
1897     hlayout->setMargin(0);
1898     hlayout->setSpacing(3);
1899     hlayout->addWidget(sliderLabel, 0);
1900     hlayout->addWidget(m_slider);
1901     hlayout->addWidget(m_value);
1902     hlayout->addWidget(new QLabel("%"));
1903     mainLayout->addLayout(hlayout, 0);
1904   }
1905   setLayout(mainLayout);
1906 
1907   bool ret = connect(m_slider, SIGNAL(sliderReleased()), this,
1908                      SLOT(onSliderReleased()));
1909   ret      = ret && connect(m_slider, SIGNAL(sliderMoved(int)), this,
1910                        SLOT(onSliderChange(int)));
1911   ret      = ret && connect(m_slider, SIGNAL(valueChanged(int)), this,
1912                        SLOT(onSliderValueChanged(int)));
1913   ret      = ret && connect(m_value, SIGNAL(textChanged(const QString &)), this,
1914                        SLOT(onValueChanged(const QString &)));
1915   assert(ret);
1916 }
1917 
1918 //----------------------------------------------------------------
1919 
onSliderValueChanged(int val)1920 void SoundColumnPopup::onSliderValueChanged(int val) {
1921   if (m_slider->isSliderDown()) return;
1922   m_value->setText(QString::number(val));
1923   onSliderReleased();
1924 }
1925 
onSliderReleased()1926 void SoundColumnPopup::onSliderReleased() {
1927   int val = m_slider->value();
1928   m_column->getSoundColumn()->setVolume(((double)val / 100.0));
1929   TApp::instance()->getCurrentXsheet()->notifyXsheetSoundChanged();
1930   TApp::instance()->getCurrentScene()->notifySceneChanged();
1931   TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
1932   ((ColumnArea *)parent())->update();
1933 }
1934 
1935 //-----------------------------------------------------------------------
1936 
onSliderChange(int val)1937 void SoundColumnPopup::onSliderChange(int val) {
1938   disconnect(m_value, SIGNAL(textChanged(const QString &)), 0, 0);
1939   m_value->setText(QString::number(val));
1940   connect(m_value, SIGNAL(textChanged(const QString &)), this,
1941           SLOT(onValueChanged(const QString &)));
1942 }
1943 
1944 //----------------------------------------------------------------
1945 
onValueChanged(const QString & str)1946 void SoundColumnPopup::onValueChanged(const QString &str) {
1947   int val = str.toInt();
1948   m_slider->setValue(val);
1949   m_column->getSoundColumn()->setVolume(((double)val / 100.0));
1950 
1951   TApp::instance()->getCurrentXsheet()->notifyXsheetSoundChanged();
1952   TApp::instance()->getCurrentScene()->notifySceneChanged();
1953   TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
1954   ((ColumnArea *)parent())->update();
1955 }
1956 
1957 //----------------------------------------------------------------
1958 
setColumn(TXshColumn * column)1959 void SoundColumnPopup::setColumn(TXshColumn *column) {
1960   m_column = column;
1961   assert(m_column);
1962   double volume = m_column->getSoundColumn()->getVolume();
1963   int val       = (int)troundp(100.0 * volume);
1964   m_slider->setValue(val);
1965   disconnect(m_value, SIGNAL(textChanged(const QString &)), 0, 0);
1966   m_value->setText(QString::number(val));
1967   connect(m_value, SIGNAL(textChanged(const QString &)), this,
1968           SLOT(onValueChanged(const QString &)));
1969 }
1970 
mouseReleaseEvent(QMouseEvent * e)1971 void SoundColumnPopup::mouseReleaseEvent(QMouseEvent *e) {
1972   // hide();
1973 }
1974 
1975 //----------------------------------------------------------------
1976 
openTransparencyPopup()1977 void ColumnArea::openTransparencyPopup() {
1978   if (m_transparencyPopupTimer) m_transparencyPopupTimer->stop();
1979   if (m_col < 0) return;
1980   TXshColumn *column = m_viewer->getXsheet()->getColumn(m_col);
1981   if (!column || column->isEmpty()) return;
1982 
1983   if (!column->isCamstandVisible()) {
1984     column->setCamstandVisible(true);
1985     TApp::instance()->getCurrentScene()->notifySceneChanged();
1986     TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
1987     update();
1988   }
1989 
1990   m_columnTransparencyPopup->setColumn(column);
1991   m_columnTransparencyPopup->show();
1992 }
1993 
openSoundColumnPopup()1994 void ColumnArea::openSoundColumnPopup() {
1995   if (m_col < 0) return;
1996   TXshColumn *column = m_viewer->getXsheet()->getColumn(m_col);
1997   if (!column || column->isEmpty()) return;
1998 
1999   if (!column->isCamstandVisible()) {
2000     column->setCamstandVisible(true);
2001     TApp::instance()->getCurrentXsheet()->notifyXsheetSoundChanged();
2002     TApp::instance()->getCurrentScene()->notifySceneChanged();
2003     TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
2004     update();
2005   }
2006 
2007   m_soundColumnPopup->setColumn(column);
2008   m_soundColumnPopup->show();
2009 }
2010 
openCameraColumnPopup(QPoint pos)2011 void ColumnArea::openCameraColumnPopup(QPoint pos) {
2012   QMenu menu(this);
2013 
2014   TXsheet *xsh           = TApp::instance()->getCurrentXsheet()->getXsheet();
2015   TStageObjectTree *tree = xsh->getStageObjectTree();
2016   int i, objCount = tree->getStageObjectCount();
2017   for (i = 0; i < objCount; i++) {
2018     TStageObject *obj = tree->getStageObject(i);
2019     if (!obj || !obj->getId().isCamera()) continue;
2020     TStageObjectId objId = obj->getId();
2021     std::string objName  = obj->getName();
2022     QAction *action      = new QAction(QString::fromStdString(objName), this);
2023     action->setData(objId.getIndex());
2024     connect(action, SIGNAL(triggered()), this,
2025             SLOT(onCameraColumnChangedTriggered()));
2026     menu.addAction(action);
2027   }
2028 
2029   menu.exec(pos);
2030 }
2031 
onCameraColumnChangedTriggered()2032 void ColumnArea::onCameraColumnChangedTriggered() {
2033   int newIndex = qobject_cast<QAction *>(sender())->data().toInt();
2034   onXsheetCameraChange(newIndex);
2035 }
2036 
2037 //----------------------------------------------------------------
2038 
onXsheetCameraChange(int newIndex)2039 void ColumnArea::onXsheetCameraChange(int newIndex) {
2040   int oldIndex = m_viewer->getXsheet()->getCameraColumnIndex();
2041   if (newIndex == oldIndex) return;
2042 
2043   TXsheetHandle *xsheetHandle = TApp::instance()->getCurrentXsheet();
2044 
2045   CameraColumnSwitchUndo *undo =
2046       new CameraColumnSwitchUndo(oldIndex, newIndex, xsheetHandle);
2047   undo->redo();
2048   TUndoManager::manager()->add(undo);
2049 }
2050 
2051 //----------------------------------------------------------------
2052 
startTransparencyPopupTimer(QMouseEvent * e)2053 void ColumnArea::startTransparencyPopupTimer(QMouseEvent *e) {  // AREA
2054   if (!m_columnTransparencyPopup)
2055     m_columnTransparencyPopup = new ColumnTransparencyPopup(
2056         this);  // Qt::ToolTip|Qt::MSWindowsFixedSizeDialogHint);//Qt::MSWindowsFixedSizeDialogHint|Qt::Tool);
2057 
2058   m_columnTransparencyPopup->move(e->globalPos().x(), e->globalPos().y());
2059 
2060   if (!m_transparencyPopupTimer) {
2061     m_transparencyPopupTimer = new QTimer(this);
2062     bool ret = connect(m_transparencyPopupTimer, SIGNAL(timeout()), this,
2063                        SLOT(openTransparencyPopup()));
2064     assert(ret);
2065     m_transparencyPopupTimer->setSingleShot(true);
2066   }
2067 
2068   m_transparencyPopupTimer->start(300);
2069 }
2070 
2071 //----------------------------------------------------------------
2072 
mousePressEvent(QMouseEvent * event)2073 void ColumnArea::mousePressEvent(QMouseEvent *event) {
2074   const Orientation *o = m_viewer->orientation();
2075 
2076   m_doOnRelease = 0;
2077   m_viewer->setQtModifiers(event->modifiers());
2078   assert(getDragTool() == 0);
2079 
2080   m_col = -1;  // new in 6.4
2081 
2082   // both left and right click can change the selection
2083   if (event->button() == Qt::LeftButton || event->button() == Qt::RightButton) {
2084     TXsheet *xsh   = m_viewer->getXsheet();
2085     ColumnFan *fan = xsh->getColumnFan(o);
2086     m_col          = m_viewer->xyToPosition(event->pos()).layer();
2087     // when clicking the column fan
2088     if (!fan->isActive(m_col))  // column Fan
2089     {
2090       for (auto o : Orientations::all()) {
2091         fan = xsh->getColumnFan(o);
2092         for (int i = m_col; !fan->isActive(i); i--) fan->activate(i);
2093       }
2094 
2095       TApp::instance()->getCurrentScene()->setDirtyFlag(true);
2096       TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
2097       return;
2098     }
2099     // set the clicked column to current
2100     else
2101       m_viewer->setCurrentColumn(m_col);
2102 
2103     TXshColumn *column = xsh->getColumn(m_col);
2104     bool isEmpty       = !column || column->isEmpty();
2105     TApp::instance()->getCurrentObject()->setIsSpline(false);
2106 
2107     // get mouse position
2108     QPoint mouseInCell =
2109         event->pos() - m_viewer->positionToXY(CellPosition(0, m_col));
2110     // int x = event->pos().x() - m_viewer->columnToX(m_col);
2111     // int y = event->pos().y();
2112     // QPoint mouseInCell(x, y);
2113     int x = mouseInCell.x(), y = mouseInCell.y();
2114 
2115     // clicking on the camera column
2116     if (m_col < 0) {
2117       // lock button
2118       if (o->rect(PredefinedRect::CAMERA_LOCK_AREA).contains(mouseInCell) &&
2119           event->button() == Qt::LeftButton)
2120         m_doOnRelease = isCtrlPressed ? ToggleAllLock : ToggleLock;
2121       // config button
2122       else if (o->rect(PredefinedRect::CAMERA_CONFIG_AREA)
2123                    .contains(mouseInCell) &&
2124                event->button() == Qt::LeftButton)
2125         m_doOnRelease = OpenSettings;
2126       // clicking another area means column selection
2127       else {
2128         if (m_viewer->getColumnSelection()->isColumnSelected(m_col) &&
2129             event->button() == Qt::RightButton)
2130           return;
2131         setDragTool(XsheetGUI::DragTool::makeColumnSelectionTool(m_viewer));
2132       }
2133     }
2134     // clicking on the normal columns
2135     else if (!isEmpty) {
2136       // grabbing the left side of the column enables column move
2137       if (o->rect(PredefinedRect::DRAG_LAYER).contains(mouseInCell) ||
2138           (!o->flag(PredefinedFlag::DRAG_LAYER_VISIBLE)  // If dragbar hidden,
2139                                                          // layer name/number
2140                                                          // becomes dragbar
2141            && (o->rect(PredefinedRect::LAYER_NUMBER).contains(mouseInCell) ||
2142                o->rect(PredefinedRect::LAYER_NAME).contains(mouseInCell)))) {
2143         setDragTool(XsheetGUI::DragTool::makeColumnMoveTool(m_viewer));
2144       }
2145       // lock button
2146       else if (o->rect(PredefinedRect::LOCK_AREA).contains(mouseInCell) &&
2147                event->button() == Qt::LeftButton) {
2148         m_doOnRelease = isCtrlPressed ? ToggleAllLock : ToggleLock;
2149       }
2150       // preview button
2151       else if (o->rect(PredefinedRect::EYE_AREA).contains(mouseInCell) &&
2152                event->button() == Qt::LeftButton) {
2153         if (column->getSoundTextColumn()) {
2154           // do nothing
2155         } else {
2156           m_doOnRelease =
2157               isCtrlPressed ? ToggleAllPreviewVisible : TogglePreviewVisible;
2158           if (column->getSoundColumn())
2159             TApp::instance()->getCurrentXsheet()->notifyXsheetSoundChanged();
2160         }
2161       }
2162       // camstand button
2163       else if (o->rect(PredefinedRect::PREVIEW_LAYER_AREA)
2164                    .contains(mouseInCell) &&
2165                event->button() == Qt::LeftButton) {
2166         if (column->getPaletteColumn() || column->getSoundTextColumn()) {
2167           // do nothing
2168         } else {
2169           m_doOnRelease =
2170               isCtrlPressed ? ToggleAllTransparency : ToggleTransparency;
2171           if (!o->flag(PredefinedFlag::CONFIG_AREA_VISIBLE) &&
2172               !column->getSoundColumn())
2173             startTransparencyPopupTimer(event);
2174         }
2175       }
2176       // config button
2177       else if (o->rect(PredefinedRect::CONFIG_AREA).contains(mouseInCell) &&
2178                event->button() == Qt::LeftButton) {
2179         TXshZeraryFxColumn *zColumn =
2180             dynamic_cast<TXshZeraryFxColumn *>(column);
2181 
2182         if (column && (zColumn || column->getPaletteColumn() ||
2183                        column->getSoundTextColumn())) {
2184           // do nothing
2185         } else
2186           m_doOnRelease = OpenSettings;
2187       }
2188       // sound column
2189       else if (column && column->getSoundColumn()) {
2190         if (o->rect(PredefinedRect::SOUND_ICON).contains(mouseInCell)) {
2191           TXshSoundColumn *s = column->getSoundColumn();
2192           if (s) {
2193             if (s->isPlaying())
2194               s->stop();
2195             else {
2196               s->play();
2197               if (!s->isPlaying())
2198                 s->stop();  // Serve per vista, quando le casse non sono
2199                             // attaccate
2200             }
2201             int interval = 0;
2202             if (s->isPlaying()) {
2203               TSoundTrackP sTrack = s->getCurrentPlaySoundTruck();
2204               interval            = sTrack->getDuration() * 1000 + 300;
2205             }
2206             if (s->isPlaying() && interval > 0) {
2207               QTimer::singleShot(interval, this, [this, s] {
2208                 if (s && s->isPlaying()) s->stop();
2209                 update();
2210               });
2211             }
2212           }
2213           update();
2214         } else if (!o->flag(PredefinedFlag::CONFIG_AREA_VISIBLE) &&
2215                    o->rect(PredefinedRect::VOLUME_AREA).contains(mouseInCell))
2216           setDragTool(XsheetGUI::DragTool::makeVolumeDragTool(m_viewer));
2217         else
2218           setDragTool(XsheetGUI::DragTool::makeColumnSelectionTool(m_viewer));
2219       }
2220       // clicking another area means column selection
2221       else {
2222         if (m_viewer->getColumnSelection()->isColumnSelected(m_col) &&
2223             event->button() == Qt::RightButton)
2224           return;
2225 
2226         setDragTool(XsheetGUI::DragTool::makeColumnSelectionTool(m_viewer));
2227 
2228         if (column) {
2229           // toggle columnIcon visibility with alt+click
2230           TXshLevelColumn *levelColumn = column->getLevelColumn();
2231           TXshMeshColumn *meshColumn   = column->getMeshColumn();
2232           if (Preferences::instance()->getColumnIconLoadingPolicy() ==
2233                   Preferences::LoadOnDemand &&
2234               (event->modifiers() & Qt::AltModifier)) {
2235             if (levelColumn)
2236               levelColumn->setIconVisible(!levelColumn->isIconVisible());
2237             else if (meshColumn)
2238               meshColumn->setIconVisible(!meshColumn->isIconVisible());
2239           }
2240         }
2241       }
2242       // update the current fx when zerary fx column is clicked
2243       if (column && column->getZeraryFxColumn()) {
2244         TFx *fx = column->getZeraryFxColumn()->getZeraryColumnFx();
2245         TApp::instance()->getCurrentFx()->setFx(fx);
2246       }
2247     } else {
2248       if (m_viewer->getColumnSelection()->isColumnSelected(m_col) &&
2249           event->button() == Qt::RightButton)
2250         return;
2251       setDragTool(XsheetGUI::DragTool::makeColumnSelectionTool(m_viewer));
2252     }
2253 
2254     m_viewer->dragToolClick(event);
2255     update();
2256 
2257   } else if (event->button() == Qt::MidButton) {
2258     m_pos       = event->pos();
2259     m_isPanning = true;
2260   }
2261 }
2262 
2263 //-----------------------------------------------------------------------------
2264 
mouseMoveEvent(QMouseEvent * event)2265 void ColumnArea::mouseMoveEvent(QMouseEvent *event) {
2266   const Orientation *o = m_viewer->orientation();
2267 
2268   m_viewer->setQtModifiers(event->modifiers());
2269   QPoint pos = event->pos();
2270 
2271   if (m_isPanning) {  // Pan tasto centrale
2272     QPoint delta = m_pos - pos;
2273     if (o->isVerticalTimeline())
2274       delta.setY(0);
2275     else
2276       delta.setX(0);
2277     m_viewer->scroll(delta);
2278     return;
2279   }
2280 
2281   int col = m_viewer->xyToPosition(pos).layer();
2282   if (col < -1) col = 0;
2283   TXsheet *xsh       = m_viewer->getXsheet();
2284   TXshColumn *column = xsh->getColumn(col);
2285   QPoint mouseInCell = pos - m_viewer->positionToXY(CellPosition(0, col));
2286   int x = mouseInCell.x(), y = mouseInCell.y();
2287 
2288 #ifdef LINETEST
2289   // Ensure that the menu of the motion path is hidden
2290   if ((x - m_mtypeBox.left() > 20 || y < m_mtypeBox.y() ||
2291        y > m_mtypeBox.bottom()) &&
2292       !m_motionPathMenu->isHidden())
2293     m_motionPathMenu->hide();
2294 #endif
2295   if ((event->buttons() & Qt::LeftButton) != 0 &&
2296       !visibleRegion().contains(pos)) {
2297     QRect bounds = visibleRegion().boundingRect();
2298     if (o->isVerticalTimeline())
2299       m_viewer->setAutoPanSpeed(bounds, QPoint(pos.x(), bounds.top()));
2300     else
2301       m_viewer->setAutoPanSpeed(bounds, QPoint(bounds.left(), pos.y()));
2302   } else
2303     m_viewer->stopAutoPan();
2304 
2305   m_pos = pos;
2306 
2307   if (event->buttons() && getDragTool()) {
2308     m_viewer->dragToolDrag(event);
2309     update();
2310     return;
2311   }
2312 
2313   // Setto i toolTip
2314   TStageObjectId columnId = m_viewer->getObjectId(col);
2315   TStageObjectId parentId = xsh->getStageObjectParent(columnId);
2316 
2317   if (col < 0)
2318     m_tooltip = tr("Click to select camera");
2319   else if (o->rect(PredefinedRect::DRAG_LAYER).contains(mouseInCell)) {
2320     m_tooltip = tr("Click to select column, drag to move it");
2321   } else if (o->rect(PredefinedRect::LAYER_NUMBER).contains(mouseInCell)) {
2322     if (o->isVerticalTimeline())
2323       m_tooltip = tr("Click to select column, drag to move it");
2324     else
2325       m_tooltip = tr("Click to select column");
2326   } else if (o->rect(PredefinedRect::LAYER_NAME).contains(mouseInCell)) {
2327     if (o->isVerticalTimeline())
2328       m_tooltip =
2329           tr("Click to select column, drag to move it, double-click to edit");
2330     else if (column && column->getSoundColumn()) {
2331       // sound column
2332       if (o->rect(PredefinedRect::SOUND_ICON).contains(mouseInCell))
2333         m_tooltip = tr("Click to play the soundtrack back");
2334       else if (!o->flag(PredefinedFlag::CONFIG_AREA_VISIBLE) &&
2335                o->rect(PredefinedRect::VOLUME_AREA).contains(mouseInCell))
2336         m_tooltip = tr("Set the volume of the soundtrack");
2337     } else
2338       m_tooltip = tr("Click to select column, double-click to edit");
2339   } else if (o->rect(PredefinedRect::LOCK_AREA).contains(mouseInCell)) {
2340     m_tooltip = tr("Lock Toggle");
2341   } else if (o->rect(PredefinedRect::CONFIG_AREA).contains(mouseInCell)) {
2342     m_tooltip = tr("Additional column settings");
2343   } else if (o->rect(PredefinedRect::EYE_AREA).contains(mouseInCell)) {
2344     m_tooltip = tr("Preview Visibility Toggle");
2345   } else if (o->rect(PredefinedRect::PREVIEW_LAYER_AREA)
2346                  .contains(mouseInCell)) {
2347     m_tooltip = tr("Camera Stand Visibility Toggle");
2348   } else {
2349     if (column && column->getSoundColumn()) {
2350       // sound column
2351       if (o->rect(PredefinedRect::SOUND_ICON).contains(mouseInCell))
2352         m_tooltip = tr("Click to play the soundtrack back");
2353       else if (!o->flag(PredefinedFlag::CONFIG_AREA_VISIBLE) &&
2354                o->rect(PredefinedRect::VOLUME_AREA).contains(mouseInCell))
2355         m_tooltip = tr("Set the volume of the soundtrack");
2356     } else if (Preferences::instance()->getColumnIconLoadingPolicy() ==
2357                Preferences::LoadOnDemand)
2358       m_tooltip = tr("Alt + Click to Toggle Thumbnail");
2359     else
2360       m_tooltip = tr("");
2361   }
2362   update();
2363 }
2364 
2365 //-----------------------------------------------------------------------------
2366 
event(QEvent * event)2367 bool ColumnArea::event(QEvent *event) {
2368   if (event->type() == QEvent::ToolTip) {
2369     if (!m_tooltip.isEmpty())
2370       QToolTip::showText(mapToGlobal(m_pos), m_tooltip);
2371     else
2372       QToolTip::hideText();
2373   }
2374   return QWidget::event(event);
2375 }
2376 
2377 //-----------------------------------------------------------------------------
2378 
mouseReleaseEvent(QMouseEvent * event)2379 void ColumnArea::mouseReleaseEvent(QMouseEvent *event) {
2380   TApp *app    = TApp::instance();
2381   TXsheet *xsh = m_viewer->getXsheet();
2382   int col, totcols = xsh->getColumnCount();
2383   if (m_doOnRelease != 0) {
2384     TXshColumn *column = xsh->getColumn(m_col);
2385     if (m_doOnRelease == ToggleTransparency) {
2386       column->setCamstandVisible(!column->isCamstandVisible());
2387       if (column->getSoundColumn())
2388         app->getCurrentXsheet()->notifyXsheetSoundChanged();
2389     } else if (m_doOnRelease == TogglePreviewVisible)
2390       column->setPreviewVisible(!column->isPreviewVisible());
2391     else if (m_doOnRelease == ToggleLock)
2392       column->lock(!column->isLocked());
2393     else if (m_doOnRelease == OpenSettings) {
2394       QPoint pos = event->pos();
2395       int col    = m_viewer->xyToPosition(pos).layer();
2396       // Align popup to be below to CONFIG button
2397       QRect configRect = m_viewer->orientation()->rect(
2398           (col < 0) ? PredefinedRect::CAMERA_CONFIG_AREA
2399                     : PredefinedRect::CONFIG_AREA);
2400       CellPosition cellPosition(0, col);
2401       QPoint topLeft     = m_viewer->positionToXY(cellPosition);
2402       QPoint mouseInCell = pos - topLeft;
2403       int x              = configRect.left() - mouseInCell.x() +
2404               1;  // distance from right edge of CONFIG button
2405       int y =
2406           mouseInCell.y() -
2407           configRect.bottom();  // distance from bottum edge of CONFIG button
2408 
2409       if (col < 0) {
2410         openCameraColumnPopup(
2411             QPoint(event->globalPos().x() + x, event->globalPos().y() - y));
2412       } else if (column->getSoundColumn()) {
2413         if (!m_soundColumnPopup)
2414           m_soundColumnPopup = new SoundColumnPopup(this);
2415 
2416         m_soundColumnPopup->move(event->globalPos().x() + x,
2417                                  event->globalPos().y() - y);
2418 
2419         openSoundColumnPopup();
2420       } else {
2421         if (!m_columnTransparencyPopup)
2422           m_columnTransparencyPopup = new ColumnTransparencyPopup(this);
2423 
2424         m_columnTransparencyPopup->move(event->globalPos().x() + x,
2425                                         event->globalPos().y() - y);
2426 
2427         // make sure the popup doesn't go off the screen to the right
2428         QDesktopWidget *desktop = qApp->desktop();
2429         QRect screenRect        = desktop->screenGeometry(app->getMainWindow());
2430 
2431         int popupLeft  = event->globalPos().x() + x;
2432         int popupRight = popupLeft + m_columnTransparencyPopup->width();
2433 
2434         // first condition checks if popup is on same monitor as main app;
2435         // if popup is on different monitor, leave as is
2436         if (popupLeft < screenRect.right() && popupRight > screenRect.right()) {
2437           int distance = popupRight - screenRect.right();
2438           m_columnTransparencyPopup->move(
2439               m_columnTransparencyPopup->x() - distance,
2440               m_columnTransparencyPopup->y());
2441         }
2442 
2443         openTransparencyPopup();
2444       }
2445     } else if (m_doOnRelease == ToggleAllPreviewVisible) {
2446       for (col = 0; col < totcols; col++) {
2447         TXshColumn *column = xsh->getColumn(col);
2448         if (!xsh->isColumnEmpty(col) && !column->getPaletteColumn() &&
2449             !column->getSoundTextColumn()) {
2450           column->setPreviewVisible(!column->isPreviewVisible());
2451         }
2452       }
2453     } else if (m_doOnRelease == ToggleAllTransparency) {
2454       bool sound_changed = false;
2455       for (col = 0; col < totcols; col++) {
2456         TXshColumn *column = xsh->getColumn(col);
2457         if (!xsh->isColumnEmpty(col) && !column->getPaletteColumn() &&
2458             !column->getSoundTextColumn()) {
2459           column->setCamstandVisible(!column->isCamstandVisible());
2460           if (column->getSoundColumn()) sound_changed = true;
2461         }
2462       }
2463 
2464       if (sound_changed) {
2465         app->getCurrentXsheet()->notifyXsheetSoundChanged();
2466       }
2467     } else if (m_doOnRelease == ToggleAllLock) {
2468       int startCol =
2469           Preferences::instance()->isXsheetCameraColumnVisible() ? -1 : 0;
2470       for (col = startCol; col < totcols; col++) {
2471         TXshColumn *column = xsh->getColumn(col);
2472         if (!xsh->isColumnEmpty(col)) {
2473           column->lock(!column->isLocked());
2474         }
2475       }
2476     } else
2477       assert(false);
2478 
2479     app->getCurrentScene()->notifySceneChanged();
2480     // signal XsheetChanged will invoke PreviewFxManager to all rendered frames,
2481     // if necessary. it causes slowness when opening preview flipbook of large
2482     // scene.
2483     bool isTransparencyRendered = app->getCurrentScene()
2484                                       ->getScene()
2485                                       ->getProperties()
2486                                       ->isColumnColorFilterOnRenderEnabled();
2487     if ((isTransparencyRendered && (m_doOnRelease == ToggleTransparency ||
2488                                     m_doOnRelease == ToggleAllTransparency ||
2489                                     m_doOnRelease == OpenSettings)) ||
2490         m_doOnRelease == TogglePreviewVisible ||
2491         m_doOnRelease == ToggleAllPreviewVisible)
2492       app->getCurrentXsheet()->notifyXsheetChanged();
2493     update();
2494     m_doOnRelease = 0;
2495   }
2496 
2497   if (m_transparencyPopupTimer) m_transparencyPopupTimer->stop();
2498 
2499   m_viewer->setQtModifiers(0);
2500   m_viewer->dragToolRelease(event);
2501   m_isPanning = false;
2502   m_viewer->stopAutoPan();
2503 }
2504 
2505 //-----------------------------------------------------------------------------
2506 
mouseDoubleClickEvent(QMouseEvent * event)2507 void ColumnArea::mouseDoubleClickEvent(QMouseEvent *event) {
2508   const Orientation *o = m_viewer->orientation();
2509 
2510   QPoint pos = event->pos();
2511   int col    = m_viewer->xyToPosition(pos).layer();
2512   CellPosition cellPosition(0, col);
2513   QPoint topLeft     = m_viewer->positionToXY(cellPosition);
2514   QPoint mouseInCell = pos - topLeft;
2515 
2516   QRect nameRect = o->rect((col < 0) ? PredefinedRect::CAMERA_LAYER_NAME
2517                                      : PredefinedRect::LAYER_NAME);
2518   if (!nameRect.contains(mouseInCell)) return;
2519 
2520   TXsheet *xsh = m_viewer->getXsheet();
2521   if (col >= 0 && xsh->isColumnEmpty(col)) return;
2522 
2523   QPoint fieldPos =
2524       (col < 0 && o->isVerticalTimeline()) ? nameRect.topLeft() : topLeft;
2525   QRect renameRect =
2526       o->rect(PredefinedRect::RENAME_COLUMN).translated(fieldPos);
2527   m_renameColumnField->show(renameRect, col);
2528 }
2529 
2530 //-----------------------------------------------------------------------------
2531 
contextMenuEvent(QContextMenuEvent * event)2532 void ColumnArea::contextMenuEvent(QContextMenuEvent *event) {
2533 #ifndef _WIN32
2534   /* On windows the widget receive the release event before the menu
2535      is shown, on linux and osx the release event is lost, never
2536      received by the widget */
2537   QMouseEvent fakeRelease(QEvent::MouseButtonRelease, event->pos(),
2538                           Qt::RightButton, Qt::NoButton, Qt::NoModifier);
2539 
2540   QApplication::instance()->sendEvent(this, &fakeRelease);
2541 #endif
2542   const Orientation *o = m_viewer->orientation();
2543 
2544   int col = m_viewer->xyToPosition(event->pos()).layer();
2545 
2546   bool isCamera = col < 0;
2547 
2548   m_viewer->setCurrentColumn(col);
2549   TXsheet *xsh       = m_viewer->getXsheet();
2550   QPoint topLeft     = m_viewer->positionToXY(CellPosition(0, col));
2551   QPoint mouseInCell = event->pos() - topLeft;
2552 
2553   QMenu menu(this);
2554   CommandManager *cmdManager = CommandManager::instance();
2555 
2556   //---- Preview
2557   if (((isCamera && !o->isVerticalTimeline()) || !xsh->isColumnEmpty(col)) &&
2558       o->rect(PredefinedRect::EYE_AREA).contains(mouseInCell)) {
2559     menu.setObjectName("xsheetColumnAreaMenu_Preview");
2560 
2561     menu.addAction(cmdManager->getAction("MI_EnableThisColumnOnly"));
2562     menu.addAction(cmdManager->getAction("MI_EnableSelectedColumns"));
2563     menu.addAction(cmdManager->getAction("MI_EnableAllColumns"));
2564     menu.addAction(cmdManager->getAction("MI_DisableAllColumns"));
2565     menu.addAction(cmdManager->getAction("MI_DisableSelectedColumns"));
2566     menu.addAction(cmdManager->getAction("MI_SwapEnabledColumns"));
2567   }
2568   //---- Lock
2569   else if ((isCamera || !xsh->isColumnEmpty(col)) &&
2570            o->rect((isCamera) ? PredefinedRect::CAMERA_LOCK_AREA
2571                               : PredefinedRect::LOCK_AREA)
2572                .contains(mouseInCell)) {
2573     menu.setObjectName("xsheetColumnAreaMenu_Lock");
2574 
2575     menu.addAction(cmdManager->getAction("MI_LockThisColumnOnly"));
2576     menu.addAction(cmdManager->getAction("MI_LockSelectedColumns"));
2577     menu.addAction(cmdManager->getAction("MI_LockAllColumns"));
2578     menu.addAction(cmdManager->getAction("MI_UnlockSelectedColumns"));
2579     menu.addAction(cmdManager->getAction("MI_UnlockAllColumns"));
2580     menu.addAction(cmdManager->getAction("MI_ToggleColumnLocks"));
2581   }
2582   //---- Camstand
2583   else if (((isCamera && !o->isVerticalTimeline()) ||
2584             !xsh->isColumnEmpty(col)) &&
2585            o->rect(PredefinedRect::PREVIEW_LAYER_AREA).contains(mouseInCell)) {
2586     menu.setObjectName("xsheetColumnAreaMenu_Camstand");
2587 
2588     menu.addAction(cmdManager->getAction("MI_ActivateThisColumnOnly"));
2589     menu.addAction(cmdManager->getAction("MI_ActivateSelectedColumns"));
2590     menu.addAction(cmdManager->getAction("MI_ActivateAllColumns"));
2591     menu.addAction(cmdManager->getAction("MI_DeactivateAllColumns"));
2592     menu.addAction(cmdManager->getAction("MI_DeactivateSelectedColumns"));
2593     menu.addAction(cmdManager->getAction("MI_ToggleColumnsActivation"));
2594     // hide all columns placed on the left
2595     menu.addAction(cmdManager->getAction("MI_DeactivateUpperColumns"));
2596   }
2597   // right clicking another area / right clicking empty column head
2598   else {
2599     if (!isCamera) {
2600       int r0, r1;
2601       xsh->getCellRange(col, r0, r1);
2602       TXshCell cell = xsh->getCell(r0, col);
2603       menu.addAction(cmdManager->getAction(MI_Cut));
2604       menu.addAction(cmdManager->getAction(MI_Copy));
2605       menu.addAction(cmdManager->getAction(MI_Paste));
2606       menu.addAction(cmdManager->getAction(MI_PasteAbove));
2607       menu.addAction(cmdManager->getAction(MI_Clear));
2608       menu.addAction(cmdManager->getAction(MI_Insert));
2609       menu.addAction(cmdManager->getAction(MI_InsertAbove));
2610       menu.addSeparator();
2611       menu.addAction(cmdManager->getAction(MI_InsertFx));
2612       menu.addAction(cmdManager->getAction(MI_NewNoteLevel));
2613       menu.addAction(cmdManager->getAction(MI_RemoveEmptyColumns));
2614       menu.addSeparator();
2615       if (m_viewer->getXsheet()->isColumnEmpty(col) ||
2616           (cell.m_level && cell.m_level->getChildLevel()))
2617         menu.addAction(cmdManager->getAction(MI_OpenChild));
2618 
2619       // Close sub xsheet and move to parent sheet
2620       ToonzScene *scene      = TApp::instance()->getCurrentScene()->getScene();
2621       ChildStack *childStack = scene->getChildStack();
2622       if (childStack && childStack->getAncestorCount() > 0) {
2623         menu.addAction(cmdManager->getAction(MI_CloseChild));
2624       }
2625 
2626       menu.addAction(cmdManager->getAction(MI_Collapse));
2627       if (cell.m_level && cell.m_level->getChildLevel()) {
2628         menu.addAction(cmdManager->getAction(MI_Resequence));
2629         menu.addAction(cmdManager->getAction(MI_CloneChild));
2630         menu.addAction(cmdManager->getAction(MI_ExplodeChild));
2631       }
2632       menu.addSeparator();
2633     }
2634     menu.addAction(cmdManager->getAction(MI_FoldColumns));
2635     if (Preferences::instance()->isShowKeyframesOnXsheetCellAreaEnabled()) {
2636       QAction *cameraToggle =
2637           cmdManager->getAction(MI_ToggleXsheetCameraColumn);
2638       bool cameraVisible =
2639           Preferences::instance()->isXsheetCameraColumnVisible();
2640       if (cameraVisible)
2641         cameraToggle->setText(tr("Hide Camera Column"));
2642       else
2643         cameraToggle->setText(tr("Show Camera Column"));
2644       menu.addAction(cameraToggle);
2645     }
2646     menu.addSeparator();
2647     menu.addAction(cmdManager->getAction(MI_ToggleXSheetToolbar));
2648 
2649     if (isCamera) {
2650       menu.exec(event->globalPos());
2651       return;
2652     }
2653 
2654     // force the selected cells placed in n-steps
2655     if (!xsh->isColumnEmpty(col)) {
2656       menu.addSeparator();
2657       QMenu *reframeSubMenu = new QMenu(tr("Reframe"), this);
2658       {
2659         reframeSubMenu->addAction(cmdManager->getAction(MI_Reframe1));
2660         reframeSubMenu->addAction(cmdManager->getAction(MI_Reframe2));
2661         reframeSubMenu->addAction(cmdManager->getAction(MI_Reframe3));
2662         reframeSubMenu->addAction(cmdManager->getAction(MI_Reframe4));
2663         reframeSubMenu->addAction(
2664             cmdManager->getAction(MI_ReframeWithEmptyInbetweens));
2665       }
2666       menu.addMenu(reframeSubMenu);
2667       menu.addAction(cmdManager->getAction(MI_AutoInputCellNumber));
2668     }
2669 
2670     if (containsRasterLevel(m_viewer->getColumnSelection())) {
2671       QMenu *subsampleSubMenu = new QMenu(tr("Subsampling"), this);
2672       {
2673         subsampleSubMenu->addAction(m_subsampling1);
2674         subsampleSubMenu->addAction(m_subsampling2);
2675         subsampleSubMenu->addAction(m_subsampling3);
2676         subsampleSubMenu->addAction(m_subsampling4);
2677       }
2678       menu.addMenu(subsampleSubMenu);
2679     }
2680 
2681     if (!xsh->isColumnEmpty(col)) {
2682       menu.addAction(cmdManager->getAction(MI_ReplaceLevel));
2683       menu.addAction(cmdManager->getAction(MI_ReplaceParentDirectory));
2684 
2685       // if (containsVectorLevel(col)) {
2686       //  menu.addSeparator();
2687       //  QAction *setMask =
2688       //      new QAction(tr("Temporary Mask (Not in final render)"), this);
2689       //  setMask->setCheckable(true);
2690       //  setMask->setChecked(xsh->getColumn(col)->isMask());
2691       //  setMask->setToolTip(
2692       //      tr("Only Toonz Vector levels can be used as masks. \n Masks don't
2693       //      "
2694       //         "show up in final renders."));
2695       //  bool ret = true;
2696       //  ret      = ret &&
2697       //        connect(setMask, &QAction::toggled, [=]() { onSetMask(col); });
2698       //  assert(ret);
2699       //  menu.addAction(setMask);
2700       //}
2701     }
2702   }
2703 
2704   QAction *act  = cmdManager->getAction(MI_Insert),
2705           *act2 = cmdManager->getAction(MI_InsertAbove),
2706           *act3 = cmdManager->getAction(MI_Paste),
2707           *act4 = cmdManager->getAction(MI_PasteAbove);
2708 
2709   QString actText = act->text(), act2Text = act2->text(),
2710           act3Text = act3->text(), act4Text = act4->text();
2711 
2712   if (o->isVerticalTimeline()) {
2713     act->setText(tr("&Insert Before"));
2714     act2->setText(tr("&Insert After"));
2715     act3->setText(tr("&Paste Insert Before"));
2716     act4->setText(tr("&Paste Insert After"));
2717   } else {
2718     act->setText(tr("&Insert Below"));
2719     act2->setText(tr("&Insert Above"));
2720     act3->setText(tr("&Paste Insert Below"));
2721     act4->setText(tr("&Paste Insert Above"));
2722   }
2723 
2724   menu.exec(event->globalPos());
2725 
2726   act->setText(actText);
2727   act2->setText(act2Text);
2728   act3->setText(act3Text);
2729   act4->setText(act4Text);
2730 }
2731 
2732 //-----------------------------------------------------------------------------
2733 
onSetMask(int col)2734 void ColumnArea::onSetMask(int col) {
2735   TXshColumn *column = m_viewer->getXsheet()->getColumn(m_col);
2736 
2737   std::string name = m_viewer->getXsheet()
2738                          ->getStageObject(TStageObjectId::ColumnId(col))
2739                          ->getName();
2740   ColumnMaskUndo *undo = new ColumnMaskUndo(col, column->isMask(), name);
2741   undo->redo();
2742   TUndoManager::manager()->add(undo);
2743   update();
2744 }
2745 
2746 //-----------------------------------------------------------------------------
2747 
onSubSampling(QAction * action)2748 void ColumnArea::onSubSampling(QAction *action) {
2749   int subsampling;
2750   if (action == m_subsampling1)
2751     subsampling = 1;
2752   else if (action == m_subsampling2)
2753     subsampling = 2;
2754   else if (action == m_subsampling3)
2755     subsampling = 3;
2756   else if (action == m_subsampling4)
2757     subsampling = 4;
2758 
2759   TColumnSelection *selection = m_viewer->getColumnSelection();
2760   TXsheet *xsh                = m_viewer->getXsheet();
2761   assert(selection && xsh);
2762   const std::set<int> indexes = selection->getIndices();
2763   for (auto const &e : indexes) {
2764     if (e < 0) continue;  // Ignore camera column
2765     TXshColumn *column          = xsh->getColumn(e);
2766     TXshColumn::ColumnType type = column->getColumnType();
2767     if (type != TXshColumn::eLevelType) continue;
2768     const QSet<TXshSimpleLevel *> levels = getLevels(column);
2769     QSet<TXshSimpleLevel *>::const_iterator it2;
2770     for (it2 = levels.begin(); it2 != levels.end(); it2++) {
2771       TXshSimpleLevel *sl = *it2;
2772       if (sl->getProperties()->getDirtyFlag()) continue;
2773       int type = sl->getType();
2774       if (type == TZI_XSHLEVEL || type == TZP_XSHLEVEL ||
2775           type == OVL_XSHLEVEL) {
2776         sl->getProperties()->setSubsampling(subsampling);
2777         sl->invalidateFrames();
2778       }
2779     }
2780   }
2781   TApp::instance()
2782       ->getCurrentXsheet()
2783       ->getXsheet()
2784       ->getStageObjectTree()
2785       ->invalidateAll();
2786   TApp::instance()->getCurrentScene()->notifySceneChanged();
2787 }
2788 }  // namespace XsheetGUI
2789