| |
| |
| #include "toonzqt/functionsheet.h" |
| |
| |
| #include "toonzqt/gutil.h" |
| #include "toonzqt/functionviewer.h" |
| |
| |
| #include "toonz/tframehandle.h" |
| #include "toonz/doubleparamcmd.h" |
| #include "toonz/preferences.h" |
| |
| |
| #include "tunit.h" |
| |
| #include "../toonz/menubarcommandids.h" |
| |
| |
| #include <QPainter> |
| #include <QGridLayout> |
| #include <QPaintEvent> |
| #include <QMenu> |
| #include <QApplication> //for drag&drop |
| #include <QDrag> |
| |
| |
| |
| |
| |
| namespace |
| { |
| |
| const int cColumnDragHandleWidth = 8; |
| |
| const int cGroupShortNameY = 0; |
| const int cGroupLongNameY = 27; |
| const int cChannelNameY = 50; |
| const int cColHeadersEndY = 87; |
| |
| } |
| |
| |
| |
| |
| |
| |
| class MoveChannelsDragTool : public Spreadsheet::DragTool |
| { |
| FunctionSheet *m_sheet; |
| std::vector<KeyframeSetter *> m_setters; |
| int m_oldRow; |
| QRect m_selectedCells; |
| int m_firstKeyframeRow; |
| |
| public: |
| MoveChannelsDragTool(FunctionSheet *sheet) : m_sheet(sheet), m_firstKeyframeRow(-1) {} |
| |
| void click(int row, int col, QMouseEvent *e) |
| { |
| m_firstKeyframeRow = -1; |
| FunctionTreeModel::Channel *channel = m_sheet->getChannel(col); |
| if (!channel) |
| return; |
| TDoubleParam *curve = channel->getParam(); |
| int k0 = -1, k1 = -1; |
| if (curve->isKeyframe(row)) |
| k0 = k1 = curve->getClosestKeyframe(row); |
| else { |
| k0 = curve->getPrevKeyframe(row); |
| k1 = curve->getNextKeyframe(row); |
| } |
| |
| if (k0 < 0 || k1 < 0) |
| return; |
| int r0 = tround(curve->keyframeIndexToFrame(k0)); |
| int r1 = tround(curve->keyframeIndexToFrame(k1)); |
| if (m_sheet->isSelectedCell(row, col)) { |
| m_selectedCells = m_sheet->getSelectedCells(); |
| m_selectedCells.setTop(r0); |
| m_selectedCells.setBottom(r1); |
| } else |
| m_selectedCells = QRect(col, r0, 1, r1 - r0 + 1); |
| |
| m_sheet->selectCells(m_selectedCells); |
| |
| |
| |
| |
| |
| |
| |
| for (int col = m_selectedCells.left(); col <= m_selectedCells.right(); ++col) { |
| TDoubleParam *curve = m_sheet->getCurve(col); |
| if (!curve) |
| continue; |
| KeyframeSetter *setter = new KeyframeSetter(curve); |
| for (int k = 0; k < curve->getKeyframeCount(); k++) { |
| int row = (int)curve->keyframeIndexToFrame(k); |
| if (r0 <= row && row <= r1) { |
| if (m_firstKeyframeRow < 0 || row < m_firstKeyframeRow) |
| m_firstKeyframeRow = row; |
| setter->selectKeyframe(k); |
| } |
| } |
| m_setters.push_back(setter); |
| } |
| m_oldRow = row; |
| } |
| |
| void drag(int row, int col, QMouseEvent *e) |
| { |
| int d = row - m_oldRow; |
| m_oldRow = row; |
| if (d + m_firstKeyframeRow < 0) |
| d = -m_firstKeyframeRow; |
| m_firstKeyframeRow += d; |
| for (int i = 0; i < (int)m_setters.size(); i++) |
| m_setters[i]->moveKeyframes(d, 0.0); |
| m_selectedCells.translate(0, d); |
| m_sheet->selectCells(m_selectedCells); |
| } |
| |
| void release(int row, int col, QMouseEvent *e) |
| { |
| for (int i = 0; i < (int)m_setters.size(); i++) |
| delete m_setters[i]; |
| m_setters.clear(); |
| } |
| }; |
| |
| |
| |
| class FunctionSheetSelectionTool : public Spreadsheet::DragTool |
| { |
| int m_firstRow, m_firstCol; |
| FunctionSheet *m_sheet; |
| |
| public: |
| FunctionSheetSelectionTool(FunctionSheet *sheet) |
| : m_sheet(sheet), m_firstRow(-1), m_firstCol(-1) {} |
| |
| void click(int row, int col, QMouseEvent *e) |
| { |
| if (0 != (e->modifiers() & Qt::ShiftModifier) && !m_sheet->getSelectedCells().isEmpty()) { |
| QRect selectedCells = m_sheet->getSelectedCells(); |
| if (col < selectedCells.center().x()) { |
| m_firstCol = selectedCells.right(); |
| selectedCells.setLeft(col); |
| } else { |
| m_firstCol = selectedCells.left(); |
| selectedCells.setRight(col); |
| } |
| if (row < selectedCells.center().y()) { |
| m_firstRow = selectedCells.bottom(); |
| selectedCells.setTop(row); |
| } else { |
| m_firstRow = selectedCells.top(); |
| selectedCells.setBottom(row); |
| } |
| m_sheet->selectCells(selectedCells); |
| } else { |
| |
| m_firstCol = col; |
| m_firstRow = row; |
| QRect selectedCells(col, row, 1, 1); |
| m_sheet->selectCells(selectedCells); |
| } |
| } |
| |
| void drag(int row, int col, QMouseEvent *e) |
| { |
| if (row < 0) |
| row = 0; |
| if (col < 0) |
| col = 0; |
| int r0 = qMin(row, m_firstRow); |
| int r1 = qMax(row, m_firstRow); |
| int c0 = qMin(col, m_firstCol); |
| int c1 = qMax(col, m_firstCol); |
| QRect selectedCells(c0, r0, c1 - c0 + 1, r1 - r0 + 1); |
| m_sheet->selectCells(selectedCells); |
| } |
| |
| void release(int row, int col, QMouseEvent *e) |
| { |
| if (row == m_firstRow && col == m_firstCol) { |
| if (Preferences::instance()->isMoveCurrentEnabled()) |
| m_sheet->setCurrentFrame(row); |
| FunctionTreeModel::Channel *channel = m_sheet->getChannel(col); |
| if (channel) |
| channel->setIsCurrent(true); |
| } |
| } |
| }; |
| |
| |
| |
| |
| |
| FunctionSheetRowViewer::FunctionSheetRowViewer(FunctionSheet *parent) |
| : Spreadsheet::RowPanel(parent), m_sheet(parent) |
| { |
| setMinimumSize(QSize(100, 100)); |
| setMouseTracking(true); |
| setFocusPolicy(Qt::NoFocus); |
| } |
| |
| |
| |
| void FunctionSheetRowViewer::paintEvent(QPaintEvent *e) |
| { |
| |
| Spreadsheet::RowPanel::paintEvent(e); |
| } |
| |
| |
| |
| void FunctionSheetRowViewer::mousePressEvent(QMouseEvent *e) |
| { |
| |
| Spreadsheet::RowPanel::mousePressEvent(e); |
| } |
| |
| |
| |
| void FunctionSheetRowViewer::mouseMoveEvent(QMouseEvent *e) |
| { |
| |
| Spreadsheet::RowPanel::mouseMoveEvent(e); |
| } |
| |
| |
| |
| void FunctionSheetRowViewer::mouseReleaseEvent(QMouseEvent *e) |
| { |
| Spreadsheet::RowPanel::mouseReleaseEvent(e); |
| } |
| |
| |
| |
| void FunctionSheetRowViewer::contextMenuEvent(QContextMenuEvent *event) |
| { |
| QMenu *menu = new QMenu(this); |
| CommandManager *cmdManager = CommandManager::instance(); |
| menu->addAction(cmdManager->getAction(MI_InsertSceneFrame)); |
| menu->addAction(cmdManager->getAction(MI_RemoveSceneFrame)); |
| menu->addAction(cmdManager->getAction(MI_InsertGlobalKeyframe)); |
| menu->addAction(cmdManager->getAction(MI_RemoveGlobalKeyframe)); |
| menu->exec(event->globalPos()); |
| } |
| |
| |
| |
| |
| |
| FunctionSheetColumnHeadViewer::FunctionSheetColumnHeadViewer(FunctionSheet *parent) |
| : Spreadsheet::ColumnPanel(parent), m_sheet(parent), m_draggingChannel(0) |
| { |
| setMouseTracking(true); |
| setFocusPolicy(Qt::NoFocus); |
| } |
| |
| |
| |
| void FunctionSheetColumnHeadViewer::paintEvent(QPaintEvent *e) |
| { |
| QPainter painter(this); |
| |
| QRect toBeUpdated = e->rect(); |
| painter.setClipRect(toBeUpdated); |
| |
| int x0 = toBeUpdated.left(); |
| int x1 = toBeUpdated.right(); |
| |
| |
| int c0 = getViewer()->xToColumn(x0); |
| int c1 = getViewer()->xToColumn(x1); |
| |
| if (c0 > c1) |
| return; |
| |
| int n = c1 - c0 + 1 + 2; |
| |
| FunctionTreeModel::ChannelGroup *currentGroup = 0; |
| |
| |
| std::vector<FunctionTreeModel::ChannelGroup *> channelGroups(n); |
| for (int i = 0; i < n; ++i) { |
| channelGroups[i] = 0; |
| |
| int c = c0 - 1 + i; |
| if (c < 0) |
| continue; |
| |
| FunctionTreeModel::Channel *channel = m_sheet->getChannel(c); |
| if (!channel) |
| continue; |
| |
| channelGroups[i] = channel->getChannelGroup(); |
| if (!currentGroup && channel->isCurrent()) |
| currentGroup = channelGroups[i]; |
| } |
| |
| int y0 = 0; |
| int y1 = 17; |
| int y2 = 34; |
| int y3 = 53; |
| |
| |
| for (int c = c0; c <= c1; c++) { |
| FunctionTreeModel::Channel *channel = m_sheet->getChannel(c); |
| if (!channel) |
| continue; |
| int x0 = getViewer()->columnToX(c); |
| int x1 = getViewer()->columnToX(c + 1) - 1; |
| |
| int width = x1 - x0 + 1; |
| |
| painter.fillRect(x0, y0, width, y3 - y0, getViewer()->getBGColor()); |
| } |
| |
| for (int c = c0; c <= c1; ++c) { |
| FunctionTreeModel::Channel *channel = m_sheet->getChannel(c); |
| if (!channel) |
| continue; |
| int i = c - c0 + 1; |
| |
| FunctionTreeModel::ChannelGroup |
| *prevGroup = channelGroups[c - c0], |
| *group = channelGroups[c - c0 + 1], |
| *nextGroup = channelGroups[c - c0 + 2]; |
| |
| |
| bool firstGroupColumn = prevGroup != group; |
| bool lastGroupColumn = nextGroup != group; |
| |
| |
| int x0 = getViewer()->columnToX(c); |
| int x1 = getViewer()->columnToX(c + 1) - 1; |
| |
| int width = x1 - x0 + 1; |
| |
| QRect selectedRect = m_sheet->getSelectedCells(); |
| bool isSelected = (selectedRect.left() <= c && c <= selectedRect.right()) ? true : false; |
| |
| |
| if (isSelected) |
| painter.fillRect(x0, y1, width, y3 - y1, getViewer()->getCurrentRowBgColor()); |
| |
| |
| painter.setPen(QPen(getViewer()->getColumnHeaderBorderColor(), 3)); |
| painter.drawLine(x0, y0, x1, y0); |
| painter.setPen(getViewer()->getColumnHeaderBorderColor()); |
| painter.drawLine(x0, y1, x1, y1); |
| |
| |
| painter.fillRect(x0, y1, 6, y3 - y1, getViewer()->getColumnHeaderBorderColor()); |
| if (firstGroupColumn) |
| painter.fillRect(x0, y0, 6, y1 - y0, getViewer()->getColumnHeaderBorderColor()); |
| |
| |
| painter.setPen(getViewer()->getTextColor()); |
| if (channel->isCurrent()) |
| painter.setPen(getViewer()->getSelectedColumnTextColor()); |
| |
| QString text = channel->getShortName(); |
| int d = 8; |
| painter.drawText(x0 + d, y1, width - d, y3 - y1 + 1, Qt::TextWrapAnywhere | Qt::AlignLeft | Qt::AlignVCenter, text); |
| |
| |
| if (firstGroupColumn) { |
| int tmpwidth = (lastGroupColumn) ? width : width * 2; |
| painter.setPen(getViewer()->getTextColor()); |
| if (group == currentGroup) |
| painter.setPen(getViewer()->getSelectedColumnTextColor()); |
| text = group->getShortName(); |
| painter.drawText(x0 + d, y0, tmpwidth - d, y1 - y0 + 1, Qt::AlignLeft | Qt::AlignVCenter, text); |
| } |
| } |
| } |
| |
| |
| |
| |
| void FunctionSheetColumnHeadViewer::mouseMoveEvent(QMouseEvent *e) |
| { |
| if ((e->buttons() & Qt::MidButton) && |
| m_draggingChannel && |
| (e->pos() - m_dragStartPosition).manhattanLength() >= QApplication::startDragDistance()) { |
| QDrag *drag = new QDrag(this); |
| QMimeData *mimeData = new QMimeData; |
| mimeData->setText(m_draggingChannel->getExprRefName()); |
| drag->setMimeData(mimeData); |
| static const QPixmap cursorPixmap(":Resources/dragcursor_exp_text.png"); |
| drag->setDragCursor(cursorPixmap, Qt::MoveAction); |
| Qt::DropAction dropAction = drag->exec(); |
| return; |
| } |
| |
| |
| int col = getViewer()->xToColumn(e->pos().x()); |
| FunctionTreeModel::Channel *channel = m_sheet->getChannel(col); |
| if (!channel) { |
| setToolTip(QString("")); |
| } else |
| setToolTip(channel->getExprRefName()); |
| } |
| |
| |
| |
| void FunctionSheetColumnHeadViewer::mousePressEvent(QMouseEvent *e) |
| { |
| QPoint pos = e->pos(); |
| int currentC = getViewer()->xToColumn(pos.x()); |
| FunctionTreeModel::Channel *channel; |
| for (int c = 0; c <= m_sheet->getChannelCount(); c++) { |
| channel = m_sheet->getChannel(c); |
| if (!channel || c != currentC) |
| continue; |
| break; |
| } |
| if (channel && e->button() == Qt::MidButton) { |
| m_draggingChannel = channel; |
| m_dragStartPosition = e->pos(); |
| return; |
| } else if (channel) |
| channel->setIsCurrent(true); |
| m_draggingChannel = 0; |
| if (!channel) |
| return; |
| |
| |
| FunctionTreeModel::ChannelGroup *channelGroup = channel->getChannelGroup(); |
| if (!channelGroup->isOpen()) |
| channelGroup->getModel()->setExpandedItem(channelGroup->createIndex(), true); |
| |
| std::set<double> frames; |
| channel->getParam()->getKeyframes(frames); |
| |
| QRect rect(0, 0, 0, 0); |
| if (!frames.empty()) |
| rect = QRect(currentC, 0, 1, (*frames.rbegin()) + 1); |
| |
| getViewer()->selectCells(rect); |
| } |
| |
| |
| |
| void FunctionSheetColumnHeadViewer::contextMenuEvent(QContextMenuEvent *ce) |
| { |
| |
| const QPoint &pos = ce->pos(); |
| int cursorCol = getViewer()->xToColumn(pos.x()); |
| |
| if (cursorCol < 0 || cursorCol >= m_sheet->getChannelCount()) |
| return; |
| |
| FunctionTreeModel::Channel *channel = m_sheet->getChannel(cursorCol); |
| if (!channel) |
| return; |
| |
| |
| FunctionViewer *fv = m_sheet->getViewer(); |
| if (!fv) { |
| assert(fv); |
| return; |
| } |
| |
| const QPoint &globalPos = mapToGlobal(pos); |
| |
| if (pos.y() >= cChannelNameY) |
| fv->openContextMenu(channel, globalPos); |
| else { |
| FunctionTreeModel::ChannelGroup *group = channel->getChannelGroup(); |
| |
| |
| |
| QMenu menu; |
| |
| QAction showAnimatedOnly(FunctionTreeView::tr("Show Animated Only"), 0); |
| QAction showAll(FunctionTreeView::tr("Show All"), 0); |
| menu.addAction(&showAnimatedOnly); |
| menu.addAction(&showAll); |
| |
| |
| QAction *action = menu.exec(globalPos); |
| |
| if (action != &showAll && action != &showAnimatedOnly) |
| return; |
| |
| |
| if (action == &showAll) { |
| int c, cCount = group->getChildCount(); |
| for (c = 0; c != cCount; ++c) { |
| FunctionTreeModel::Channel *channel = dynamic_cast<FunctionTreeModel::Channel *>(group->getChild(c)); |
| if (channel && !channel->isHidden()) |
| channel->setIsActive(true); |
| } |
| } else if (action == &showAnimatedOnly) { |
| int c, cCount = group->getChildCount(); |
| for (c = 0; c != cCount; ++c) { |
| FunctionTreeModel::Channel *channel = dynamic_cast<FunctionTreeModel::Channel *>(group->getChild(c)); |
| if (channel && !channel->isHidden()) |
| channel->setIsActive(channel->isAnimated()); |
| } |
| } |
| |
| fv->update(); |
| } |
| } |
| |
| |
| |
| |
| |
| FunctionSheetCellViewer::FunctionSheetCellViewer(FunctionSheet *parent) |
| : Spreadsheet::CellPanel(parent), m_sheet(parent), m_editRow(0), m_editCol(0) |
| { |
| m_lineEdit = new DVGui::LineEdit(this); |
| |
| m_lineEdit->hide(); |
| bool ret = connect(m_lineEdit, SIGNAL(editingFinished()), this, SLOT(onCellEditorEditingFinished())); |
| assert(ret); |
| setMouseTracking(true); |
| |
| setFocusProxy(m_lineEdit); |
| } |
| |
| |
| |
| |
| Spreadsheet::DragTool *FunctionSheetCellViewer::createDragTool(QMouseEvent *e) |
| { |
| int row = getViewer()->yToRow(e->pos().y()); |
| int col = getViewer()->xToColumn(e->pos().x()); |
| bool isEmpty = true; |
| TDoubleParam *curve = m_sheet->getCurve(col); |
| if (curve) { |
| int kCount = curve->getKeyframeCount(); |
| if (kCount > 0) { |
| int row0 = (int)curve->keyframeIndexToFrame(0); |
| int row1 = (int)curve->keyframeIndexToFrame(kCount - 1); |
| isEmpty = row < row0 || row > row1; |
| } |
| } |
| |
| if (!isEmpty) { |
| int x = e->pos().x() - getViewer()->columnToX(col); |
| if (0 <= x && x < cColumnDragHandleWidth + 9) |
| return new MoveChannelsDragTool(m_sheet); |
| } |
| return new FunctionSheetSelectionTool(m_sheet); |
| |
| |
| } |
| |
| |
| |
| void FunctionSheetCellViewer::drawCells(QPainter &painter, int r0, int c0, int r1, int c1) |
| { |
| |
| QColor KeyFrameColor = getViewer()->getKeyFrameColor(); |
| QColor KeyFrameBorderColor = getViewer()->getKeyFrameBorderColor(); |
| QColor SelectedKeyFrameColor = getViewer()->getSelectedKeyFrameColor(); |
| |
| QColor InBetweenColor = getViewer()->getInBetweenColor(); |
| QColor InBetweenBorderColor = getViewer()->getInBetweenBorderColor(); |
| QColor SelectedInBetweenColor = getViewer()->getSelectedInBetweenColor(); |
| |
| QColor SelectedEmptyColor = getViewer()->getSelectedEmptyColor(); |
| |
| QColor SelectedSceneRangeEmptyColor = getViewer()->getSelectedSceneRangeEmptyColor(); |
| |
| |
| int y0 = getViewer()->rowToY(r0); |
| int y1 = getViewer()->rowToY(r1 + 1) - 1; |
| for (int c = c0; c <= c1; c++) { |
| TDoubleParam *curve = m_sheet->getCurve(c); |
| |
| if (!curve) |
| continue; |
| |
| int x0 = getViewer()->columnToX(c); |
| int x1 = getViewer()->columnToX(c + 1) - 1; |
| |
| |
| int kr0 = 0, kr1 = -1; |
| int kCount = curve->getKeyframeCount(); |
| if (kCount > 0) { |
| kr0 = curve->keyframeIndexToFrame(0); |
| kr1 = curve->keyframeIndexToFrame(kCount - 1); |
| } |
| |
| |
| TMeasure *measure = curve->getMeasure(); |
| const TUnit *unit = measure ? measure->getCurrentUnit() : 0; |
| |
| |
| for (int row = r0; row <= r1; row++) { |
| int ya = m_sheet->rowToY(row); |
| int yb = m_sheet->rowToY(row + 1) - 1; |
| |
| bool isSelected = getViewer()->isSelectedCell(row, c); |
| |
| double value = curve->getValue(row); |
| if (unit) |
| value = unit->convertTo(value); |
| |
| QRect cellRect(x0, ya, x1 - x0 + 1, yb - ya + 1); |
| QRect borderRect(x0, ya, 7, yb - ya + 1); |
| QColor cellColor, borderColor; |
| |
| |
| if (kr0 <= row && row <= kr1) { |
| if (curve->isKeyframe(row)) { |
| cellColor = (isSelected) ? SelectedKeyFrameColor : KeyFrameColor; |
| borderColor = KeyFrameBorderColor; |
| } else { |
| cellColor = (isSelected) ? SelectedInBetweenColor : InBetweenColor; |
| borderColor = InBetweenBorderColor; |
| } |
| painter.setPen(Qt::NoPen); |
| painter.fillRect(cellRect, cellColor); |
| painter.fillRect(borderRect, borderColor); |
| |
| |
| if (curve->isKeyframe(row)) { |
| TDoubleKeyframe kf = curve->getKeyframeAt(row); |
| |
| if (!kf.m_linkedHandles) { |
| int rowCenterPos = (ya + yb) / 2; |
| QPoint points[4] = { |
| QPoint(x0, rowCenterPos), |
| QPoint(x0 + 7, rowCenterPos + 3), |
| QPoint(x0 + 7, rowCenterPos - 3), |
| QPoint(x0, rowCenterPos)}; |
| QBrush oldBrush = painter.brush(); |
| painter.setBrush(QBrush(cellColor)); |
| painter.drawPolygon(points, 4); |
| painter.setBrush(oldBrush); |
| } |
| } |
| |
| |
| painter.setPen(getViewer()->getTextColor()); |
| |
| |
| QString text; |
| |
| double thousandValue = value * 1000.0; |
| if (areAlmostEqual(thousandValue, (double)tround(thousandValue), 0.0001)) { |
| text = QString::number(value, 'f', 3); |
| while (text.endsWith("0")) { |
| text.chop(1); |
| if (text.endsWith(".")) { |
| text.chop(1); |
| break; |
| } |
| } |
| } else { |
| text = QString::number(value, 'f', 4); |
| text.truncate(5); |
| text.append("~"); |
| } |
| |
| #ifdef WIN32 |
| static QFont font("Arial", 9, QFont::Normal); |
| #else |
| static QFont font("Helvetica", 9, QFont::Normal); |
| #endif |
| painter.setFont(font); |
| painter.drawText(cellRect.adjusted(10, 0, 0, 0), Qt::AlignVCenter | Qt::AlignLeft, text); |
| } |
| |
| else if (isSelected) { |
| int rowCount = getViewer()->getRowCount(); |
| cellColor = (row >= rowCount) ? SelectedEmptyColor : SelectedSceneRangeEmptyColor; |
| painter.setPen(Qt::NoPen); |
| painter.fillRect(cellRect, cellColor); |
| } |
| } |
| } |
| } |
| |
| |
| |
| void FunctionSheetCellViewer::mouseDoubleClickEvent(QMouseEvent *e) |
| { |
| int row = getViewer()->yToRow(e->pos().y()); |
| int col = getViewer()->xToColumn(e->pos().x()); |
| int x0, y0, x1, y1; |
| x0 = getViewer()->columnToX(col); |
| x1 = getViewer()->columnToX(col + 1) - 1; |
| y0 = getViewer()->rowToY(row); |
| y1 = getViewer()->rowToY(row + 1) - 1; |
| |
| m_editRow = row; |
| m_editCol = col; |
| |
| TDoubleParam *curve = m_sheet->getCurve(col); |
| if (curve) { |
| double v = curve->getValue(row); |
| TMeasure *measure = curve->getMeasure(); |
| const TUnit *unit = measure ? measure->getCurrentUnit() : 0; |
| if (unit) |
| v = unit->convertTo(v); |
| |
| m_lineEdit->setText(QString::number(v, 'f', 4)); |
| |
| m_lineEdit->setSelection(m_lineEdit->text().length(), -m_lineEdit->text().length()); |
| } else |
| m_lineEdit->setText(""); |
| |
| #ifdef WIN32 |
| static QFont font("Arial", 9, QFont::Normal); |
| #else |
| static QFont font("Helvetica", 9, QFont::Normal); |
| #endif |
| m_lineEdit->setFont(font); |
| |
| m_lineEdit->setGeometry(x0 - 2, y0 - 2, x1 - x0 + 1 + 4, y1 - y0 + 1 + 4); |
| m_lineEdit->show(); |
| m_lineEdit->raise(); |
| m_lineEdit->setFocus(); |
| } |
| |
| |
| |
| void FunctionSheetCellViewer::onCellEditorEditingFinished() |
| { |
| QString text = m_lineEdit->text(); |
| if (!text.isEmpty() && m_lineEdit->isReturnPressed()) { |
| double value = text.toDouble(); |
| TDoubleParam *curve = m_sheet->getCurve(m_editCol); |
| if (curve) { |
| TMeasure *measure = curve->getMeasure(); |
| const TUnit *unit = measure ? measure->getCurrentUnit() : 0; |
| if (unit) |
| value = unit->convertFrom(value); |
| KeyframeSetter::setValue(curve, m_editRow, value); |
| } |
| } |
| m_lineEdit->hide(); |
| m_lineEdit->clearFocus(); |
| m_sheet->setFocus(); |
| update(); |
| } |
| |
| |
| |
| void FunctionSheetCellViewer::mousePressEvent(QMouseEvent *e) |
| { |
| |
| if (m_lineEdit->isVisible()) { |
| m_lineEdit->hide(); |
| m_lineEdit->clearFocus(); |
| m_sheet->setFocus(); |
| } |
| |
| if (e->button() == Qt::LeftButton || e->button() == Qt::MidButton) |
| Spreadsheet::CellPanel::mousePressEvent(e); |
| else if (e->button() == Qt::RightButton) { |
| int row = getViewer()->yToRow(e->pos().y()); |
| int col = getViewer()->xToColumn(e->pos().x()); |
| update(); |
| openContextMenu(e); |
| } |
| } |
| |
| |
| |
| void FunctionSheetCellViewer::mouseReleaseEvent(QMouseEvent *e) |
| { |
| Spreadsheet::CellPanel::mouseReleaseEvent(e); |
| |
| |
| |
| |
| |
| |
| |
| } |
| |
| |
| |
| void FunctionSheetCellViewer::mouseMoveEvent(QMouseEvent *e) |
| { |
| Spreadsheet::CellPanel::mouseMoveEvent(e); |
| } |
| |
| |
| |
| |
| void FunctionSheetCellViewer::openContextMenu(QMouseEvent *e) |
| { |
| struct locals { |
| static void sheet__setSegmentType( |
| FunctionSelection *selection, |
| TDoubleParam *curve, |
| int segmentIndex, |
| TDoubleKeyframe::Type type) |
| { |
| selection->selectSegment(curve, segmentIndex); |
| KeyframeSetter setter(curve, segmentIndex); |
| setter.setType(type); |
| } |
| }; |
| |
| QAction deleteKeyframeAction(tr("Delete Key"), 0); |
| QAction insertKeyframeAction(tr("Set Key"), 0); |
| QAction setLinearAction(tr("Linear Interpolation"), 0); |
| QAction setSpeedInOutAction(tr("Speed In / Speed Out Interpolation"), 0); |
| QAction setEaseInOutAction(tr("Ease In / Ease Out Interpolation"), 0); |
| QAction setEaseInOut2Action(tr("Ease In / Ease Out (%) Interpolation"), 0); |
| QAction setExponentialAction(tr("Exponential Interpolation"), 0); |
| QAction setExpressionAction(tr("Expression Interpolation"), 0); |
| QAction setFileAction(tr("File Interpolation"), 0); |
| QAction setConstantAction(tr("Constant Interpolation"), 0); |
| QAction setStep1Action(tr("Step 1"), 0); |
| QAction setStep2Action(tr("Step 2"), 0); |
| QAction setStep3Action(tr("Step 3"), 0); |
| QAction setStep4Action(tr("Step 4"), 0); |
| |
| int row = getViewer()->yToRow(e->pos().y()); |
| int col = getViewer()->xToColumn(e->pos().x()); |
| TDoubleParam *curve = m_sheet->getCurve(col); |
| if (!curve) |
| return; |
| |
| bool isEmpty = true; |
| bool isKeyframe = false; |
| |
| |
| int kCount = curve->getKeyframeCount(); |
| if (kCount > 0) { |
| if (curve->keyframeIndexToFrame(0) <= row && |
| row <= curve->keyframeIndexToFrame(kCount - 1)) { |
| isEmpty = false; |
| isKeyframe = curve->isKeyframe(row); |
| } |
| } |
| int kIndex = curve->getPrevKeyframe(row); |
| |
| |
| QMenu menu(0); |
| if (!isKeyframe) |
| menu.addAction(&insertKeyframeAction); |
| |
| if (!isEmpty && !isKeyframe && kIndex >= 0) { |
| menu.addSeparator(); |
| TDoubleKeyframe kf = curve->getKeyframe(kIndex); |
| if (kf.m_type != TDoubleKeyframe::Linear) |
| menu.addAction(&setLinearAction); |
| if (kf.m_type != TDoubleKeyframe::SpeedInOut) |
| menu.addAction(&setSpeedInOutAction); |
| if (kf.m_type != TDoubleKeyframe::EaseInOut) |
| menu.addAction(&setEaseInOutAction); |
| if (kf.m_type != TDoubleKeyframe::EaseInOutPercentage) |
| menu.addAction(&setEaseInOut2Action); |
| if (kf.m_type != TDoubleKeyframe::Exponential) |
| menu.addAction(&setExponentialAction); |
| if (kf.m_type != TDoubleKeyframe::Expression) |
| menu.addAction(&setExpressionAction); |
| if (kf.m_type != TDoubleKeyframe::File) |
| menu.addAction(&setFileAction); |
| if (kf.m_type != TDoubleKeyframe::Constant) |
| menu.addAction(&setConstantAction); |
| menu.addSeparator(); |
| if (kf.m_step != 1) |
| menu.addAction(&setStep1Action); |
| if (kf.m_step != 2) |
| menu.addAction(&setStep2Action); |
| if (kf.m_step != 3) |
| menu.addAction(&setStep3Action); |
| if (kf.m_step != 4) |
| menu.addAction(&setStep4Action); |
| } |
| |
| menu.addSeparator(); |
| |
| CommandManager *cmdManager = CommandManager::instance(); |
| menu.addAction(cmdManager->getAction("MI_Cut")); |
| menu.addAction(cmdManager->getAction("MI_Copy")); |
| menu.addAction(cmdManager->getAction("MI_Paste")); |
| menu.addAction(cmdManager->getAction("MI_Clear")); |
| |
| menu.addAction(cmdManager->getAction("MI_Insert")); |
| |
| FunctionSelection *selection = m_sheet->getSelection(); |
| |
| |
| QAction *action = menu.exec(e->globalPos()); |
| if (action == &deleteKeyframeAction) { |
| KeyframeSetter::removeKeyframeAt(curve, row); |
| } else if (action == &insertKeyframeAction) { |
| KeyframeSetter(curve).createKeyframe(row); |
| } else if (action == &setLinearAction) |
| locals::sheet__setSegmentType(selection, curve, kIndex, TDoubleKeyframe::Linear); |
| else if (action == &setSpeedInOutAction) |
| locals::sheet__setSegmentType(selection, curve, kIndex, TDoubleKeyframe::SpeedInOut); |
| else if (action == &setEaseInOutAction) |
| locals::sheet__setSegmentType(selection, curve, kIndex, TDoubleKeyframe::EaseInOut); |
| else if (action == &setEaseInOut2Action) |
| locals::sheet__setSegmentType(selection, curve, kIndex, TDoubleKeyframe::EaseInOutPercentage); |
| else if (action == &setExponentialAction) |
| locals::sheet__setSegmentType(selection, curve, kIndex, TDoubleKeyframe::Exponential); |
| else if (action == &setExpressionAction) |
| locals::sheet__setSegmentType(selection, curve, kIndex, TDoubleKeyframe::Expression); |
| else if (action == &setFileAction) |
| locals::sheet__setSegmentType(selection, curve, kIndex, TDoubleKeyframe::File); |
| else if (action == &setConstantAction) |
| locals::sheet__setSegmentType(selection, curve, kIndex, TDoubleKeyframe::Constant); |
| else if (action == &setStep1Action) |
| KeyframeSetter(curve, kIndex).setStep(1); |
| else if (action == &setStep2Action) |
| KeyframeSetter(curve, kIndex).setStep(2); |
| else if (action == &setStep3Action) |
| KeyframeSetter(curve, kIndex).setStep(3); |
| else if (action == &setStep4Action) |
| KeyframeSetter(curve, kIndex).setStep(4); |
| |
| update(); |
| } |
| |
| |
| |
| |
| |
| class FunctionSheetColumnToCurveMapper : public ColumnToCurveMapper |
| { |
| FunctionSheet *m_sheet; |
| |
| public: |
| FunctionSheetColumnToCurveMapper(FunctionSheet *sheet) : m_sheet(sheet) {} |
| TDoubleParam *getCurve(int columnIndex) const |
| { |
| FunctionTreeModel::Channel *channel = m_sheet->getChannel(columnIndex); |
| if (channel) |
| return channel->getParam(); |
| else |
| return 0; |
| } |
| }; |
| |
| |
| |
| |
| |
| FunctionSheet::FunctionSheet(QWidget *parent) |
| : SpreadsheetViewer(parent), m_selectedCells(), m_selection(0) |
| { |
| setColumnsPanel(m_columnHeadViewer = new FunctionSheetColumnHeadViewer(this)); |
| setRowsPanel(m_rowViewer = new FunctionSheetRowViewer(this)); |
| setCellsPanel(m_cellViewer = new FunctionSheetCellViewer(this)); |
| |
| setColumnCount(20); |
| } |
| |
| |
| |
| FunctionSheet::~FunctionSheet() |
| { |
| } |
| |
| |
| |
| bool FunctionSheet::anyWidgetHasFocus() |
| { |
| return hasFocus() || |
| m_rowViewer->hasFocus() || |
| m_columnHeadViewer->hasFocus() || |
| m_cellViewer->hasFocus(); |
| } |
| |
| |
| |
| void FunctionSheet::setSelection(FunctionSelection *selection) |
| { |
| m_selection = selection; |
| m_selection->setColumnToCurveMapper(new FunctionSheetColumnToCurveMapper(this)); |
| } |
| |
| |
| |
| void FunctionSheet::showEvent(QShowEvent *e) |
| { |
| registerFrameScroller(); |
| SpreadsheetViewer::showEvent(e); |
| } |
| |
| |
| |
| void FunctionSheet::hideEvent(QHideEvent *e) |
| { |
| unregisterFrameScroller(); |
| SpreadsheetViewer::hideEvent(e); |
| } |
| |
| |
| |
| void FunctionSheet::onFrameSwitched() |
| { |
| setCurrentRow(getCurrentFrame()); |
| m_rowViewer->update(); |
| m_cellViewer->update(); |
| } |
| |
| |
| |
| void FunctionSheet::setCurrentFrame(int frame) |
| { |
| if (getFrameHandle()) |
| getFrameHandle()->setFrame(frame); |
| } |
| |
| |
| |
| int FunctionSheet::getCurrentFrame() const |
| { |
| return getFrameHandle() ? getFrameHandle()->getFrame() : 0; |
| } |
| |
| |
| |
| int FunctionSheet::getChannelCount() |
| { |
| if (m_functionTreeModel == 0) |
| return 0; |
| else |
| return m_functionTreeModel->getActiveChannelCount(); |
| } |
| |
| |
| |
| FunctionTreeModel::Channel *FunctionSheet::getChannel(int column) |
| { |
| if (m_functionTreeModel == 0) |
| return 0; |
| else |
| return m_functionTreeModel->getActiveChannel(column); |
| } |
| |
| |
| |
| TDoubleParam *FunctionSheet::getCurve(int column) |
| { |
| FunctionTreeModel::Channel *channel = getChannel(column); |
| return channel ? channel->getParam() : 0; |
| } |
| |
| |
| |
| void FunctionSheet::setModel(FunctionTreeModel *model) |
| { |
| m_functionTreeModel = model; |
| } |
| |
| |
| |
| void FunctionSheet::setViewer(FunctionViewer *viewer) |
| { |
| m_functionViewer = viewer; |
| } |
| |
| |
| |
| QRect FunctionSheet::getSelectedCells() const |
| { |
| if (getSelection()) |
| return getSelection()->getSelectedCells(); |
| else |
| return QRect(); |
| } |
| |
| |
| |
| void FunctionSheet::selectCells(const QRect &selectedCells) |
| { |
| m_selectedCells = selectedCells; |
| if (getSelection()) { |
| QList<TDoubleParam *> curves; |
| for (int c = selectedCells.left(); c <= selectedCells.right(); c++) { |
| TDoubleParam *param = 0; |
| if (c < getChannelCount()) |
| param = getChannel(c)->getParam(); |
| curves.push_back(param); |
| } |
| getSelection()->selectCells(selectedCells, curves); |
| |
| if (selectedCells.width() == 1 && curves[0] && !getChannel(selectedCells.x())->isCurrent()) |
| getChannel(selectedCells.x())->setIsCurrent(true); |
| } |
| |
| updateAll(); |
| } |
| |
| |
| |
| void FunctionSheet::updateAll() |
| { |
| m_rowViewer->update(); |
| m_columnHeadViewer->update(); |
| m_cellViewer->update(); |
| setColumnCount(getChannelCount()); |
| } |
| |
| |
| |
| |
| QString FunctionSheet::getSelectedParamName() |
| { |
| if (m_functionTreeModel->getCurrentChannel()) |
| return m_functionTreeModel->getCurrentChannel()->getExprRefName(); |
| else |
| return QString(); |
| } |
| |
| |
| |
| int FunctionSheet::getColumnIndexByCurve(TDoubleParam *param) const |
| { |
| return m_functionTreeModel->getColumnIndexByCurve(param); |
| } |
| |
| |
| |
| |
| void FunctionSheet::onCurrentChannelChanged(FunctionTreeModel::Channel *channel) |
| { |
| if (!channel) |
| return; |
| for (int c = 0; c < getChannelCount(); c++) { |
| FunctionTreeModel::Channel *tmpChan = getChannel(c); |
| |
| if (tmpChan == channel) { |
| ensureVisibleCol(c); |
| return; |
| } |
| } |
| } |
| |