1
2
3 #include "toonzqt/functionsheet.h"
4
5 // TnzQt includes
6 #include "toonzqt/gutil.h"
7 #include "toonzqt/functionviewer.h"
8
9 // TnzLib includes
10 #include "toonz/tframehandle.h"
11 #include "toonz/doubleparamcmd.h"
12 #include "toonz/preferences.h"
13 #include "toonz/toonzfolders.h"
14 #include "toonz/tstageobject.h"
15 #include "toonz/txsheethandle.h"
16 #include "toonz/txsheet.h"
17
18 // TnzBase includes
19 #include "tunit.h"
20
21 #include "../toonz/menubarcommandids.h"
22
23 // Qt includes
24 #include <QPainter>
25 #include <QGridLayout>
26 #include <QPaintEvent>
27 #include <QMenu>
28 #include <QApplication> //for drag&drop
29 #include <QDrag>
30
31 //********************************************************************************
32 // Local namespace stuff
33 //********************************************************************************
34
35 namespace {
36
37 const int cColumnDragHandleWidth = 8;
38
39 const int cGroupShortNameY =
40 0; //!< Column header's y pos for channel groups' short name tabs
41 const int cGroupLongNameY = 27; //!< Same for its long name tabs
42 const int cChannelNameY = 50; //!< Column header's y pos of channel name tabs,
43 //! up to the widget's height
44 const int cColHeadersEndY = 87; //!< End of column headers y pos
45
46 } // namespace
47
48 //********************************************************************************
49 // Function Sheet Tools
50 //********************************************************************************
51
52 /*--- NumericalColumnsのセグメントの左側のバーをクリックしたとき ---*/
53 class MoveChannelsDragTool final : public Spreadsheet::DragTool {
54 FunctionSheet *m_sheet;
55 std::vector<KeyframeSetter *> m_setters;
56 int m_oldRow;
57 QRect m_selectedCells;
58 int m_firstKeyframeRow;
59
60 public:
MoveChannelsDragTool(FunctionSheet * sheet)61 MoveChannelsDragTool(FunctionSheet *sheet)
62 : m_sheet(sheet), m_firstKeyframeRow(-1) {}
63
click(int row,int col,QMouseEvent * e)64 void click(int row, int col, QMouseEvent *e) override {
65 m_firstKeyframeRow = -1;
66 FunctionTreeModel::Channel *channel = m_sheet->getChannel(col);
67 if (!channel) return;
68 TDoubleParam *curve = channel->getParam();
69 int k0 = -1, k1 = -1;
70 if (curve->isKeyframe(row))
71 k0 = k1 = curve->getClosestKeyframe(row);
72 else {
73 k0 = curve->getPrevKeyframe(row);
74 k1 = curve->getNextKeyframe(row);
75 }
76 // return if clicking outside of the segments
77 if (k0 < 0 || k1 < 0) return;
78 int r0 = tround(curve->keyframeIndexToFrame(k0));
79 int r1 = tround(curve->keyframeIndexToFrame(k1));
80 if (m_sheet->isSelectedCell(row, col)) {
81 m_selectedCells = m_sheet->getSelectedCells();
82 m_selectedCells.setTop(r0);
83 m_selectedCells.setBottom(r1);
84 } else
85 m_selectedCells = QRect(col, r0, 1, r1 - r0 + 1);
86
87 m_sheet->selectCells(m_selectedCells);
88
89 /*---
90 シンプルに左のバーをクリックした場合はcolは1つだけ。
91 すでに複数Columnが選択されている上でその選択範囲内のセルの左バーをクリックした場合は
92 横(Column)幅は選択範囲に順ずるようになる。高さ(row)はクリックしたセグメントと同じになる。
93 ---*/
94 /*--- セグメントごとドラッグに備えてKeyFrameを格納する ---*/
95 for (int col = m_selectedCells.left(); col <= m_selectedCells.right();
96 ++col) {
97 TDoubleParam *curve = m_sheet->getCurve(col);
98 if (!curve) continue;
99 KeyframeSetter *setter = new KeyframeSetter(curve);
100 for (int k = 0; k < curve->getKeyframeCount(); k++) {
101 int row = (int)curve->keyframeIndexToFrame(k);
102 if (r0 <= row && row <= r1) {
103 if (m_firstKeyframeRow < 0 || row < m_firstKeyframeRow)
104 m_firstKeyframeRow = row;
105 setter->selectKeyframe(k);
106 }
107 }
108 m_setters.push_back(setter);
109 }
110 m_oldRow = row;
111 }
112
drag(int row,int col,QMouseEvent * e)113 void drag(int row, int col, QMouseEvent *e) override {
114 int d = row - m_oldRow;
115 m_oldRow = row;
116 if (d + m_firstKeyframeRow < 0) d = -m_firstKeyframeRow;
117 m_firstKeyframeRow += d;
118 for (int i = 0; i < (int)m_setters.size(); i++)
119 m_setters[i]->moveKeyframes(d, 0.0);
120 m_selectedCells.translate(0, d);
121 m_sheet->selectCells(m_selectedCells);
122 }
123
release(int row,int col,QMouseEvent * e)124 void release(int row, int col, QMouseEvent *e) override {
125 for (int i = 0; i < (int)m_setters.size(); i++) delete m_setters[i];
126 m_setters.clear();
127 }
128 };
129
130 //-----------------------------------------------------------------------------
131 /*--- NumericalColumnsのセル部分をクリックしたとき ---*/
132 class FunctionSheetSelectionTool final : public Spreadsheet::DragTool {
133 int m_firstRow, m_firstCol;
134 FunctionSheet *m_sheet;
135
136 public:
FunctionSheetSelectionTool(FunctionSheet * sheet)137 FunctionSheetSelectionTool(FunctionSheet *sheet)
138 : m_sheet(sheet), m_firstRow(-1), m_firstCol(-1) {}
139
click(int row,int col,QMouseEvent * e)140 void click(int row, int col, QMouseEvent *e) override {
141 if (0 != (e->modifiers() & Qt::ShiftModifier) &&
142 !m_sheet->getSelectedCells().isEmpty()) {
143 QRect selectedCells = m_sheet->getSelectedCells();
144 if (col < selectedCells.center().x()) {
145 m_firstCol = selectedCells.right();
146 selectedCells.setLeft(col);
147 } else {
148 m_firstCol = selectedCells.left();
149 selectedCells.setRight(col);
150 }
151 if (row < selectedCells.center().y()) {
152 m_firstRow = selectedCells.bottom();
153 selectedCells.setTop(row);
154 } else {
155 m_firstRow = selectedCells.top();
156 selectedCells.setBottom(row);
157 }
158 m_sheet->selectCells(selectedCells);
159 } else {
160 // regular click, no shift
161 m_firstCol = col;
162 m_firstRow = row;
163 QRect selectedCells(col, row, 1, 1);
164 m_sheet->selectCells(selectedCells);
165 }
166 }
167
drag(int row,int col,QMouseEvent * e)168 void drag(int row, int col, QMouseEvent *e) override {
169 if (row < 0) row = 0;
170 if (col < 0) col = 0;
171 int r0 = std::min(row, m_firstRow);
172 int r1 = std::max(row, m_firstRow);
173 int c0 = std::min(col, m_firstCol);
174 int c1 = std::max(col, m_firstCol);
175 QRect selectedCells(c0, r0, c1 - c0 + 1, r1 - r0 + 1);
176 m_sheet->selectCells(selectedCells);
177 }
178
release(int row,int col,QMouseEvent * e)179 void release(int row, int col, QMouseEvent *e) override {
180 if (row == m_firstRow && col == m_firstCol) {
181 if (Preferences::instance()->isMoveCurrentEnabled())
182 m_sheet->setCurrentFrame(row);
183 FunctionTreeModel::Channel *channel = m_sheet->getChannel(col);
184 if (channel) channel->setIsCurrent(true);
185 }
186 }
187 };
188
189 //********************************************************************************
190 // FunctionSheetRowViewer implementation
191 //********************************************************************************
192
FunctionSheetRowViewer(FunctionSheet * parent)193 FunctionSheetRowViewer::FunctionSheetRowViewer(FunctionSheet *parent)
194 : Spreadsheet::RowPanel(parent), m_sheet(parent) {
195 setMinimumSize(QSize(100, 100));
196 setMouseTracking(true);
197 setFocusPolicy(Qt::NoFocus);
198 }
199
200 //-----------------------------------------------------------------------------
201
paintEvent(QPaintEvent * e)202 void FunctionSheetRowViewer::paintEvent(QPaintEvent *e) {
203 // calls GenericPanel's event
204 Spreadsheet::RowPanel::paintEvent(e);
205 }
206
207 //-----------------------------------------------------------------------------
208
mousePressEvent(QMouseEvent * e)209 void FunctionSheetRowViewer::mousePressEvent(QMouseEvent *e) {
210 // calls GenericPanel's event
211 Spreadsheet::RowPanel::mousePressEvent(e);
212 }
213
214 //-----------------------------------------------------------------------------
215
mouseMoveEvent(QMouseEvent * e)216 void FunctionSheetRowViewer::mouseMoveEvent(QMouseEvent *e) {
217 // calls GenericPanel's event
218 Spreadsheet::RowPanel::mouseMoveEvent(e);
219 }
220
221 //-----------------------------------------------------------------------------
222
mouseReleaseEvent(QMouseEvent * e)223 void FunctionSheetRowViewer::mouseReleaseEvent(QMouseEvent *e) {
224 Spreadsheet::RowPanel::mouseReleaseEvent(e);
225 }
226
227 //-----------------------------------------------------------------------------
228
contextMenuEvent(QContextMenuEvent * event)229 void FunctionSheetRowViewer::contextMenuEvent(QContextMenuEvent *event) {
230 QMenu *menu = new QMenu(this);
231 CommandManager *cmdManager = CommandManager::instance();
232 menu->addAction(cmdManager->getAction(MI_InsertSceneFrame));
233 menu->addAction(cmdManager->getAction(MI_RemoveSceneFrame));
234 menu->addAction(cmdManager->getAction(MI_InsertGlobalKeyframe));
235 menu->addAction(cmdManager->getAction(MI_RemoveGlobalKeyframe));
236 menu->exec(event->globalPos());
237 }
238
239 //********************************************************************************
240 // FunctionSheetColumnHeadViewer implementation
241 //********************************************************************************
242
FunctionSheetColumnHeadViewer(FunctionSheet * parent)243 FunctionSheetColumnHeadViewer::FunctionSheetColumnHeadViewer(
244 FunctionSheet *parent)
245 : Spreadsheet::ColumnPanel(parent), m_sheet(parent), m_draggingChannel(0) {
246 setMouseTracking(true); // for updating the tooltip
247 setFocusPolicy(Qt::NoFocus);
248 }
249
250 //-----------------------------------------------------------------------------
251
paintEvent(QPaintEvent * e)252 void FunctionSheetColumnHeadViewer::paintEvent(QPaintEvent *e) {
253 QPainter painter(this);
254
255 QRect toBeUpdated = e->rect();
256 painter.setClipRect(toBeUpdated);
257
258 // visible columns range
259 CellRange visible = getViewer()->xyRectToRange(toBeUpdated);
260 int c0 = visible.from().layer();
261 int c1 = visible.to().layer();
262
263 if (c0 > c1) return;
264
265 int n = c1 - c0 + 1 + 2;
266
267 FunctionTreeModel::ChannelGroup *currentGroup = 0;
268
269 /*--- Display range + right and left 1 column range ChannelGroup. If there is
270 * none, put 0
271 * ---*/
272 std::vector<FunctionTreeModel::ChannelGroup *> channelGroups(n);
273 for (int i = 0; i < n; ++i) {
274 channelGroups[i] = 0;
275
276 int c = c0 - 1 + i;
277 if (c < 0) continue;
278
279 FunctionTreeModel::Channel *channel = m_sheet->getChannel(c);
280 if (!channel) continue;
281
282 channelGroups[i] = channel->getChannelGroup();
283 if (!currentGroup && channel->isCurrent()) currentGroup = channelGroups[i];
284 }
285
286 int y0 = 0;
287 int y1 = 17; // needs work
288 int y2 = 34;
289 int y3 = 53;
290
291 /*--- Fill header with background color ---*/
292 for (int c = c0; c <= c1; c++) {
293 FunctionTreeModel::Channel *channel = m_sheet->getChannel(c);
294 if (!channel) break;
295 int x0 = getViewer()->columnToX(c);
296 int x1 = getViewer()->columnToX(c + 1) - 1;
297 // Column Width
298 int width = x1 - x0 + 1;
299
300 painter.fillRect(x0, y0, width, y3 - y0, getViewer()->getBGColor());
301 }
302
303 for (int c = c0; c <= c1; ++c) {
304 FunctionTreeModel::Channel *channel = m_sheet->getChannel(c);
305 if (!channel) {
306 if (c != c0) {
307 // draw "the end" border
308 int x0 = getViewer()->columnToX(c);
309 painter.setPen(getViewer()->getColumnHeaderBorderColor());
310 painter.drawLine(x0, y0, x0, y3);
311 }
312 break;
313 }
314 int i = c - c0 + 1;
315 /*---- Channel Column of the current Column and the preceding and following
316 * Columns ---*/
317 FunctionTreeModel::ChannelGroup *prevGroup = channelGroups[c - c0],
318 *group = channelGroups[c - c0 + 1],
319 *nextGroup = channelGroups[c - c0 + 2];
320
321 /*---- If the group is different from the before and after, flags are set
322 * respectively ---*/
323 bool firstGroupColumn = prevGroup != group;
324 bool lastGroupColumn = nextGroup != group;
325
326 /*--- The left and right coordinates of the current column ---*/
327 int x0 = getViewer()->columnToX(c);
328 int x1 = getViewer()->columnToX(c + 1) - 1;
329 // Column width
330 int width = x1 - x0 + 1;
331
332 QRect selectedRect = m_sheet->getSelectedCells();
333 bool isSelected =
334 (selectedRect.left() <= c && c <= selectedRect.right()) ? true : false;
335
336 // paint with light color if selected
337 if (isSelected)
338 painter.fillRect(x0, y1, width, y3 - y1,
339 getViewer()->getCurrentRowBgColor());
340
341 // draw horizonntal lines
342 painter.setPen(QPen(getViewer()->getColumnHeaderBorderColor(), 3));
343 painter.drawLine(x0, y0, x1, y0);
344 painter.setPen(getViewer()->getColumnHeaderBorderColor());
345 painter.drawLine(x0, y1, x1, y1);
346
347 // draw vertical bar
348 painter.fillRect(x0, y1, 6, y3 - y1,
349 getViewer()->getColumnHeaderBorderColor());
350 if (firstGroupColumn)
351 painter.fillRect(x0, y0, 6, y1 - y0,
352 getViewer()->getColumnHeaderBorderColor());
353
354 // channel name
355 painter.setPen(getViewer()->getTextColor());
356 if (channel->isCurrent())
357 painter.setPen(m_sheet->getViewer()->getCurrentTextColor());
358
359 QString text = channel->getShortName();
360 int d = 8;
361 painter.drawText(x0 + d, y1, width - d, y3 - y1 + 1,
362 Qt::TextWrapAnywhere | Qt::AlignLeft | Qt::AlignVCenter,
363 text);
364
365 // warning of losing expression reference
366 TXsheet *xsh = m_sheet->getViewer()->getXsheetHandle()->getXsheet();
367 if (xsh->isReferenceManagementIgnored(channel->getParam())) {
368 static QIcon paramIgnoredIcon(":Resources/paramignored_on.svg");
369 painter.drawPixmap(QPoint(x0 + 30, y1 + 20),
370 paramIgnoredIcon.pixmap(21, 17));
371 }
372
373 // group name
374 if (firstGroupColumn) {
375 int tmpwidth = (lastGroupColumn) ? width : width * 2;
376 painter.setPen(getViewer()->getTextColor());
377 if (group == currentGroup)
378 painter.setPen(m_sheet->getViewer()->getCurrentTextColor());
379 text = group->getShortName();
380 painter.drawText(x0 + d, y0, tmpwidth - d, y1 - y0 + 1,
381 Qt::AlignLeft | Qt::AlignVCenter, text);
382 }
383 }
384 }
385
386 //-----------------------------------------------------------------------------
387 /*! update tooltips
388 */
mouseMoveEvent(QMouseEvent * e)389 void FunctionSheetColumnHeadViewer::mouseMoveEvent(QMouseEvent *e) {
390 if ((e->buttons() & Qt::MidButton) && m_draggingChannel &&
391 (e->pos() - m_dragStartPosition).manhattanLength() >=
392 QApplication::startDragDistance()) {
393 QDrag *drag = new QDrag(this);
394 QMimeData *mimeData = new QMimeData;
395 mimeData->setText(m_draggingChannel->getExprRefName());
396 drag->setMimeData(mimeData);
397 static const QPixmap cursorPixmap(":Resources/dragcursor_exp_text.png");
398 drag->setDragCursor(cursorPixmap, Qt::MoveAction);
399 Qt::DropAction dropAction = drag->exec();
400 return;
401 }
402
403 // get the column under the cursor
404 int col = getViewer()->xyToPosition(e->pos()).layer();
405 FunctionTreeModel::Channel *channel = m_sheet->getChannel(col);
406 if (!channel) {
407 setToolTip(QString(""));
408 } else {
409 QString tooltip = channel->getExprRefName();
410 TXsheet *xsh = m_sheet->getViewer()->getXsheetHandle()->getXsheet();
411 if (xsh->isReferenceManagementIgnored(channel->getParam()))
412 tooltip +=
413 "\n" + tr("Some key(s) in this parameter loses original reference in "
414 "expression.\nManually changing any keyframe will clear "
415 "the warning.");
416
417 setToolTip(tooltip);
418 }
419
420 // modify selected channel by left dragging
421 if (m_clickedColumn >= 0 && channel && e->buttons() & Qt::LeftButton) {
422 int fromC = std::min(m_clickedColumn, col);
423 int toC = std::max(m_clickedColumn, col);
424 int lastKeyPos = 0;
425 for (int c = fromC; c <= toC; c++) {
426 FunctionTreeModel::Channel *tmpChan = m_sheet->getChannel(c);
427 if (!tmpChan) continue;
428 std::set<double> frames;
429 tmpChan->getParam()->getKeyframes(frames);
430 if (!frames.empty())
431 lastKeyPos = std::max(lastKeyPos, (int)*frames.rbegin());
432 }
433 QRect rect(std::min(m_clickedColumn, col), 0,
434 std::abs(col - m_clickedColumn) + 1, lastKeyPos + 1);
435 getViewer()->selectCells(rect);
436 }
437 }
438
439 //-----------------------------------------------------------------------------
440
mousePressEvent(QMouseEvent * e)441 void FunctionSheetColumnHeadViewer::mousePressEvent(QMouseEvent *e) {
442 QPoint pos = e->pos();
443 int currentC = getViewer()->xyToPosition(pos).layer();
444 FunctionTreeModel::Channel *channel = m_sheet->getChannel(currentC);
445 if (!channel) {
446 m_clickedColumn = -1;
447 return;
448 }
449
450 if (e->button() == Qt::MidButton) {
451 m_draggingChannel = channel;
452 m_dragStartPosition = e->pos();
453 return;
454 } else
455 channel->setIsCurrent(true);
456 m_draggingChannel = 0;
457
458 if (e->button() == Qt::LeftButton) {
459 int lastKeyPos = 0;
460 // if the current selection does not contain the first cell in m_firstColumn
461 // then we assume that the selection has been modified and treat shift+click
462 // as normal click.
463 if (getViewer()->getSelectedCells().contains(m_clickedColumn, 0) &&
464 (e->modifiers() & Qt::ShiftModifier)) {
465 int fromC = std::min(m_clickedColumn, currentC);
466 int toC = std::max(m_clickedColumn, currentC);
467 for (int c = fromC; c <= toC; c++) {
468 FunctionTreeModel::Channel *tmpChan = m_sheet->getChannel(c);
469 if (!tmpChan) continue;
470 std::set<double> frames;
471 tmpChan->getParam()->getKeyframes(frames);
472 if (!frames.empty())
473 lastKeyPos = std::max(lastKeyPos, (int)*frames.rbegin());
474 }
475 } else {
476 // Open folder
477 FunctionTreeModel::ChannelGroup *channelGroup =
478 channel->getChannelGroup();
479 if (!channelGroup->isOpen())
480 channelGroup->getModel()->setExpandedItem(channelGroup->createIndex(),
481 true);
482 // Select all segment
483 std::set<double> frames;
484 channel->getParam()->getKeyframes(frames);
485 if (!frames.empty()) lastKeyPos = (int)*frames.rbegin();
486 m_clickedColumn = currentC;
487 }
488 QRect rect(std::min(m_clickedColumn, currentC), 0,
489 std::abs(currentC - m_clickedColumn) + 1, lastKeyPos + 1);
490
491 getViewer()->selectCells(rect);
492 }
493 // Switch selection before opening the context menu
494 // if the clicked column is out of the selection
495 else if (e->button() == Qt::RightButton) {
496 QRect selectedCell = getViewer()->getSelectedCells();
497 if (selectedCell.left() > currentC || selectedCell.right() < currentC) {
498 int lastKeyPos = 0;
499 std::set<double> frames;
500 channel->getParam()->getKeyframes(frames);
501 if (!frames.empty()) lastKeyPos = (int)*frames.rbegin();
502 getViewer()->selectCells(QRect(currentC, 0, 1, lastKeyPos + 1));
503 }
504 }
505 }
506
507 //-----------------------------------------------------------------------------
508
contextMenuEvent(QContextMenuEvent * ce)509 void FunctionSheetColumnHeadViewer::contextMenuEvent(QContextMenuEvent *ce) {
510 // First, select column under cursor
511 const QPoint &pos = ce->pos();
512 int cursorCol = getViewer()->xyToPosition(pos).layer();
513
514 if (cursorCol < 0 || cursorCol >= m_sheet->getChannelCount()) return;
515
516 FunctionTreeModel::Channel *channel = m_sheet->getChannel(cursorCol);
517 if (!channel) return;
518
519 // Ok, now let's summon a context menu with appropriate options
520 FunctionViewer *fv = m_sheet->getViewer();
521 if (!fv) {
522 assert(fv);
523 return;
524 }
525
526 const QPoint &globalPos = mapToGlobal(pos);
527
528 if (pos.y() >= cChannelNameY)
529 fv->openContextMenu(channel, globalPos);
530 else {
531 FunctionTreeModel::ChannelGroup *group = channel->getChannelGroup();
532
533 // In this case, commands are different from the tree view. Rather than
534 // showing in the tree,
535 // channels get ACTIVATED
536 QMenu menu;
537
538 QAction showAnimatedOnly(FunctionTreeView::tr("Show Animated Only"), 0);
539 QAction showAll(FunctionTreeView::tr("Show All"), 0);
540 QAction hideSelected(FunctionTreeView::tr("Hide Selected"), 0);
541 menu.addAction(&showAnimatedOnly);
542 menu.addAction(&showAll);
543 menu.addAction(&hideSelected);
544
545 // execute menu
546 QAction *action = menu.exec(globalPos);
547
548 // Process action
549 if (action == &showAll) {
550 int c, cCount = group->getChildCount();
551 for (c = 0; c != cCount; ++c) {
552 FunctionTreeModel::Channel *channel =
553 dynamic_cast<FunctionTreeModel::Channel *>(group->getChild(c));
554 if (channel && !channel->isHidden()) channel->setIsActive(true);
555 }
556 } else if (action == &showAnimatedOnly) {
557 int c, cCount = group->getChildCount();
558 for (c = 0; c != cCount; ++c) {
559 FunctionTreeModel::Channel *channel =
560 dynamic_cast<FunctionTreeModel::Channel *>(group->getChild(c));
561 if (channel && !channel->isHidden())
562 channel->setIsActive(channel->isAnimated());
563 }
564 } else if (action == &hideSelected) {
565 QRect selectedCells = getViewer()->getSelectedCells();
566 // hide the selected columns from the right to the left
567 for (int col = selectedCells.right(); col >= selectedCells.left();
568 col--) {
569 FunctionTreeModel::Channel *chan = m_sheet->getChannel(col);
570 if (chan) chan->setIsActive(false);
571 }
572 // clear cell selection
573 getViewer()->selectCells(QRect());
574 } else
575 return;
576
577 fv->update();
578 }
579 }
580
581 //********************************************************************************
582 // FunctionSheetCellViewer implementation
583 //********************************************************************************
584
FunctionSheetCellViewer(FunctionSheet * parent)585 FunctionSheetCellViewer::FunctionSheetCellViewer(FunctionSheet *parent)
586 : Spreadsheet::CellPanel(parent)
587 , m_sheet(parent)
588 , m_editRow(0)
589 , m_editCol(0) {
590 m_lineEdit = new DVGui::LineEdit(this);
591 // lineEdit->setGeometry(10,10,100,30);
592 m_lineEdit->hide();
593 bool ret = connect(m_lineEdit, SIGNAL(editingFinished()), this,
594 SLOT(onCellEditorEditingFinished()));
595 ret = ret && connect(m_lineEdit, SIGNAL(mouseMoved(QMouseEvent *)), this,
596 SLOT(onMouseMovedInLineEdit(QMouseEvent *)));
597 assert(ret);
598 setMouseTracking(true);
599
600 setFocusProxy(m_lineEdit);
601 }
602
603 //-----------------------------------------------------------------------------
604 /*! Called when the cell panel is left/right-clicked
605 */
createDragTool(QMouseEvent * e)606 Spreadsheet::DragTool *FunctionSheetCellViewer::createDragTool(QMouseEvent *e) {
607 CellPosition cellPosition = getViewer()->xyToPosition(e->pos());
608 int row = cellPosition.frame();
609 int col = cellPosition.layer();
610 bool isEmpty = true;
611 TDoubleParam *curve = m_sheet->getCurve(col);
612 if (curve) {
613 int kCount = curve->getKeyframeCount();
614 if (kCount > 0) {
615 int row0 = (int)curve->keyframeIndexToFrame(0);
616 int row1 = (int)curve->keyframeIndexToFrame(kCount - 1);
617 isEmpty = row < row0 || row > row1;
618 }
619 }
620
621 if (!isEmpty) {
622 int x = e->pos().x() - getViewer()->columnToX(col);
623 if (0 <= x && x < cColumnDragHandleWidth + 9)
624 return new MoveChannelsDragTool(m_sheet);
625 }
626 return new FunctionSheetSelectionTool(m_sheet);
627
628 // return Spreadsheet::CellPanel::createDragTool(e);
629 }
630
631 //-----------------------------------------------------------------------------
632
drawCells(QPainter & painter,int r0,int c0,int r1,int c1)633 void FunctionSheetCellViewer::drawCells(QPainter &painter, int r0, int c0,
634 int r1, int c1) {
635 // key frames
636 QColor KeyFrameColor = getViewer()->getKeyFrameColor();
637 QColor KeyFrameBorderColor = getViewer()->getKeyFrameBorderColor();
638 QColor SelectedKeyFrameColor = getViewer()->getSelectedKeyFrameColor();
639 QColor IgnoredKeyFrameColor = getViewer()->getIgnoredKeyFrameColor();
640 QColor SelectedIgnoredKeyFrameColor =
641 getViewer()->getSelectedIgnoredKeyFrameColor();
642 // inbetween
643 QColor InBetweenColor = getViewer()->getInBetweenColor();
644 QColor InBetweenBorderColor = getViewer()->getInBetweenBorderColor();
645 QColor SelectedInBetweenColor = getViewer()->getSelectedInBetweenColor();
646 QColor IgnoredInBetweenColor = getViewer()->getIgnoredInBetweenColor();
647 QColor SelectedIgnoredInBetweenColor =
648 getViewer()->getSelectedIgnoredInBetweenColor();
649
650 // empty cells
651 QColor SelectedEmptyColor = getViewer()->getSelectedEmptyColor();
652 // empty cells in scene frame range
653 QColor SelectedSceneRangeEmptyColor =
654 getViewer()->getSelectedSceneRangeEmptyColor();
655
656 TXsheet *xsh = m_sheet->getViewer()->getXsheetHandle()->getXsheet();
657
658 // top and bottom pos
659 int y0 = getViewer()->rowToY(r0);
660 int y1 = getViewer()->rowToY(r1 + 1) - 1;
661 for (int c = c0; c <= c1; c++) {
662 TDoubleParam *curve = m_sheet->getCurve(c);
663 /*--- もしカラムcにパラメータが無ければcurveには0が返る ---*/
664 if (!curve) continue;
665 // left and right pos
666 int x0 = getViewer()->columnToX(c);
667 int x1 = getViewer()->columnToX(c + 1) - 1;
668
669 // find the curve keyframe range
670 int kr0 = 0, kr1 = -1;
671 int kCount = curve->getKeyframeCount();
672 if (kCount > 0) {
673 kr0 = curve->keyframeIndexToFrame(0);
674 kr1 = curve->keyframeIndexToFrame(kCount - 1);
675 }
676
677 // get the unit
678 TMeasure *measure = curve->getMeasure();
679 const TUnit *unit = measure ? measure->getCurrentUnit() : 0;
680
681 bool isStageObjectCycled = false;
682 TStageObject *obj = m_sheet->getStageObject(c);
683 if (obj && obj->isCycleEnabled()) isStageObjectCycled = true;
684
685 bool isParamCycled = curve->isCycleEnabled();
686 int rowCount = getViewer()->getRowCount();
687
688 bool isRefMngIgnored = xsh->isReferenceManagementIgnored(curve);
689
690 // draw each cell
691 for (int row = r0; row <= r1; row++) {
692 int ya = m_sheet->rowToY(row);
693 int yb = m_sheet->rowToY(row + 1) - 1;
694
695 bool isSelected = getViewer()->isSelectedCell(row, c);
696
697 double value = (isStageObjectCycled)
698 ? curve->getValue(obj->paramsTime((double)row))
699 : curve->getValue(row);
700 if (unit) value = unit->convertTo(value);
701 enum { None, Key, Inbetween, CycleRange } drawValue = None;
702
703 QRect cellRect(x0, ya, x1 - x0 + 1, yb - ya + 1);
704 QRect borderRect(x0, ya, 7, yb - ya + 1);
705 QColor cellColor, borderColor;
706
707 /*--- キーフレーム間の範囲だけ色をつける ---*/
708 if (kr0 <= row && row <= kr1) {
709 if (curve->isKeyframe(row)) {
710 cellColor =
711 (isRefMngIgnored)
712 ? ((isSelected) ? SelectedIgnoredKeyFrameColor
713 : IgnoredKeyFrameColor)
714 : ((isSelected) ? SelectedKeyFrameColor : KeyFrameColor);
715 borderColor = KeyFrameBorderColor;
716 } else {
717 cellColor =
718 (isRefMngIgnored)
719 ? ((isSelected) ? SelectedIgnoredInBetweenColor
720 : IgnoredInBetweenColor)
721 : ((isSelected) ? SelectedInBetweenColor : InBetweenColor);
722 borderColor = InBetweenBorderColor;
723
724 // when the inbetween values are hidden, change the cell colors to
725 // semi-transparent if the frame is in middle of the value step
726 if (!m_sheet->isIbtwnValueVisible()) {
727 TDoubleKeyframe kf =
728 curve->getKeyframe(curve->getPrevKeyframe(row));
729 int step = kf.m_step;
730 if (step > 1 && (row - (int)std::floor(kf.m_frame)) % step != 0)
731 cellColor.setAlpha(128);
732 }
733 }
734 painter.setPen(Qt::NoPen);
735 painter.fillRect(cellRect, cellColor);
736 painter.fillRect(borderRect, borderColor);
737
738 // display whether segment are Linked
739 if (curve->isKeyframe(row)) {
740 TDoubleKeyframe kf = curve->getKeyframeAt(row);
741 // if the segments are NOT linked, then cut off the side bar
742 if (!kf.m_linkedHandles) {
743 int rowCenterPos = (ya + yb) / 2;
744 QPoint points[4] = {
745 QPoint(x0, rowCenterPos), QPoint(x0 + 7, rowCenterPos + 3),
746 QPoint(x0 + 7, rowCenterPos - 3), QPoint(x0, rowCenterPos)};
747 QBrush oldBrush = painter.brush();
748 painter.setBrush(QBrush(cellColor));
749 painter.drawPolygon(points, 4);
750 painter.setBrush(oldBrush);
751 }
752 }
753
754 drawValue = (curve->isKeyframe(row))
755 ? Key
756 : (m_sheet->isIbtwnValueVisible()) ? Inbetween : None;
757
758 }
759 // empty cells
760 else {
761 // show values for cycled parameter.
762 // cycle option can be set in two ways; one is as TStageObject,
763 // the other is as TDoubleParam.
764 // - TStageObject cycle literally cycles values with no offset.
765 // Applied to all transformation parameters of the cycled object.
766 // - TDoubleParam cycle includes value offset so that the curve
767 // connects smoothly.
768 // - TStageObject cycle option has a priority to TDoubleParam one.
769 // (see TStageObject::paramsTime() in tstageobject.cpp)
770 if (kCount > 0 && row > kr1 && (isStageObjectCycled || isParamCycled) &&
771 (row < rowCount)) {
772 drawValue = CycleRange;
773 }
774 // empty and selected cell
775 if (isSelected) {
776 cellColor = (row >= rowCount) ? SelectedEmptyColor
777 : SelectedSceneRangeEmptyColor;
778 painter.setPen(Qt::NoPen);
779 painter.fillRect(cellRect, cellColor);
780 }
781 }
782
783 if (drawValue != None) {
784 // draw cell value
785 if (drawValue == Key || drawValue == Inbetween)
786 painter.setPen(getViewer()->getTextColor());
787 else {
788 QColor semiTranspTextColor = getViewer()->getTextColor();
789 semiTranspTextColor.setAlpha(128);
790 painter.setPen(semiTranspTextColor);
791 }
792
793 /*--- 整数から小数点以下3桁以内の場合はそれ以降の0000を描かない ---*/
794 QString text;
795
796 double thousandValue = value * 1000.0;
797 if (areAlmostEqual(thousandValue, (double)tround(thousandValue),
798 0.0001)) {
799 text = QString::number(value, 'f', 3);
800 while (text.endsWith("0")) {
801 text.chop(1);
802 if (text.endsWith(".")) {
803 text.chop(1);
804 break;
805 }
806 }
807 } else {
808 text = QString::number(value, 'f', 4);
809 text.truncate(5);
810 text.append("~");
811 }
812
813 QString fontName = Preferences::instance()->getInterfaceFont();
814 if (fontName == "") {
815 #ifdef _WIN32
816 fontName = "Arial";
817 #else
818 fontName = "Helvetica";
819 #endif
820 }
821 static QFont font(fontName, -1);
822 font.setBold(drawValue == Key);
823 font.setPixelSize(12);
824 painter.setFont(font);
825 painter.drawText(cellRect.adjusted(10, 0, 0, 0),
826 Qt::AlignVCenter | Qt::AlignLeft, text);
827 }
828 }
829
830 if (kCount > 0 && (isStageObjectCycled || isParamCycled)) {
831 // draw the row zigzag
832 int ymax = m_sheet->rowToY(r1 + 1);
833 int qx = x0 + 4;
834 int qy = m_sheet->rowToY(kr1 + 1);
835 int zig = 2;
836 QColor zigzagColor = (isStageObjectCycled) ? getViewer()->getTextColor()
837 : KeyFrameBorderColor;
838 painter.setPen(zigzagColor);
839 painter.drawLine(QPoint(qx, qy), QPoint(qx - zig, qy + zig));
840 qy += zig;
841 while (qy < ymax) {
842 painter.drawLine(QPoint(qx - zig, qy), QPoint(qx + zig, qy + 2 * zig));
843 painter.drawLine(QPoint(qx + zig, qy + 2 * zig),
844 QPoint(qx - zig, qy + 4 * zig));
845 qy += 4 * zig;
846 }
847 }
848 }
849 }
850
851 //-----------------------------------------------------------------------------
852
mouseDoubleClickEvent(QMouseEvent * e)853 void FunctionSheetCellViewer::mouseDoubleClickEvent(QMouseEvent *e) {
854 CellPosition cellPosition = getViewer()->xyToPosition(e->pos());
855 int row = cellPosition.frame();
856 int col = cellPosition.layer();
857 int x0, y0, x1, y1;
858 x0 = getViewer()->columnToX(col);
859 x1 = getViewer()->columnToX(col + 1) - 1;
860 y0 = getViewer()->rowToY(row);
861 y1 = getViewer()->rowToY(row + 1) - 1;
862
863 m_editRow = row;
864 m_editCol = col;
865
866 TDoubleParam *curve = m_sheet->getCurve(col);
867 if (curve) {
868 double v = curve->getValue(row);
869 TMeasure *measure = curve->getMeasure();
870 const TUnit *unit = measure ? measure->getCurrentUnit() : 0;
871 if (unit) v = unit->convertTo(v);
872 m_currentValue = v;
873 m_lineEdit->setText(QString::number(v, 'f', 4));
874 // in order to put the cursor to the left end
875 m_lineEdit->setSelection(m_lineEdit->text().length(),
876 -m_lineEdit->text().length());
877 } else
878 m_lineEdit->setText("");
879
880 QString fontName = Preferences::instance()->getInterfaceFont();
881 if (fontName == "") {
882 #ifdef _WIN32
883 fontName = "Arial";
884 #else
885 fontName = "Helvetica";
886 #endif
887 }
888 static QFont font(fontName, 9, QFont::Normal);
889 m_lineEdit->setFont(font);
890
891 m_lineEdit->setGeometry(x0 - 2, y0 - 2, x1 - x0 + 1 + 4,
892 y1 - y0 + 1 + 4); // x0,y0,x1-x0+1,y0-y1+1);
893 m_lineEdit->show();
894 m_lineEdit->raise();
895 m_lineEdit->setFocus();
896 }
897
898 //-----------------------------------------------------------------------------
899
onCellEditorEditingFinished()900 void FunctionSheetCellViewer::onCellEditorEditingFinished() {
901 QString text = m_lineEdit->text();
902 if (!text.isEmpty() &&
903 (m_lineEdit->isReturnPressed() || m_lineEdit->getMouseDragEditing())) {
904 double value = text.toDouble();
905 TDoubleParam *curve = m_sheet->getCurve(m_editCol);
906 if (curve) {
907 TMeasure *measure = curve->getMeasure();
908 const TUnit *unit = measure ? measure->getCurrentUnit() : 0;
909 if (unit) value = unit->convertFrom(value);
910 KeyframeSetter::setValue(curve, m_editRow, value);
911 }
912 }
913 m_lineEdit->hide();
914 m_lineEdit->clearFocus();
915 m_sheet->setFocus();
916 update();
917 }
918
919 //-----------------------------------------------------------------------------
920
mousePressEvent(QMouseEvent * e)921 void FunctionSheetCellViewer::mousePressEvent(QMouseEvent *e) {
922 // escape from the line edit by clicking outside
923 if (m_lineEdit->isVisible()) {
924 m_lineEdit->hide();
925 m_lineEdit->clearFocus();
926 m_sheet->setFocus();
927 }
928 if (e->button() == Qt::LeftButton && e->modifiers() == Qt::ControlModifier) {
929 mouseDoubleClickEvent(e);
930 if (m_lineEdit->text() != "") {
931 m_lineEdit->setMouseDragEditing(true);
932 m_mouseXPosition = e->x();
933 }
934 } else if (e->button() == Qt::LeftButton &&
935 e->modifiers() == Qt::AltModifier) {
936 CellPosition cellPosition = getViewer()->xyToPosition(e->pos());
937 int row = cellPosition.frame();
938 int col = cellPosition.layer();
939 TDoubleParam *curve = m_sheet->getCurve(col);
940 if (curve) {
941 KeyframeSetter::removeKeyframeAt(curve, row);
942 }
943 } else if (e->button() == Qt::LeftButton || e->button() == Qt::MidButton)
944 Spreadsheet::CellPanel::mousePressEvent(e);
945 else if (e->button() == Qt::RightButton) {
946 update();
947 openContextMenu(e);
948 }
949 }
950
951 //-----------------------------------------------------------------------------
952
mouseReleaseEvent(QMouseEvent * e)953 void FunctionSheetCellViewer::mouseReleaseEvent(QMouseEvent *e) {
954 if (m_lineEdit->getMouseDragEditing()) {
955 std::string textValue = m_lineEdit->text().toStdString();
956 onCellEditorEditingFinished();
957 m_lineEdit->setMouseDragEditing(false);
958 } else
959 Spreadsheet::CellPanel::mouseReleaseEvent(e);
960 /*
961 CellPosition cellPosition = getViewer ()->xyToPosition (e->pos ());
962 int row = cellPosition.frame ();
963 int col = cellPosition.layer ();
964 FunctionSheet::DragTool *dragTool = m_sheet->getDragTool();
965 if(dragTool) dragTool->release(row,col);
966 m_sheet->setDragTool(0);
967 */
968 }
969
970 //-----------------------------------------------------------------------------
971
mouseMoveEvent(QMouseEvent * e)972 void FunctionSheetCellViewer::mouseMoveEvent(QMouseEvent *e) {
973 if (m_lineEdit->getMouseDragEditing()) {
974 double newValue = m_currentValue + ((e->x() - m_mouseXPosition) / 2);
975 m_lineEdit->setText(QString::number(newValue, 'f', 4));
976 m_updatedValue = newValue;
977 } else
978 Spreadsheet::CellPanel::mouseMoveEvent(e);
979 }
980
981 //-----------------------------------------------------------------------------
982
onMouseMovedInLineEdit(QMouseEvent * event)983 void FunctionSheetCellViewer::onMouseMovedInLineEdit(QMouseEvent *event) {
984 if (m_lineEdit->getMouseDragEditing()) mouseMoveEvent(event);
985 }
986
987 //-----------------------------------------------------------------------------
988
989 // TODO: refactor: cfr functionpanel.cpp
openContextMenu(QMouseEvent * e)990 void FunctionSheetCellViewer::openContextMenu(QMouseEvent *e) {
991 QAction deleteKeyframeAction(tr("Delete Key"), 0);
992 QAction insertKeyframeAction(tr("Set Key"), 0);
993
994 QStringList interpNames;
995 interpNames << tr("Constant Interpolation") << tr("Linear Interpolation")
996 << tr("Speed In / Speed Out Interpolation")
997 << tr("Ease In / Ease Out Interpolation")
998 << tr("Ease In / Ease Out (%) Interpolation")
999 << tr("Exponential Interpolation")
1000 << tr("Expression Interpolation") << tr("File Interpolation")
1001 << tr("Similar Shape Interpolation");
1002 QAction activateCycleAction(tr("Activate Cycle"), 0);
1003 QAction deactivateCycleAction(tr("Deactivate Cycle"), 0);
1004 QAction showIbtwnAction(tr("Show Inbetween Values"), 0);
1005 QAction hideIbtwnAction(tr("Hide Inbetween Values"), 0);
1006
1007 CellPosition cellPosition = getViewer()->xyToPosition(e->pos());
1008 int row = cellPosition.frame();
1009 int col = cellPosition.layer();
1010 TDoubleParam *curve = m_sheet->getCurve(col);
1011 if (!curve) return;
1012
1013 bool isEmpty = true;
1014 bool isKeyframe = false;
1015
1016 // find the curve keyframe range
1017 int kCount = curve->getKeyframeCount();
1018 if (kCount > 0) {
1019 if (curve->keyframeIndexToFrame(0) <= row &&
1020 row <= curve->keyframeIndexToFrame(kCount - 1)) {
1021 isEmpty = false;
1022 isKeyframe = curve->isKeyframe(row);
1023 }
1024 }
1025 int kIndex = curve->getPrevKeyframe(row);
1026
1027 // if the FunctionSelection is not current or when clicking outside of the
1028 // selection, then select the clicked cell.
1029 FunctionSelection *selection = m_sheet->getSelection();
1030 if (!selection->getSelectedCells().contains(col, row)) {
1031 selection->makeCurrent();
1032 selection->selectCells(QRect(col, row, 1, 1));
1033 }
1034 CommandManager *cmdManager = CommandManager::instance();
1035
1036 // build menu
1037 QMenu menu(0);
1038
1039 // on clicking after last keyframe
1040 if (kCount > 0 && isEmpty && kIndex == kCount - 1) {
1041 if (curve->isCycleEnabled())
1042 menu.addAction(&deactivateCycleAction);
1043 else
1044 menu.addAction(&activateCycleAction);
1045 }
1046
1047 if (!isKeyframe) // menu.addAction(&deleteKeyframeAction); else
1048 menu.addAction(&insertKeyframeAction);
1049
1050 // change interpolation commands
1051 QList<QAction *> interpActions;
1052 int interp = selection->getCommonSegmentType();
1053 if (interp != -1) {
1054 menu.addSeparator();
1055 QMenu *interpMenu = menu.addMenu(tr("Change Interpolation"));
1056 for (int i = (int)TDoubleKeyframe::Constant;
1057 i <= (int)TDoubleKeyframe::SimilarShape; i++) {
1058 if (interp != i) {
1059 QAction *interpAction = new QAction(interpNames[i - 1], 0);
1060 interpAction->setData(i);
1061 interpActions.append(interpAction);
1062 interpMenu->addAction(interpAction);
1063 }
1064 }
1065 }
1066
1067 // change step commands
1068 int step = selection->getCommonStep();
1069 if (step != -1) {
1070 QMenu *stepMenu = menu.addMenu(tr("Change Step"));
1071 if (step != 1) stepMenu->addAction(cmdManager->getAction("MI_ResetStep"));
1072 if (step != 2) stepMenu->addAction(cmdManager->getAction("MI_Step2"));
1073 if (step != 3) stepMenu->addAction(cmdManager->getAction("MI_Step3"));
1074 if (step != 4) stepMenu->addAction(cmdManager->getAction("MI_Step4"));
1075 }
1076
1077 menu.addSeparator();
1078
1079 menu.addAction(cmdManager->getAction("MI_Cut"));
1080 menu.addAction(cmdManager->getAction("MI_Copy"));
1081 menu.addAction(cmdManager->getAction("MI_Paste"));
1082 menu.addAction(cmdManager->getAction("MI_Clear"));
1083
1084 menu.addAction(cmdManager->getAction("MI_Insert"));
1085
1086 if (!isEmpty && kIndex >= 0) {
1087 menu.addSeparator();
1088 if (m_sheet->isIbtwnValueVisible())
1089 menu.addAction(&hideIbtwnAction);
1090 else
1091 menu.addAction(&showIbtwnAction);
1092 }
1093
1094 TSceneHandle *sceneHandle = m_sheet->getViewer()->getSceneHandle();
1095 // execute menu
1096 QAction *action = menu.exec(e->globalPos()); // QCursor::pos());
1097 if (action == &deleteKeyframeAction) {
1098 KeyframeSetter::removeKeyframeAt(curve, row);
1099 } else if (action == &insertKeyframeAction) {
1100 KeyframeSetter(curve).createKeyframe(row);
1101 } else if (interpActions.contains(action)) {
1102 selection->setSegmentType((TDoubleKeyframe::Type)action->data().toInt());
1103 } else if (action == &activateCycleAction)
1104 KeyframeSetter::enableCycle(curve, true, sceneHandle);
1105 else if (action == &deactivateCycleAction)
1106 KeyframeSetter::enableCycle(curve, false, sceneHandle);
1107 else if (action == &hideIbtwnAction)
1108 m_sheet->setIbtwnValueVisible(false);
1109 else if (action == &showIbtwnAction)
1110 m_sheet->setIbtwnValueVisible(true);
1111
1112 update();
1113 }
1114
1115 //********************************************************************************
1116 // FunctionSheetColumnToCurveMapper implementation
1117 //********************************************************************************
1118
1119 class FunctionSheetColumnToCurveMapper final : public ColumnToCurveMapper {
1120 FunctionSheet *m_sheet;
1121
1122 public:
FunctionSheetColumnToCurveMapper(FunctionSheet * sheet)1123 FunctionSheetColumnToCurveMapper(FunctionSheet *sheet) : m_sheet(sheet) {}
getCurve(int columnIndex) const1124 TDoubleParam *getCurve(int columnIndex) const override {
1125 FunctionTreeModel::Channel *channel = m_sheet->getChannel(columnIndex);
1126 if (channel)
1127 return channel->getParam();
1128 else
1129 return 0;
1130 }
1131 };
1132
1133 //********************************************************************************
1134 // FunctionSheet implementation
1135 //********************************************************************************
1136
FunctionSheet(QWidget * parent,bool isFloating)1137 FunctionSheet::FunctionSheet(QWidget *parent, bool isFloating)
1138 : SpreadsheetViewer(parent)
1139 , m_selectedCells()
1140 , m_selection(0)
1141 , m_isFloating(isFloating) {
1142 setColumnsPanel(m_columnHeadViewer = new FunctionSheetColumnHeadViewer(this));
1143 setRowsPanel(m_rowViewer = new FunctionSheetRowViewer(this));
1144 setCellsPanel(m_cellViewer = new FunctionSheetCellViewer(this));
1145
1146 setWindowFlag(Qt::Window);
1147 setColumnCount(20);
1148 setWindowTitle(tr("Function Editor"));
1149 setFocusPolicy(Qt::ClickFocus);
1150
1151 if (m_isFloating) {
1152 // load the dialog size
1153 TFilePath fp(ToonzFolder::getMyModuleDir() + TFilePath("popups.ini"));
1154 QSettings settings(toQString(fp), QSettings::IniFormat);
1155
1156 setGeometry(settings.value("FunctionSpreadsheet", QRect(500, 500, 400, 300))
1157 .toRect());
1158 }
1159 }
1160
1161 //-----------------------------------------------------------------------------
1162
~FunctionSheet()1163 FunctionSheet::~FunctionSheet() {
1164 if (m_isFloating) {
1165 TFilePath fp(ToonzFolder::getMyModuleDir() + TFilePath("popups.ini"));
1166 QSettings settings(toQString(fp), QSettings::IniFormat);
1167
1168 settings.setValue("FunctionSpreadsheet", geometry());
1169 }
1170 }
1171
1172 //-----------------------------------------------------------------------------
1173
anyWidgetHasFocus()1174 bool FunctionSheet::anyWidgetHasFocus() {
1175 return hasFocus() || m_rowViewer->hasFocus() ||
1176 m_columnHeadViewer->hasFocus() || m_cellViewer->hasFocus();
1177 }
1178
1179 //-----------------------------------------------------------------------------
1180
setSelection(FunctionSelection * selection)1181 void FunctionSheet::setSelection(FunctionSelection *selection) {
1182 m_selection = selection;
1183 m_selection->setColumnToCurveMapper(
1184 new FunctionSheetColumnToCurveMapper(this));
1185 }
1186
1187 //-----------------------------------------------------------------------------
1188
showEvent(QShowEvent * e)1189 void FunctionSheet::showEvent(QShowEvent *e) {
1190 m_frameScroller.registerFrameScroller();
1191 SpreadsheetViewer::showEvent(e);
1192 }
1193
1194 //-----------------------------------------------------------------------------
1195
hideEvent(QHideEvent * e)1196 void FunctionSheet::hideEvent(QHideEvent *e) {
1197 m_frameScroller.unregisterFrameScroller();
1198 SpreadsheetViewer::hideEvent(e);
1199 }
1200
1201 //-----------------------------------------------------------------------------
1202
onFrameSwitched()1203 void FunctionSheet::onFrameSwitched() {
1204 setCurrentRow(getCurrentFrame());
1205 m_rowViewer->update();
1206 m_cellViewer->update();
1207 }
1208
1209 //-----------------------------------------------------------------------------
1210
setCurrentFrame(int frame)1211 void FunctionSheet::setCurrentFrame(int frame) {
1212 if (getFrameHandle()) getFrameHandle()->setFrame(frame);
1213 }
1214
1215 //-----------------------------------------------------------------------------
1216
getCurrentFrame() const1217 int FunctionSheet::getCurrentFrame() const {
1218 return getFrameHandle() ? getFrameHandle()->getFrame() : 0;
1219 }
1220
1221 //-----------------------------------------------------------------------------
1222
getChannelCount()1223 int FunctionSheet::getChannelCount() {
1224 if (m_functionTreeModel == 0)
1225 return 0;
1226 else
1227 return m_functionTreeModel->getActiveChannelCount();
1228 }
1229
1230 //-----------------------------------------------------------------------------
1231
getChannel(int column)1232 FunctionTreeModel::Channel *FunctionSheet::getChannel(int column) {
1233 if (m_functionTreeModel == 0)
1234 return 0;
1235 else
1236 return m_functionTreeModel->getActiveChannel(column);
1237 }
1238
1239 //-----------------------------------------------------------------------------
1240
getCurve(int column)1241 TDoubleParam *FunctionSheet::getCurve(int column) {
1242 FunctionTreeModel::Channel *channel = getChannel(column);
1243 return channel ? channel->getParam() : 0;
1244 }
1245
1246 //-----------------------------------------------------------------------------
1247
setModel(FunctionTreeModel * model)1248 void FunctionSheet::setModel(FunctionTreeModel *model) {
1249 m_functionTreeModel = model;
1250 }
1251
1252 //-----------------------------------------------------------------------------
1253
setViewer(FunctionViewer * viewer)1254 void FunctionSheet::setViewer(FunctionViewer *viewer) {
1255 m_functionViewer = viewer;
1256 }
1257
1258 //-----------------------------------------------------------------------------
1259
getSelectedCells() const1260 QRect FunctionSheet::getSelectedCells() const {
1261 if (getSelection())
1262 return getSelection()->getSelectedCells();
1263 else
1264 return QRect();
1265 }
1266
1267 //-----------------------------------------------------------------------------
1268
selectCells(const QRect & selectedCells)1269 void FunctionSheet::selectCells(const QRect &selectedCells) {
1270 m_selectedCells = selectedCells;
1271 if (getSelection()) {
1272 QList<TDoubleParam *> curves;
1273 for (int c = selectedCells.left(); c <= selectedCells.right(); c++) {
1274 TDoubleParam *param = 0;
1275 if (c < getChannelCount()) param = getChannel(c)->getParam();
1276 curves.push_back(param);
1277 }
1278 getSelection()->selectCells(selectedCells, curves);
1279
1280 if (selectedCells.width() == 1 && curves[0] &&
1281 !getChannel(selectedCells.x())->isCurrent())
1282 getChannel(selectedCells.x())->setIsCurrent(true);
1283 }
1284
1285 updateAll();
1286 }
1287
1288 //-----------------------------------------------------------------------------
1289
updateAll()1290 void FunctionSheet::updateAll() {
1291 m_rowViewer->update();
1292 m_columnHeadViewer->update();
1293 m_cellViewer->update();
1294 setColumnCount(getChannelCount());
1295 }
1296
1297 //-----------------------------------------------------------------------------
1298 /*! Display expression name of the current segment
1299 */
getSelectedParamName()1300 QString FunctionSheet::getSelectedParamName() {
1301 if (m_functionTreeModel->getCurrentChannel())
1302 return m_functionTreeModel->getCurrentChannel()->getExprRefName();
1303 else
1304 return QString();
1305 }
1306
1307 //-----------------------------------------------------------------------------
1308
getColumnIndexByCurve(TDoubleParam * param) const1309 int FunctionSheet::getColumnIndexByCurve(TDoubleParam *param) const {
1310 return m_functionTreeModel->getColumnIndexByCurve(param);
1311 }
1312
1313 //-----------------------------------------------------------------------------
1314 /*! scroll column to show the current one
1315 */
onCurrentChannelChanged(FunctionTreeModel::Channel * channel)1316 void FunctionSheet::onCurrentChannelChanged(
1317 FunctionTreeModel::Channel *channel) {
1318 if (!channel) return;
1319 for (int c = 0; c < getChannelCount(); c++) {
1320 FunctionTreeModel::Channel *tmpChan = getChannel(c);
1321
1322 if (tmpChan == channel) {
1323 ensureVisibleCol(c);
1324 return;
1325 }
1326 }
1327 }
1328
1329 //-----------------------------------------------------------------------------
1330 /*! Obtains a pointer to the stage object containing the parameter of specified
1331 * column
1332 */
getStageObject(int column)1333 TStageObject *FunctionSheet::getStageObject(int column) {
1334 FunctionTreeModel::Channel *channel = getChannel(column);
1335 if (!channel) return nullptr;
1336
1337 FunctionTreeModel::ChannelGroup *channelGroup = channel->getChannelGroup();
1338 if (!channelGroup) return nullptr;
1339
1340 // returns nullptr if the channel is a fx parameter
1341 StageObjectChannelGroup *stageItem =
1342 dynamic_cast<StageObjectChannelGroup *>(channelGroup);
1343 if (!stageItem) return nullptr;
1344
1345 return stageItem->getStageObject();
1346 }