Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonzqt/functionsheet.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzQt includes
Toshihiro Shimizu 890ddd
#include "toonzqt/gutil.h"
Toshihiro Shimizu 890ddd
#include "toonzqt/functionviewer.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzLib includes
Toshihiro Shimizu 890ddd
#include "toonz/tframehandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/doubleparamcmd.h"
Toshihiro Shimizu 890ddd
#include "toonz/preferences.h"
Jeremy Bullock 4ce953
#include "toonz/toonzfolders.h"
shun_iwasawa 768e20
#include "toonz/tstageobject.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzBase includes
Toshihiro Shimizu 890ddd
#include "tunit.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "../toonz/menubarcommandids.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Qt includes
Toshihiro Shimizu 890ddd
#include <qpainter></qpainter>
Toshihiro Shimizu 890ddd
#include <qgridlayout></qgridlayout>
Toshihiro Shimizu 890ddd
#include <qpaintevent></qpaintevent>
Toshihiro Shimizu 890ddd
#include <qmenu></qmenu>
Shinya Kitaoka 120a6e
#include <qapplication>  //for drag&drop</qapplication>
Toshihiro Shimizu 890ddd
#include <qdrag></qdrag>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
//    Local namespace stuff
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
const int cColumnDragHandleWidth = 8;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
const int cGroupShortNameY =
Shinya Kitaoka 120a6e
    0;  //!< Column header's y pos for channel groups' short name tabs
Shinya Kitaoka 120a6e
const int cGroupLongNameY = 27;  //!< Same for its long name tabs
Shinya Kitaoka 120a6e
const int cChannelNameY = 50;  //!< Column header's y pos of channel name tabs,
Shinya Kitaoka 38fd86
                               //! up to the widget's height
Shinya Kitaoka 120a6e
const int cColHeadersEndY = 87;  //!< End of column headers y pos
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
//    Function Sheet Tools
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*--- NumericalColumnsのセグメントの左側のバーをクリックしたとき ---*/
Shinya Kitaoka d1f6c4
class MoveChannelsDragTool final : public Spreadsheet::DragTool {
Shinya Kitaoka 120a6e
  FunctionSheet *m_sheet;
Shinya Kitaoka 120a6e
  std::vector<keyframesetter *=""> m_setters;</keyframesetter>
Shinya Kitaoka 120a6e
  int m_oldRow;
Shinya Kitaoka 120a6e
  QRect m_selectedCells;
Shinya Kitaoka 120a6e
  int m_firstKeyframeRow;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  MoveChannelsDragTool(FunctionSheet *sheet)
Shinya Kitaoka 120a6e
      : m_sheet(sheet), m_firstKeyframeRow(-1) {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void click(int row, int col, QMouseEvent *e) override {
Shinya Kitaoka 120a6e
    m_firstKeyframeRow                  = -1;
Shinya Kitaoka 120a6e
    FunctionTreeModel::Channel *channel = m_sheet->getChannel(col);
Shinya Kitaoka 120a6e
    if (!channel) return;
Shinya Kitaoka 120a6e
    TDoubleParam *curve = channel->getParam();
Shinya Kitaoka 120a6e
    int k0 = -1, k1 = -1;
Shinya Kitaoka 120a6e
    if (curve->isKeyframe(row))
Shinya Kitaoka 120a6e
      k0 = k1 = curve->getClosestKeyframe(row);
Shinya Kitaoka 120a6e
    else {
Shinya Kitaoka 120a6e
      k0 = curve->getPrevKeyframe(row);
Shinya Kitaoka 120a6e
      k1 = curve->getNextKeyframe(row);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    // return if clicking outside of the segments
Shinya Kitaoka 120a6e
    if (k0 < 0 || k1 < 0) return;
Shinya Kitaoka 120a6e
    int r0 = tround(curve->keyframeIndexToFrame(k0));
Shinya Kitaoka 120a6e
    int r1 = tround(curve->keyframeIndexToFrame(k1));
Shinya Kitaoka 120a6e
    if (m_sheet->isSelectedCell(row, col)) {
Shinya Kitaoka 120a6e
      m_selectedCells = m_sheet->getSelectedCells();
Shinya Kitaoka 120a6e
      m_selectedCells.setTop(r0);
Shinya Kitaoka 120a6e
      m_selectedCells.setBottom(r1);
Shinya Kitaoka 120a6e
    } else
Shinya Kitaoka 120a6e
      m_selectedCells = QRect(col, r0, 1, r1 - r0 + 1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_sheet->selectCells(m_selectedCells);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    /*---
Shinya Kitaoka 120a6e
シンプルに左のバーをクリックした場合はcolは1つだけ。
Shinya Kitaoka 120a6e
すでに複数Columnが選択されている上でその選択範囲内のセルの左バーをクリックした場合は
Shinya Kitaoka 120a6e
横(Column)幅は選択範囲に順ずるようになる。高さ(row)はクリックしたセグメントと同じになる。
Shinya Kitaoka 120a6e
---*/
Shinya Kitaoka 120a6e
    /*--- セグメントごとドラッグに備えてKeyFrameを格納する ---*/
Shinya Kitaoka 120a6e
    for (int col = m_selectedCells.left(); col <= m_selectedCells.right();
Shinya Kitaoka 120a6e
         ++col) {
Shinya Kitaoka 120a6e
      TDoubleParam *curve = m_sheet->getCurve(col);
Shinya Kitaoka 120a6e
      if (!curve) continue;
Shinya Kitaoka 120a6e
      KeyframeSetter *setter = new KeyframeSetter(curve);
Shinya Kitaoka 120a6e
      for (int k = 0; k < curve->getKeyframeCount(); k++) {
Shinya Kitaoka 120a6e
        int row = (int)curve->keyframeIndexToFrame(k);
Shinya Kitaoka 120a6e
        if (r0 <= row && row <= r1) {
Shinya Kitaoka 120a6e
          if (m_firstKeyframeRow < 0 || row < m_firstKeyframeRow)
Shinya Kitaoka 120a6e
            m_firstKeyframeRow = row;
Shinya Kitaoka 120a6e
          setter->selectKeyframe(k);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      m_setters.push_back(setter);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    m_oldRow = row;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void drag(int row, int col, QMouseEvent *e) override {
shun-iwasawa 260cd7
    int d    = row - m_oldRow;
shun-iwasawa 260cd7
    m_oldRow = row;
Shinya Kitaoka 120a6e
    if (d + m_firstKeyframeRow < 0) d = -m_firstKeyframeRow;
Shinya Kitaoka 120a6e
    m_firstKeyframeRow += d;
Shinya Kitaoka 120a6e
    for (int i = 0; i < (int)m_setters.size(); i++)
Shinya Kitaoka 120a6e
      m_setters[i]->moveKeyframes(d, 0.0);
Shinya Kitaoka 120a6e
    m_selectedCells.translate(0, d);
Shinya Kitaoka 120a6e
    m_sheet->selectCells(m_selectedCells);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void release(int row, int col, QMouseEvent *e) override {
Shinya Kitaoka 120a6e
    for (int i = 0; i < (int)m_setters.size(); i++) delete m_setters[i];
Shinya Kitaoka 120a6e
    m_setters.clear();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*--- NumericalColumnsのセル部分をクリックしたとき ---*/
Shinya Kitaoka d1f6c4
class FunctionSheetSelectionTool final : public Spreadsheet::DragTool {
Shinya Kitaoka 120a6e
  int m_firstRow, m_firstCol;
Shinya Kitaoka 120a6e
  FunctionSheet *m_sheet;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  FunctionSheetSelectionTool(FunctionSheet *sheet)
Shinya Kitaoka 120a6e
      : m_sheet(sheet), m_firstRow(-1), m_firstCol(-1) {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void click(int row, int col, QMouseEvent *e) override {
Shinya Kitaoka 120a6e
    if (0 != (e->modifiers() & Qt::ShiftModifier) &&
Shinya Kitaoka 120a6e
        !m_sheet->getSelectedCells().isEmpty()) {
Shinya Kitaoka 120a6e
      QRect selectedCells = m_sheet->getSelectedCells();
Shinya Kitaoka 120a6e
      if (col < selectedCells.center().x()) {
Shinya Kitaoka 120a6e
        m_firstCol = selectedCells.right();
Shinya Kitaoka 120a6e
        selectedCells.setLeft(col);
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        m_firstCol = selectedCells.left();
Shinya Kitaoka 120a6e
        selectedCells.setRight(col);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      if (row < selectedCells.center().y()) {
Shinya Kitaoka 120a6e
        m_firstRow = selectedCells.bottom();
Shinya Kitaoka 120a6e
        selectedCells.setTop(row);
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        m_firstRow = selectedCells.top();
Shinya Kitaoka 120a6e
        selectedCells.setBottom(row);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      m_sheet->selectCells(selectedCells);
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      // regular click, no shift
Shinya Kitaoka 120a6e
      m_firstCol = col;
Shinya Kitaoka 120a6e
      m_firstRow = row;
Shinya Kitaoka 120a6e
      QRect selectedCells(col, row, 1, 1);
Shinya Kitaoka 120a6e
      m_sheet->selectCells(selectedCells);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void drag(int row, int col, QMouseEvent *e) override {
Shinya Kitaoka 120a6e
    if (row < 0) row = 0;
Shinya Kitaoka 120a6e
    if (col < 0) col = 0;
shun-iwasawa 875c7e
    int r0 = std::min(row, m_firstRow);
shun-iwasawa 875c7e
    int r1 = std::max(row, m_firstRow);
shun-iwasawa 875c7e
    int c0 = std::min(col, m_firstCol);
shun-iwasawa 875c7e
    int c1 = std::max(col, m_firstCol);
Shinya Kitaoka 120a6e
    QRect selectedCells(c0, r0, c1 - c0 + 1, r1 - r0 + 1);
Shinya Kitaoka 120a6e
    m_sheet->selectCells(selectedCells);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void release(int row, int col, QMouseEvent *e) override {
Shinya Kitaoka 120a6e
    if (row == m_firstRow && col == m_firstCol) {
Shinya Kitaoka 120a6e
      if (Preferences::instance()->isMoveCurrentEnabled())
Shinya Kitaoka 120a6e
        m_sheet->setCurrentFrame(row);
Shinya Kitaoka 120a6e
      FunctionTreeModel::Channel *channel = m_sheet->getChannel(col);
Shinya Kitaoka 120a6e
      if (channel) channel->setIsCurrent(true);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
//    FunctionSheetRowViewer  implementation
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
FunctionSheetRowViewer::FunctionSheetRowViewer(FunctionSheet *parent)
Shinya Kitaoka 120a6e
    : Spreadsheet::RowPanel(parent), m_sheet(parent) {
Shinya Kitaoka 120a6e
  setMinimumSize(QSize(100, 100));
Shinya Kitaoka 120a6e
  setMouseTracking(true);
Shinya Kitaoka 120a6e
  setFocusPolicy(Qt::NoFocus);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionSheetRowViewer::paintEvent(QPaintEvent *e) {
Shinya Kitaoka 120a6e
  // calls GenericPanel's event
Shinya Kitaoka 120a6e
  Spreadsheet::RowPanel::paintEvent(e);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionSheetRowViewer::mousePressEvent(QMouseEvent *e) {
Shinya Kitaoka 120a6e
  // calls GenericPanel's event
Shinya Kitaoka 120a6e
  Spreadsheet::RowPanel::mousePressEvent(e);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionSheetRowViewer::mouseMoveEvent(QMouseEvent *e) {
Shinya Kitaoka 120a6e
  // calls GenericPanel's event
Shinya Kitaoka 120a6e
  Spreadsheet::RowPanel::mouseMoveEvent(e);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionSheetRowViewer::mouseReleaseEvent(QMouseEvent *e) {
Shinya Kitaoka 120a6e
  Spreadsheet::RowPanel::mouseReleaseEvent(e);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionSheetRowViewer::contextMenuEvent(QContextMenuEvent *event) {
Shinya Kitaoka 120a6e
  QMenu *menu                = new QMenu(this);
Shinya Kitaoka 120a6e
  CommandManager *cmdManager = CommandManager::instance();
Shinya Kitaoka 120a6e
  menu->addAction(cmdManager->getAction(MI_InsertSceneFrame));
Shinya Kitaoka 120a6e
  menu->addAction(cmdManager->getAction(MI_RemoveSceneFrame));
Shinya Kitaoka 120a6e
  menu->addAction(cmdManager->getAction(MI_InsertGlobalKeyframe));
Shinya Kitaoka 120a6e
  menu->addAction(cmdManager->getAction(MI_RemoveGlobalKeyframe));
Shinya Kitaoka 120a6e
  menu->exec(event->globalPos());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
//    FunctionSheetColumnHeadViewer  implementation
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
FunctionSheetColumnHeadViewer::FunctionSheetColumnHeadViewer(
Shinya Kitaoka 120a6e
    FunctionSheet *parent)
Shinya Kitaoka 120a6e
    : Spreadsheet::ColumnPanel(parent), m_sheet(parent), m_draggingChannel(0) {
Shinya Kitaoka 120a6e
  setMouseTracking(true);  // for updating the tooltip
Shinya Kitaoka 120a6e
  setFocusPolicy(Qt::NoFocus);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionSheetColumnHeadViewer::paintEvent(QPaintEvent *e) {
Shinya Kitaoka 120a6e
  QPainter painter(this);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QRect toBeUpdated = e->rect();
Shinya Kitaoka 120a6e
  painter.setClipRect(toBeUpdated);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // visible columns range
Jaroslav 203cc8
  CellRange visible = getViewer()->xyRectToRange(toBeUpdated);
Jaroslav 203cc8
  int c0            = visible.from().layer();
Jaroslav 203cc8
  int c1            = visible.to().layer();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (c0 > c1) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int n = c1 - c0 + 1 + 2;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  FunctionTreeModel::ChannelGroup *currentGroup = 0;
Shinya Kitaoka 120a6e
Jaroslav 203cc8
  /*--- Display range + right and left 1 column range ChannelGroup. If there is
Jaroslav 203cc8
   * none, put 0
Shinya Kitaoka 120a6e
   * ---*/
Shinya Kitaoka 120a6e
  std::vector<functiontreemodel::channelgroup *=""> channelGroups(n);</functiontreemodel::channelgroup>
Shinya Kitaoka 120a6e
  for (int i = 0; i < n; ++i) {
Shinya Kitaoka 120a6e
    channelGroups[i] = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    int c = c0 - 1 + i;
Shinya Kitaoka 120a6e
    if (c < 0) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    FunctionTreeModel::Channel *channel = m_sheet->getChannel(c);
Shinya Kitaoka 120a6e
    if (!channel) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    channelGroups[i] = channel->getChannelGroup();
Shinya Kitaoka 120a6e
    if (!currentGroup && channel->isCurrent()) currentGroup = channelGroups[i];
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int y0 = 0;
Jaroslav 203cc8
  int y1 = 17;  // needs work
Shinya Kitaoka 120a6e
  int y2 = 34;
Shinya Kitaoka 120a6e
  int y3 = 53;
Shinya Kitaoka 120a6e
Jaroslav 203cc8
  /*--- Fill header with background color ---*/
Shinya Kitaoka 120a6e
  for (int c = c0; c <= c1; c++) {
Shinya Kitaoka 120a6e
    FunctionTreeModel::Channel *channel = m_sheet->getChannel(c);
shun-iwasawa caf3c6
    if (!channel) break;
Shinya Kitaoka 120a6e
    int x0 = getViewer()->columnToX(c);
Shinya Kitaoka 120a6e
    int x1 = getViewer()->columnToX(c + 1) - 1;
Shinya Kitaoka 120a6e
    // Column Width
Shinya Kitaoka 120a6e
    int width = x1 - x0 + 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    painter.fillRect(x0, y0, width, y3 - y0, getViewer()->getBGColor());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int c = c0; c <= c1; ++c) {
Shinya Kitaoka 120a6e
    FunctionTreeModel::Channel *channel = m_sheet->getChannel(c);
shun-iwasawa caf3c6
    if (!channel) {
shun-iwasawa caf3c6
      if (c != c0) {
shun-iwasawa caf3c6
        // draw "the end" border
shun-iwasawa caf3c6
        int x0 = getViewer()->columnToX(c);
shun-iwasawa caf3c6
        painter.setPen(getViewer()->getColumnHeaderBorderColor());
shun-iwasawa caf3c6
        painter.drawLine(x0, y0, x0, y3);
shun-iwasawa caf3c6
      }
shun-iwasawa caf3c6
      break;
shun-iwasawa caf3c6
    }
Shinya Kitaoka 120a6e
    int i = c - c0 + 1;
Jaroslav 203cc8
    /*---- Channel Column of the current Column and the preceding and following
Jaroslav 203cc8
     * Columns ---*/
Shinya Kitaoka 120a6e
    FunctionTreeModel::ChannelGroup *prevGroup = channelGroups[c - c0],
Shinya Kitaoka 120a6e
                                    *group     = channelGroups[c - c0 + 1],
Shinya Kitaoka 120a6e
                                    *nextGroup = channelGroups[c - c0 + 2];
Shinya Kitaoka 120a6e
Jaroslav 203cc8
    /*---- If the group is different from the before and after, flags are set
Jaroslav 203cc8
     * respectively ---*/
Shinya Kitaoka 120a6e
    bool firstGroupColumn = prevGroup != group;
Shinya Kitaoka 120a6e
    bool lastGroupColumn  = nextGroup != group;
Shinya Kitaoka 120a6e
Jaroslav 203cc8
    /*--- The left and right coordinates of the current column ---*/
Shinya Kitaoka 120a6e
    int x0 = getViewer()->columnToX(c);
Shinya Kitaoka 120a6e
    int x1 = getViewer()->columnToX(c + 1) - 1;
Shinya Kitaoka 120a6e
    // Column width
Shinya Kitaoka 120a6e
    int width = x1 - x0 + 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    QRect selectedRect = m_sheet->getSelectedCells();
Shinya Kitaoka 120a6e
    bool isSelected =
Shinya Kitaoka 120a6e
        (selectedRect.left() <= c && c <= selectedRect.right()) ? true : false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // paint with light color if selected
Shinya Kitaoka 120a6e
    if (isSelected)
Shinya Kitaoka 120a6e
      painter.fillRect(x0, y1, width, y3 - y1,
Shinya Kitaoka 120a6e
                       getViewer()->getCurrentRowBgColor());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // draw horizonntal lines
Shinya Kitaoka 120a6e
    painter.setPen(QPen(getViewer()->getColumnHeaderBorderColor(), 3));
Shinya Kitaoka 120a6e
    painter.drawLine(x0, y0, x1, y0);
Shinya Kitaoka 120a6e
    painter.setPen(getViewer()->getColumnHeaderBorderColor());
Shinya Kitaoka 120a6e
    painter.drawLine(x0, y1, x1, y1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // draw vertical bar
Shinya Kitaoka 120a6e
    painter.fillRect(x0, y1, 6, y3 - y1,
Shinya Kitaoka 120a6e
                     getViewer()->getColumnHeaderBorderColor());
Shinya Kitaoka 120a6e
    if (firstGroupColumn)
Shinya Kitaoka 120a6e
      painter.fillRect(x0, y0, 6, y1 - y0,
Shinya Kitaoka 120a6e
                       getViewer()->getColumnHeaderBorderColor());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // channel name
Shinya Kitaoka 120a6e
    painter.setPen(getViewer()->getTextColor());
Shinya Kitaoka 120a6e
    if (channel->isCurrent())
shun-iwasawa 2ce475
      painter.setPen(m_sheet->getViewer()->getCurrentTextColor());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    QString text = channel->getShortName();
Shinya Kitaoka 120a6e
    int d        = 8;
Shinya Kitaoka 120a6e
    painter.drawText(x0 + d, y1, width - d, y3 - y1 + 1,
Shinya Kitaoka 120a6e
                     Qt::TextWrapAnywhere | Qt::AlignLeft | Qt::AlignVCenter,
Shinya Kitaoka 120a6e
                     text);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // group name
Shinya Kitaoka 120a6e
    if (firstGroupColumn) {
Shinya Kitaoka 120a6e
      int tmpwidth = (lastGroupColumn) ? width : width * 2;
Shinya Kitaoka 120a6e
      painter.setPen(getViewer()->getTextColor());
Shinya Kitaoka 120a6e
      if (group == currentGroup)
shun-iwasawa 2ce475
        painter.setPen(m_sheet->getViewer()->getCurrentTextColor());
Shinya Kitaoka 120a6e
      text = group->getShortName();
Shinya Kitaoka 120a6e
      painter.drawText(x0 + d, y0, tmpwidth - d, y1 - y0 + 1,
Shinya Kitaoka 120a6e
                       Qt::AlignLeft | Qt::AlignVCenter, text);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! update tooltips
shun-iwasawa 260cd7
 */
Shinya Kitaoka 120a6e
void FunctionSheetColumnHeadViewer::mouseMoveEvent(QMouseEvent *e) {
Shinya Kitaoka 120a6e
  if ((e->buttons() & Qt::MidButton) && m_draggingChannel &&
Shinya Kitaoka 120a6e
      (e->pos() - m_dragStartPosition).manhattanLength() >=
Shinya Kitaoka 120a6e
          QApplication::startDragDistance()) {
Shinya Kitaoka 120a6e
    QDrag *drag         = new QDrag(this);
Shinya Kitaoka 120a6e
    QMimeData *mimeData = new QMimeData;
Shinya Kitaoka 120a6e
    mimeData->setText(m_draggingChannel->getExprRefName());
Shinya Kitaoka 120a6e
    drag->setMimeData(mimeData);
Shinya Kitaoka 120a6e
    static const QPixmap cursorPixmap(":Resources/dragcursor_exp_text.png");
Shinya Kitaoka 120a6e
    drag->setDragCursor(cursorPixmap, Qt::MoveAction);
Shinya Kitaoka 120a6e
    Qt::DropAction dropAction = drag->exec();
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  // get the column under the cursor
Jaroslav 203cc8
  int col = getViewer()->xyToPosition(e->pos()).layer();
Shinya Kitaoka 120a6e
  FunctionTreeModel::Channel *channel = m_sheet->getChannel(col);
Shinya Kitaoka 120a6e
  if (!channel) {
Shinya Kitaoka 120a6e
    setToolTip(QString(""));
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    setToolTip(channel->getExprRefName());
shun-iwasawa 875c7e
shun-iwasawa 875c7e
  // modify selected channel by left dragging
shun-iwasawa 875c7e
  if (m_clickedColumn >= 0 && channel && e->buttons() & Qt::LeftButton) {
shun-iwasawa 875c7e
    int fromC      = std::min(m_clickedColumn, col);
shun-iwasawa 875c7e
    int toC        = std::max(m_clickedColumn, col);
shun-iwasawa 875c7e
    int lastKeyPos = 0;
shun-iwasawa 875c7e
    for (int c = fromC; c <= toC; c++) {
shun-iwasawa 875c7e
      FunctionTreeModel::Channel *tmpChan = m_sheet->getChannel(c);
shun-iwasawa 875c7e
      if (!tmpChan) continue;
shun-iwasawa 875c7e
      std::set<double> frames;</double>
shun-iwasawa 875c7e
      tmpChan->getParam()->getKeyframes(frames);
shun-iwasawa 875c7e
      if (!frames.empty())
shun-iwasawa 875c7e
        lastKeyPos = std::max(lastKeyPos, (int)*frames.rbegin());
shun-iwasawa 875c7e
    }
shun-iwasawa 875c7e
    QRect rect(std::min(m_clickedColumn, col), 0,
shun-iwasawa 875c7e
               std::abs(col - m_clickedColumn) + 1, lastKeyPos + 1);
shun-iwasawa 875c7e
    getViewer()->selectCells(rect);
shun-iwasawa 875c7e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionSheetColumnHeadViewer::mousePressEvent(QMouseEvent *e) {
shun-iwasawa 875c7e
  QPoint pos                          = e->pos();
shun-iwasawa 875c7e
  int currentC                        = getViewer()->xyToPosition(pos).layer();
shun-iwasawa 875c7e
  FunctionTreeModel::Channel *channel = m_sheet->getChannel(currentC);
shun-iwasawa 875c7e
  if (!channel) {
shun-iwasawa 875c7e
    m_clickedColumn = -1;
shun-iwasawa 875c7e
    return;
Shinya Kitaoka 120a6e
  }
shun-iwasawa 875c7e
shun-iwasawa 875c7e
  if (e->button() == Qt::MidButton) {
Shinya Kitaoka 120a6e
    m_draggingChannel   = channel;
Shinya Kitaoka 120a6e
    m_dragStartPosition = e->pos();
Shinya Kitaoka 120a6e
    return;
shun-iwasawa 875c7e
  } else
Shinya Kitaoka 120a6e
    channel->setIsCurrent(true);
Shinya Kitaoka 120a6e
  m_draggingChannel = 0;
Shinya Kitaoka 120a6e
shun-iwasawa 875c7e
  if (e->button() == Qt::LeftButton) {
shun-iwasawa 875c7e
    int lastKeyPos = 0;
shun-iwasawa 875c7e
    // if the current selection does not contain the first cell in m_firstColumn
shun-iwasawa 875c7e
    // then we assume that the selection has been modified and treat shift+click
shun-iwasawa 875c7e
    // as normal click.
shun-iwasawa 875c7e
    if (getViewer()->getSelectedCells().contains(m_clickedColumn, 0) &&
shun-iwasawa 875c7e
        (e->modifiers() & Qt::ShiftModifier)) {
shun-iwasawa 875c7e
      int fromC = std::min(m_clickedColumn, currentC);
shun-iwasawa 875c7e
      int toC   = std::max(m_clickedColumn, currentC);
shun-iwasawa 875c7e
      for (int c = fromC; c <= toC; c++) {
shun-iwasawa 875c7e
        FunctionTreeModel::Channel *tmpChan = m_sheet->getChannel(c);
shun-iwasawa 875c7e
        if (!tmpChan) continue;
shun-iwasawa 875c7e
        std::set<double> frames;</double>
shun-iwasawa 875c7e
        tmpChan->getParam()->getKeyframes(frames);
shun-iwasawa 875c7e
        if (!frames.empty())
shun-iwasawa 875c7e
          lastKeyPos = std::max(lastKeyPos, (int)*frames.rbegin());
shun-iwasawa 875c7e
      }
shun-iwasawa 875c7e
    } else {
shun-iwasawa 875c7e
      // Open folder
shun-iwasawa 875c7e
      FunctionTreeModel::ChannelGroup *channelGroup =
shun-iwasawa 875c7e
          channel->getChannelGroup();
shun-iwasawa 875c7e
      if (!channelGroup->isOpen())
shun-iwasawa 875c7e
        channelGroup->getModel()->setExpandedItem(channelGroup->createIndex(),
shun-iwasawa 875c7e
                                                  true);
shun-iwasawa 875c7e
      // Select all segment
shun-iwasawa 875c7e
      std::set<double> frames;</double>
shun-iwasawa 875c7e
      channel->getParam()->getKeyframes(frames);
shun-iwasawa 875c7e
      if (!frames.empty()) lastKeyPos = (int)*frames.rbegin();
shun-iwasawa 875c7e
      m_clickedColumn = currentC;
shun-iwasawa 875c7e
    }
shun-iwasawa 875c7e
    QRect rect(std::min(m_clickedColumn, currentC), 0,
shun-iwasawa 875c7e
               std::abs(currentC - m_clickedColumn) + 1, lastKeyPos + 1);
Shinya Kitaoka 120a6e
shun-iwasawa 875c7e
    getViewer()->selectCells(rect);
shun-iwasawa 875c7e
  }
shun-iwasawa bd3eea
  // Switch selection before opening the context menu
shun-iwasawa bd3eea
  // if the clicked column is out of the selection
shun-iwasawa bd3eea
  else if (e->button() == Qt::RightButton) {
shun-iwasawa bd3eea
    QRect selectedCell = getViewer()->getSelectedCells();
shun-iwasawa bd3eea
    if (selectedCell.left() > currentC || selectedCell.right() < currentC) {
shun-iwasawa bd3eea
      int lastKeyPos = 0;
shun-iwasawa bd3eea
      std::set<double> frames;</double>
shun-iwasawa bd3eea
      channel->getParam()->getKeyframes(frames);
shun-iwasawa bd3eea
      if (!frames.empty()) lastKeyPos = (int)*frames.rbegin();
shun-iwasawa bd3eea
      getViewer()->selectCells(QRect(currentC, 0, 1, lastKeyPos + 1));
shun-iwasawa bd3eea
    }
shun-iwasawa bd3eea
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionSheetColumnHeadViewer::contextMenuEvent(QContextMenuEvent *ce) {
Shinya Kitaoka 120a6e
  // First, select column under cursor
Shinya Kitaoka 120a6e
  const QPoint &pos = ce->pos();
Jaroslav 203cc8
  int cursorCol     = getViewer()->xyToPosition(pos).layer();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (cursorCol < 0 || cursorCol >= m_sheet->getChannelCount()) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  FunctionTreeModel::Channel *channel = m_sheet->getChannel(cursorCol);
Shinya Kitaoka 120a6e
  if (!channel) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Ok, now let's summon a context menu with appropriate options
Shinya Kitaoka 120a6e
  FunctionViewer *fv = m_sheet->getViewer();
Shinya Kitaoka 120a6e
  if (!fv) {
Shinya Kitaoka 120a6e
    assert(fv);
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const QPoint &globalPos = mapToGlobal(pos);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (pos.y() >= cChannelNameY)
Shinya Kitaoka 120a6e
    fv->openContextMenu(channel, globalPos);
Shinya Kitaoka 120a6e
  else {
Shinya Kitaoka 120a6e
    FunctionTreeModel::ChannelGroup *group = channel->getChannelGroup();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // In this case, commands are different from the tree view. Rather than
Shinya Kitaoka 120a6e
    // showing in the tree,
Shinya Kitaoka 120a6e
    // channels get ACTIVATED
Shinya Kitaoka 120a6e
    QMenu menu;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    QAction showAnimatedOnly(FunctionTreeView::tr("Show Animated Only"), 0);
Shinya Kitaoka 120a6e
    QAction showAll(FunctionTreeView::tr("Show All"), 0);
shun-iwasawa bd3eea
    QAction hideSelected(FunctionTreeView::tr("Hide Selected"), 0);
Shinya Kitaoka 120a6e
    menu.addAction(&showAnimatedOnly);
Shinya Kitaoka 120a6e
    menu.addAction(&showAll);
shun-iwasawa bd3eea
    menu.addAction(&hideSelected);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // execute menu
Shinya Kitaoka 120a6e
    QAction *action = menu.exec(globalPos);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Process action
Shinya Kitaoka 120a6e
    if (action == &showAll) {
Shinya Kitaoka 120a6e
      int c, cCount = group->getChildCount();
Shinya Kitaoka 120a6e
      for (c = 0; c != cCount; ++c) {
Shinya Kitaoka 120a6e
        FunctionTreeModel::Channel *channel =
Shinya Kitaoka 120a6e
            dynamic_cast<functiontreemodel::channel *="">(group->getChild(c));</functiontreemodel::channel>
Shinya Kitaoka 120a6e
        if (channel && !channel->isHidden()) channel->setIsActive(true);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } else if (action == &showAnimatedOnly) {
Shinya Kitaoka 120a6e
      int c, cCount = group->getChildCount();
Shinya Kitaoka 120a6e
      for (c = 0; c != cCount; ++c) {
Shinya Kitaoka 120a6e
        FunctionTreeModel::Channel *channel =
Shinya Kitaoka 120a6e
            dynamic_cast<functiontreemodel::channel *="">(group->getChild(c));</functiontreemodel::channel>
Shinya Kitaoka 120a6e
        if (channel && !channel->isHidden())
Shinya Kitaoka 120a6e
          channel->setIsActive(channel->isAnimated());
Shinya Kitaoka 120a6e
      }
shun-iwasawa bd3eea
    } else if (action == &hideSelected) {
shun-iwasawa bd3eea
      QRect selectedCells = getViewer()->getSelectedCells();
shun-iwasawa bd3eea
      // hide the selected columns from the right to the left
shun-iwasawa bd3eea
      for (int col = selectedCells.right(); col >= selectedCells.left();
shun-iwasawa bd3eea
           col--) {
shun-iwasawa bd3eea
        FunctionTreeModel::Channel *chan = m_sheet->getChannel(col);
shun-iwasawa bd3eea
        if (chan) chan->setIsActive(false);
shun-iwasawa bd3eea
      }
shun-iwasawa bd3eea
      // clear cell selection
shun-iwasawa bd3eea
      getViewer()->selectCells(QRect());
shun-iwasawa bd3eea
    } else
shun-iwasawa bd3eea
      return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    fv->update();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
//    FunctionSheetCellViewer  implementation
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
FunctionSheetCellViewer::FunctionSheetCellViewer(FunctionSheet *parent)
Shinya Kitaoka 120a6e
    : Spreadsheet::CellPanel(parent)
Shinya Kitaoka 120a6e
    , m_sheet(parent)
Shinya Kitaoka 120a6e
    , m_editRow(0)
Shinya Kitaoka 120a6e
    , m_editCol(0) {
Shinya Kitaoka 120a6e
  m_lineEdit = new DVGui::LineEdit(this);
Shinya Kitaoka 120a6e
  // lineEdit->setGeometry(10,10,100,30);
Shinya Kitaoka 120a6e
  m_lineEdit->hide();
Shinya Kitaoka 120a6e
  bool ret = connect(m_lineEdit, SIGNAL(editingFinished()), this,
Shinya Kitaoka 120a6e
                     SLOT(onCellEditorEditingFinished()));
shun-iwasawa 260cd7
  ret      = ret && connect(m_lineEdit, SIGNAL(mouseMoved(QMouseEvent *)), this,
Jeremy Bullock 771290
                       SLOT(onMouseMovedInLineEdit(QMouseEvent *)));
Shinya Kitaoka 120a6e
  assert(ret);
Shinya Kitaoka 120a6e
  setMouseTracking(true);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  setFocusProxy(m_lineEdit);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Called when the cell panel is left/right-clicked
shun-iwasawa 260cd7
 */
Shinya Kitaoka 120a6e
Spreadsheet::DragTool *FunctionSheetCellViewer::createDragTool(QMouseEvent *e) {
Jaroslav 203cc8
  CellPosition cellPosition = getViewer()->xyToPosition(e->pos());
Jaroslav 203cc8
  int row                   = cellPosition.frame();
Jaroslav 203cc8
  int col                   = cellPosition.layer();
Jaroslav 203cc8
  bool isEmpty              = true;
Jaroslav 203cc8
  TDoubleParam *curve       = m_sheet->getCurve(col);
Shinya Kitaoka 120a6e
  if (curve) {
Shinya Kitaoka 120a6e
    int kCount = curve->getKeyframeCount();
Shinya Kitaoka 120a6e
    if (kCount > 0) {
Shinya Kitaoka 120a6e
      int row0 = (int)curve->keyframeIndexToFrame(0);
Shinya Kitaoka 120a6e
      int row1 = (int)curve->keyframeIndexToFrame(kCount - 1);
Shinya Kitaoka 120a6e
      isEmpty  = row < row0 || row > row1;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!isEmpty) {
Shinya Kitaoka 120a6e
    int x = e->pos().x() - getViewer()->columnToX(col);
Shinya Kitaoka 120a6e
    if (0 <= x && x < cColumnDragHandleWidth + 9)
Shinya Kitaoka 120a6e
      return new MoveChannelsDragTool(m_sheet);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return new FunctionSheetSelectionTool(m_sheet);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // return Spreadsheet::CellPanel::createDragTool(e);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionSheetCellViewer::drawCells(QPainter &painter, int r0, int c0,
Shinya Kitaoka 120a6e
                                        int r1, int c1) {
Shinya Kitaoka 120a6e
  // key frames
Shinya Kitaoka 120a6e
  QColor KeyFrameColor         = getViewer()->getKeyFrameColor();
Shinya Kitaoka 120a6e
  QColor KeyFrameBorderColor   = getViewer()->getKeyFrameBorderColor();
Shinya Kitaoka 120a6e
  QColor SelectedKeyFrameColor = getViewer()->getSelectedKeyFrameColor();
Shinya Kitaoka 120a6e
  // inbetween
Shinya Kitaoka 120a6e
  QColor InBetweenColor         = getViewer()->getInBetweenColor();
Shinya Kitaoka 120a6e
  QColor InBetweenBorderColor   = getViewer()->getInBetweenBorderColor();
Shinya Kitaoka 120a6e
  QColor SelectedInBetweenColor = getViewer()->getSelectedInBetweenColor();
Shinya Kitaoka 120a6e
  // empty cells
Shinya Kitaoka 120a6e
  QColor SelectedEmptyColor = getViewer()->getSelectedEmptyColor();
Shinya Kitaoka 120a6e
  // empty cells in scene frame range
Shinya Kitaoka 120a6e
  QColor SelectedSceneRangeEmptyColor =
Shinya Kitaoka 120a6e
      getViewer()->getSelectedSceneRangeEmptyColor();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // top and bottom pos
Shinya Kitaoka 120a6e
  int y0 = getViewer()->rowToY(r0);
Shinya Kitaoka 120a6e
  int y1 = getViewer()->rowToY(r1 + 1) - 1;
Shinya Kitaoka 120a6e
  for (int c = c0; c <= c1; c++) {
Shinya Kitaoka 120a6e
    TDoubleParam *curve = m_sheet->getCurve(c);
Shinya Kitaoka 120a6e
    /*--- もしカラムcにパラメータが無ければcurveには0が返る ---*/
Shinya Kitaoka 120a6e
    if (!curve) continue;
Shinya Kitaoka 120a6e
    // left and right pos
Shinya Kitaoka 120a6e
    int x0 = getViewer()->columnToX(c);
Shinya Kitaoka 120a6e
    int x1 = getViewer()->columnToX(c + 1) - 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // find the curve keyframe range
Shinya Kitaoka 120a6e
    int kr0 = 0, kr1 = -1;
Shinya Kitaoka 120a6e
    int kCount = curve->getKeyframeCount();
Shinya Kitaoka 120a6e
    if (kCount > 0) {
Shinya Kitaoka 120a6e
      kr0 = curve->keyframeIndexToFrame(0);
Shinya Kitaoka 120a6e
      kr1 = curve->keyframeIndexToFrame(kCount - 1);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // get the unit
Shinya Kitaoka 120a6e
    TMeasure *measure = curve->getMeasure();
Shinya Kitaoka 120a6e
    const TUnit *unit = measure ? measure->getCurrentUnit() : 0;
Shinya Kitaoka 120a6e
shun_iwasawa 768e20
    bool isStageObjectCycled = false;
shun_iwasawa 768e20
    TStageObject *obj        = m_sheet->getStageObject(c);
shun_iwasawa 768e20
    if (obj && obj->isCycleEnabled()) isStageObjectCycled = true;
shun_iwasawa 768e20
shun_iwasawa 768e20
    bool isParamCycled = curve->isCycleEnabled();
shun_iwasawa 768e20
    int rowCount       = getViewer()->getRowCount();
shun_iwasawa 768e20
Shinya Kitaoka 120a6e
    // draw each cell
Shinya Kitaoka 120a6e
    for (int row = r0; row <= r1; row++) {
Shinya Kitaoka 120a6e
      int ya = m_sheet->rowToY(row);
Shinya Kitaoka 120a6e
      int yb = m_sheet->rowToY(row + 1) - 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      bool isSelected = getViewer()->isSelectedCell(row, c);
Shinya Kitaoka 120a6e
shun_iwasawa 768e20
      double value = (isStageObjectCycled)
shun_iwasawa 768e20
                         ? curve->getValue(obj->paramsTime((double)row))
shun_iwasawa 768e20
                         : curve->getValue(row);
Shinya Kitaoka 120a6e
      if (unit) value = unit->convertTo(value);
shun-iwasawa 260cd7
      enum { None, Key, Inbetween, CycleRange } drawValue = None;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      QRect cellRect(x0, ya, x1 - x0 + 1, yb - ya + 1);
Shinya Kitaoka 120a6e
      QRect borderRect(x0, ya, 7, yb - ya + 1);
Shinya Kitaoka 120a6e
      QColor cellColor, borderColor;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      /*--- キーフレーム間の範囲だけ色をつける ---*/
Shinya Kitaoka 120a6e
      if (kr0 <= row && row <= kr1) {
Shinya Kitaoka 120a6e
        if (curve->isKeyframe(row)) {
Shinya Kitaoka 120a6e
          cellColor   = (isSelected) ? SelectedKeyFrameColor : KeyFrameColor;
Shinya Kitaoka 120a6e
          borderColor = KeyFrameBorderColor;
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          cellColor   = (isSelected) ? SelectedInBetweenColor : InBetweenColor;
Shinya Kitaoka 120a6e
          borderColor = InBetweenBorderColor;
shun-iwasawa 260cd7
shun-iwasawa 260cd7
          // when the inbetween values are hidden, change the cell colors to
shun-iwasawa 260cd7
          // semi-transparent if the frame is in middle of the value step
shun-iwasawa 260cd7
          if (!m_sheet->isIbtwnValueVisible()) {
shun-iwasawa 260cd7
            TDoubleKeyframe kf =
shun-iwasawa 260cd7
                curve->getKeyframe(curve->getPrevKeyframe(row));
shun-iwasawa 260cd7
            int step = kf.m_step;
shun-iwasawa 260cd7
            if (step > 1 && (row - (int)std::floor(kf.m_frame)) % step != 0)
shun-iwasawa 260cd7
              cellColor.setAlpha(128);
shun-iwasawa 260cd7
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
        painter.setPen(Qt::NoPen);
Shinya Kitaoka 120a6e
        painter.fillRect(cellRect, cellColor);
Shinya Kitaoka 120a6e
        painter.fillRect(borderRect, borderColor);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        // display whether segment are Linked
Shinya Kitaoka 120a6e
        if (curve->isKeyframe(row)) {
Shinya Kitaoka 120a6e
          TDoubleKeyframe kf = curve->getKeyframeAt(row);
Shinya Kitaoka 120a6e
          // if the segments are NOT linked, then cut off the side bar
Shinya Kitaoka 120a6e
          if (!kf.m_linkedHandles) {
Shinya Kitaoka 120a6e
            int rowCenterPos = (ya + yb) / 2;
Shinya Kitaoka 120a6e
            QPoint points[4] = {
Shinya Kitaoka 120a6e
                QPoint(x0, rowCenterPos), QPoint(x0 + 7, rowCenterPos + 3),
Shinya Kitaoka 120a6e
                QPoint(x0 + 7, rowCenterPos - 3), QPoint(x0, rowCenterPos)};
Shinya Kitaoka 120a6e
            QBrush oldBrush = painter.brush();
Shinya Kitaoka 120a6e
            painter.setBrush(QBrush(cellColor));
Shinya Kitaoka 120a6e
            painter.drawPolygon(points, 4);
Shinya Kitaoka 120a6e
            painter.setBrush(oldBrush);
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
shun-iwasawa 260cd7
        drawValue = (curve->isKeyframe(row))
shun-iwasawa 260cd7
                        ? Key
shun-iwasawa 260cd7
                        : (m_sheet->isIbtwnValueVisible()) ? Inbetween : None;
shun_iwasawa 768e20
shun_iwasawa 768e20
      }
shun_iwasawa 768e20
      // empty cells
shun_iwasawa 768e20
      else {
shun_iwasawa 768e20
        // show values for cycled parameter.
shun_iwasawa 768e20
        // cycle option can be set in two ways; one is as TStageObject,
shun_iwasawa 768e20
        // the other is as TDoubleParam.
shun_iwasawa 768e20
        // - TStageObject cycle literally cycles values with no offset.
shun_iwasawa 768e20
        //   Applied to all transformation parameters of the cycled object.
shun_iwasawa 768e20
        // - TDoubleParam cycle includes value offset so that the curve
shun_iwasawa 768e20
        //   connects smoothly.
shun_iwasawa 768e20
        // - TStageObject cycle option has a priority to TDoubleParam one.
shun_iwasawa 768e20
        // (see TStageObject::paramsTime() in tstageobject.cpp)
shun_iwasawa 768e20
        if (kCount > 0 && row > kr1 && (isStageObjectCycled || isParamCycled) &&
shun_iwasawa 768e20
            (row < rowCount)) {
shun_iwasawa 768e20
          drawValue = CycleRange;
shun_iwasawa 768e20
        }
shun_iwasawa 768e20
        // empty and selected cell
shun_iwasawa 768e20
        if (isSelected) {
shun_iwasawa 768e20
          cellColor = (row >= rowCount) ? SelectedEmptyColor
shun_iwasawa 768e20
                                        : SelectedSceneRangeEmptyColor;
shun_iwasawa 768e20
          painter.setPen(Qt::NoPen);
shun_iwasawa 768e20
          painter.fillRect(cellRect, cellColor);
shun_iwasawa 768e20
        }
shun_iwasawa 768e20
      }
shun_iwasawa 768e20
shun_iwasawa 768e20
      if (drawValue != None) {
Shinya Kitaoka 120a6e
        // draw cell value
shun-iwasawa 260cd7
        if (drawValue == Key || drawValue == Inbetween)
shun_iwasawa 768e20
          painter.setPen(getViewer()->getTextColor());
shun_iwasawa 768e20
        else {
shun_iwasawa 768e20
          QColor semiTranspTextColor = getViewer()->getTextColor();
shun_iwasawa 768e20
          semiTranspTextColor.setAlpha(128);
shun_iwasawa 768e20
          painter.setPen(semiTranspTextColor);
shun_iwasawa 768e20
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        /*--- 整数から小数点以下3桁以内の場合はそれ以降の0000を描かない ---*/
Shinya Kitaoka 120a6e
        QString text;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        double thousandValue = value * 1000.0;
Shinya Kitaoka 120a6e
        if (areAlmostEqual(thousandValue, (double)tround(thousandValue),
Shinya Kitaoka 120a6e
                           0.0001)) {
Shinya Kitaoka 120a6e
          text = QString::number(value, 'f', 3);
Shinya Kitaoka 120a6e
          while (text.endsWith("0")) {
Shinya Kitaoka 120a6e
            text.chop(1);
Shinya Kitaoka 120a6e
            if (text.endsWith(".")) {
Shinya Kitaoka 120a6e
              text.chop(1);
Shinya Kitaoka 120a6e
              break;
Shinya Kitaoka 120a6e
            }
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          text = QString::number(value, 'f', 4);
Shinya Kitaoka 120a6e
          text.truncate(5);
Shinya Kitaoka 120a6e
          text.append("~");
Shinya Kitaoka 120a6e
        }
Toshihiro Shimizu 890ddd
Jeremy Bullock 807052
        QString fontName = Preferences::instance()->getInterfaceFont();
Jeremy Bullock 807052
        if (fontName == "") {
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Jeremy Bullock 807052
          fontName = "Arial";
Toshihiro Shimizu 890ddd
#else
Jeremy Bullock 807052
          fontName = "Helvetica";
Toshihiro Shimizu 890ddd
#endif
Jeremy Bullock 807052
        }
shun_iwasawa 768e20
        static QFont font(fontName, -1);
shun-iwasawa 260cd7
        font.setBold(drawValue == Key);
shun_iwasawa 01e417
        font.setPixelSize(12);
Shinya Kitaoka 120a6e
        painter.setFont(font);
Shinya Kitaoka 120a6e
        painter.drawText(cellRect.adjusted(10, 0, 0, 0),
shun-iwasawa c128ae
                         Qt::AlignVCenter | Qt::AlignLeft, text);
Shinya Kitaoka 120a6e
      }
shun_iwasawa 768e20
    }
shun_iwasawa 768e20
shun_iwasawa 768e20
    if (kCount > 0 && (isStageObjectCycled || isParamCycled)) {
shun_iwasawa 768e20
      // draw the row zigzag
shun_iwasawa 768e20
      int ymax           = m_sheet->rowToY(r1 + 1);
shun_iwasawa 768e20
      int qx             = x0 + 4;
shun_iwasawa 768e20
      int qy             = m_sheet->rowToY(kr1 + 1);
shun_iwasawa 768e20
      int zig            = 2;
shun_iwasawa 768e20
      QColor zigzagColor = (isStageObjectCycled) ? getViewer()->getTextColor()
shun_iwasawa 768e20
                                                 : KeyFrameBorderColor;
shun_iwasawa 768e20
      painter.setPen(zigzagColor);
shun_iwasawa 768e20
      painter.drawLine(QPoint(qx, qy), QPoint(qx - zig, qy + zig));
shun_iwasawa 768e20
      qy += zig;
shun_iwasawa 768e20
      while (qy < ymax) {
shun_iwasawa 768e20
        painter.drawLine(QPoint(qx - zig, qy), QPoint(qx + zig, qy + 2 * zig));
shun_iwasawa 768e20
        painter.drawLine(QPoint(qx + zig, qy + 2 * zig),
shun_iwasawa 768e20
                         QPoint(qx - zig, qy + 4 * zig));
shun_iwasawa 768e20
        qy += 4 * zig;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionSheetCellViewer::mouseDoubleClickEvent(QMouseEvent *e) {
Jaroslav 203cc8
  CellPosition cellPosition = getViewer()->xyToPosition(e->pos());
Jaroslav 203cc8
  int row                   = cellPosition.frame();
Jaroslav 203cc8
  int col                   = cellPosition.layer();
Shinya Kitaoka 120a6e
  int x0, y0, x1, y1;
Shinya Kitaoka 120a6e
  x0 = getViewer()->columnToX(col);
Shinya Kitaoka 120a6e
  x1 = getViewer()->columnToX(col + 1) - 1;
Shinya Kitaoka 120a6e
  y0 = getViewer()->rowToY(row);
Shinya Kitaoka 120a6e
  y1 = getViewer()->rowToY(row + 1) - 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_editRow = row;
Shinya Kitaoka 120a6e
  m_editCol = col;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TDoubleParam *curve = m_sheet->getCurve(col);
Shinya Kitaoka 120a6e
  if (curve) {
Shinya Kitaoka 120a6e
    double v          = curve->getValue(row);
Shinya Kitaoka 120a6e
    TMeasure *measure = curve->getMeasure();
Shinya Kitaoka 120a6e
    const TUnit *unit = measure ? measure->getCurrentUnit() : 0;
shun-iwasawa 260cd7
    if (unit) v = unit->convertTo(v);
shun-iwasawa 260cd7
    m_currentValue = v;
Shinya Kitaoka 120a6e
    m_lineEdit->setText(QString::number(v, 'f', 4));
Shinya Kitaoka 120a6e
    // in order to put the cursor to the left end
Shinya Kitaoka 120a6e
    m_lineEdit->setSelection(m_lineEdit->text().length(),
Shinya Kitaoka 120a6e
                             -m_lineEdit->text().length());
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    m_lineEdit->setText("");
Toshihiro Shimizu 890ddd
Jeremy Bullock 807052
  QString fontName = Preferences::instance()->getInterfaceFont();
Jeremy Bullock 807052
  if (fontName == "") {
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Jeremy Bullock 807052
    fontName = "Arial";
Toshihiro Shimizu 890ddd
#else
Jeremy Bullock 807052
    fontName = "Helvetica";
Toshihiro Shimizu 890ddd
#endif
Jeremy Bullock 807052
  }
Jeremy Bullock 807052
  static QFont font(fontName, 9, QFont::Normal);
Shinya Kitaoka 120a6e
  m_lineEdit->setFont(font);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_lineEdit->setGeometry(x0 - 2, y0 - 2, x1 - x0 + 1 + 4,
Shinya Kitaoka 120a6e
                          y1 - y0 + 1 + 4);  // x0,y0,x1-x0+1,y0-y1+1);
Shinya Kitaoka 120a6e
  m_lineEdit->show();
Shinya Kitaoka 120a6e
  m_lineEdit->raise();
Shinya Kitaoka 120a6e
  m_lineEdit->setFocus();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionSheetCellViewer::onCellEditorEditingFinished() {
Shinya Kitaoka 120a6e
  QString text = m_lineEdit->text();
Jeremy Bullock 771290
  if (!text.isEmpty() &&
Jeremy Bullock 771290
      (m_lineEdit->isReturnPressed() || m_lineEdit->getMouseDragEditing())) {
Shinya Kitaoka 120a6e
    double value        = text.toDouble();
Shinya Kitaoka 120a6e
    TDoubleParam *curve = m_sheet->getCurve(m_editCol);
Shinya Kitaoka 120a6e
    if (curve) {
Shinya Kitaoka 120a6e
      TMeasure *measure = curve->getMeasure();
Shinya Kitaoka 120a6e
      const TUnit *unit = measure ? measure->getCurrentUnit() : 0;
shun-iwasawa 260cd7
      if (unit) value = unit->convertFrom(value);
Shinya Kitaoka 120a6e
      KeyframeSetter::setValue(curve, m_editRow, value);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_lineEdit->hide();
Shinya Kitaoka 120a6e
  m_lineEdit->clearFocus();
Shinya Kitaoka 120a6e
  m_sheet->setFocus();
Shinya Kitaoka 120a6e
  update();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionSheetCellViewer::mousePressEvent(QMouseEvent *e) {
Shinya Kitaoka 120a6e
  // escape from the line edit by clicking outside
Shinya Kitaoka 120a6e
  if (m_lineEdit->isVisible()) {
Shinya Kitaoka 120a6e
    m_lineEdit->hide();
Shinya Kitaoka 120a6e
    m_lineEdit->clearFocus();
Shinya Kitaoka 120a6e
    m_sheet->setFocus();
Shinya Kitaoka 120a6e
  }
Jeremy Bullock 771290
  if (e->button() == Qt::LeftButton && e->modifiers() == Qt::ControlModifier) {
Jeremy Bullock 771290
    mouseDoubleClickEvent(e);
Jeremy Bullock 771290
    if (m_lineEdit->text() != "") {
Jeremy Bullock 771290
      m_lineEdit->setMouseDragEditing(true);
Jeremy Bullock 771290
      m_mouseXPosition = e->x();
Jeremy Bullock 771290
    }
Jeremy Bullock 771290
  } else if (e->button() == Qt::LeftButton &&
Jeremy Bullock 771290
             e->modifiers() == Qt::AltModifier) {
Jeremy Bullock 771290
    CellPosition cellPosition = getViewer()->xyToPosition(e->pos());
Jeremy Bullock 771290
    int row                   = cellPosition.frame();
Jeremy Bullock 771290
    int col                   = cellPosition.layer();
Jeremy Bullock 771290
    TDoubleParam *curve       = m_sheet->getCurve(col);
Jeremy Bullock 771290
    if (curve) {
Jeremy Bullock 771290
      KeyframeSetter::removeKeyframeAt(curve, row);
Jeremy Bullock 771290
    }
Jeremy Bullock 771290
  } else if (e->button() == Qt::LeftButton || e->button() == Qt::MidButton)
Shinya Kitaoka 120a6e
    Spreadsheet::CellPanel::mousePressEvent(e);
Shinya Kitaoka 120a6e
  else if (e->button() == Qt::RightButton) {
Shinya Kitaoka 120a6e
    update();
Shinya Kitaoka 120a6e
    openContextMenu(e);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionSheetCellViewer::mouseReleaseEvent(QMouseEvent *e) {
Jeremy Bullock 771290
  if (m_lineEdit->getMouseDragEditing()) {
Jeremy Bullock 771290
    std::string textValue = m_lineEdit->text().toStdString();
Jeremy Bullock 771290
    onCellEditorEditingFinished();
Jeremy Bullock 771290
    m_lineEdit->setMouseDragEditing(false);
Jeremy Bullock 771290
  } else
Jeremy Bullock 771290
    Spreadsheet::CellPanel::mouseReleaseEvent(e);
Shinya Kitaoka 120a6e
  /*
Jaroslav 203cc8
  CellPosition cellPosition = getViewer ()->xyToPosition (e->pos ());
Jaroslav 203cc8
int row = cellPosition.frame ();
Jaroslav 203cc8
int col = cellPosition.layer ();
Shinya Kitaoka 120a6e
FunctionSheet::DragTool *dragTool = m_sheet->getDragTool();
Shinya Kitaoka 120a6e
if(dragTool) dragTool->release(row,col);
Shinya Kitaoka 120a6e
m_sheet->setDragTool(0);
Shinya Kitaoka 120a6e
*/
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionSheetCellViewer::mouseMoveEvent(QMouseEvent *e) {
Jeremy Bullock 771290
  if (m_lineEdit->getMouseDragEditing()) {
Jeremy Bullock 771290
    double newValue = m_currentValue + ((e->x() - m_mouseXPosition) / 2);
Jeremy Bullock 771290
    m_lineEdit->setText(QString::number(newValue, 'f', 4));
Jeremy Bullock 771290
    m_updatedValue = newValue;
Jeremy Bullock 771290
  } else
Jeremy Bullock 771290
    Spreadsheet::CellPanel::mouseMoveEvent(e);
Jeremy Bullock 771290
}
Jeremy Bullock 771290
Jeremy Bullock 771290
//-----------------------------------------------------------------------------
Jeremy Bullock 771290
Jeremy Bullock 771290
void FunctionSheetCellViewer::onMouseMovedInLineEdit(QMouseEvent *event) {
Jeremy Bullock 771290
  if (m_lineEdit->getMouseDragEditing()) mouseMoveEvent(event);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TODO: refactor: cfr functionpanel.cpp
Shinya Kitaoka 120a6e
void FunctionSheetCellViewer::openContextMenu(QMouseEvent *e) {
Shinya Kitaoka 120a6e
  QAction deleteKeyframeAction(tr("Delete Key"), 0);
Shinya Kitaoka 120a6e
  QAction insertKeyframeAction(tr("Set Key"), 0);
shun-iwasawa 298c96
shun-iwasawa 298c96
  QStringList interpNames;
shun-iwasawa 298c96
  interpNames << tr("Constant Interpolation") << tr("Linear Interpolation")
shun-iwasawa 298c96
              << tr("Speed In / Speed Out Interpolation")
shun-iwasawa 298c96
              << tr("Ease In / Ease Out Interpolation")
shun-iwasawa 298c96
              << tr("Ease In / Ease Out (%) Interpolation")
shun-iwasawa 298c96
              << tr("Exponential Interpolation")
shun-iwasawa 298c96
              << tr("Expression Interpolation") << tr("File Interpolation")
shun-iwasawa 298c96
              << tr("Similar Shape Interpolation");
shun_iwasawa 768e20
  QAction activateCycleAction(tr("Activate Cycle"), 0);
shun_iwasawa 768e20
  QAction deactivateCycleAction(tr("Deactivate Cycle"), 0);
shun-iwasawa 260cd7
  QAction showIbtwnAction(tr("Show Inbetween Values"), 0);
shun-iwasawa 260cd7
  QAction hideIbtwnAction(tr("Hide Inbetween Values"), 0);
Shinya Kitaoka 120a6e
Jaroslav 203cc8
  CellPosition cellPosition = getViewer()->xyToPosition(e->pos());
Jaroslav 203cc8
  int row                   = cellPosition.frame();
Jaroslav 203cc8
  int col                   = cellPosition.layer();
Jaroslav 203cc8
  TDoubleParam *curve       = m_sheet->getCurve(col);
Shinya Kitaoka 120a6e
  if (!curve) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool isEmpty    = true;
Shinya Kitaoka 120a6e
  bool isKeyframe = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // find the curve keyframe range
Shinya Kitaoka 120a6e
  int kCount = curve->getKeyframeCount();
Shinya Kitaoka 120a6e
  if (kCount > 0) {
Shinya Kitaoka 120a6e
    if (curve->keyframeIndexToFrame(0) <= row &&
Shinya Kitaoka 120a6e
        row <= curve->keyframeIndexToFrame(kCount - 1)) {
Shinya Kitaoka 120a6e
      isEmpty    = false;
Shinya Kitaoka 120a6e
      isKeyframe = curve->isKeyframe(row);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  int kIndex = curve->getPrevKeyframe(row);
Shinya Kitaoka 120a6e
shun-iwasawa 298c96
  // if the FunctionSelection is not current or when clicking outside of the
shun-iwasawa 298c96
  // selection, then select the clicked cell.
shun-iwasawa 298c96
  FunctionSelection *selection = m_sheet->getSelection();
shun-iwasawa 298c96
  if (!selection->getSelectedCells().contains(col, row)) {
shun-iwasawa 298c96
    selection->makeCurrent();
shun-iwasawa 298c96
    selection->selectCells(QRect(col, row, 1, 1));
shun-iwasawa 298c96
  }
shun-iwasawa 298c96
  CommandManager *cmdManager = CommandManager::instance();
shun-iwasawa 298c96
Shinya Kitaoka 120a6e
  // build menu
Shinya Kitaoka 120a6e
  QMenu menu(0);
shun_iwasawa 768e20
shun_iwasawa 768e20
  // on clicking after last keyframe
shun_iwasawa 768e20
  if (kCount > 0 && isEmpty && kIndex == kCount - 1) {
shun_iwasawa 768e20
    if (curve->isCycleEnabled())
shun_iwasawa 768e20
      menu.addAction(&deactivateCycleAction);
shun_iwasawa 768e20
    else
shun_iwasawa 768e20
      menu.addAction(&activateCycleAction);
shun_iwasawa 768e20
  }
shun_iwasawa 768e20
Shinya Kitaoka 120a6e
  if (!isKeyframe)  // menu.addAction(&deleteKeyframeAction); else
Shinya Kitaoka 120a6e
    menu.addAction(&insertKeyframeAction);
Shinya Kitaoka 120a6e
shun-iwasawa 298c96
  // change interpolation commands
shun-iwasawa 298c96
  QList<qaction *=""> interpActions;</qaction>
shun-iwasawa 298c96
  int interp = selection->getCommonSegmentType();
shun-iwasawa 298c96
  if (interp != -1) {
Shinya Kitaoka 120a6e
    menu.addSeparator();
shun-iwasawa 298c96
    QMenu *interpMenu = menu.addMenu(tr("Change Interpolation"));
shun-iwasawa 298c96
    for (int i = (int)TDoubleKeyframe::Constant;
shun-iwasawa 298c96
         i <= (int)TDoubleKeyframe::SimilarShape; i++) {
shun-iwasawa 298c96
      if (interp != i) {
shun-iwasawa 298c96
        QAction *interpAction = new QAction(interpNames[i - 1], 0);
shun-iwasawa 298c96
        interpAction->setData(i);
shun-iwasawa 298c96
        interpActions.append(interpAction);
shun-iwasawa 298c96
        interpMenu->addAction(interpAction);
shun-iwasawa 298c96
      }
shun-iwasawa 298c96
    }
shun-iwasawa 298c96
  }
shun-iwasawa 260cd7
shun-iwasawa 298c96
  // change step commands
shun-iwasawa 298c96
  int step = selection->getCommonStep();
shun-iwasawa 298c96
  if (step != -1) {
shun-iwasawa 260cd7
    QMenu *stepMenu = menu.addMenu(tr("Change Step"));
shun-iwasawa 298c96
    if (step != 1) stepMenu->addAction(cmdManager->getAction("MI_ResetStep"));
shun-iwasawa 298c96
    if (step != 2) stepMenu->addAction(cmdManager->getAction("MI_Step2"));
shun-iwasawa 298c96
    if (step != 3) stepMenu->addAction(cmdManager->getAction("MI_Step3"));
shun-iwasawa 298c96
    if (step != 4) stepMenu->addAction(cmdManager->getAction("MI_Step4"));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  menu.addSeparator();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  menu.addAction(cmdManager->getAction("MI_Cut"));
Shinya Kitaoka 120a6e
  menu.addAction(cmdManager->getAction("MI_Copy"));
Shinya Kitaoka 120a6e
  menu.addAction(cmdManager->getAction("MI_Paste"));
Shinya Kitaoka 120a6e
  menu.addAction(cmdManager->getAction("MI_Clear"));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  menu.addAction(cmdManager->getAction("MI_Insert"));
Shinya Kitaoka 120a6e
shun-iwasawa 260cd7
  if (!isEmpty && kIndex >= 0) {
shun-iwasawa 260cd7
    menu.addSeparator();
shun-iwasawa 260cd7
    if (m_sheet->isIbtwnValueVisible())
shun-iwasawa 260cd7
      menu.addAction(&hideIbtwnAction);
shun-iwasawa 260cd7
    else
shun-iwasawa 260cd7
      menu.addAction(&showIbtwnAction);
shun-iwasawa 260cd7
  }
shun-iwasawa 260cd7
shun-iwasawa 298c96
  TSceneHandle *sceneHandle = m_sheet->getViewer()->getSceneHandle();
Shinya Kitaoka 120a6e
  // execute menu
Shinya Kitaoka 120a6e
  QAction *action = menu.exec(e->globalPos());  // QCursor::pos());
Shinya Kitaoka 120a6e
  if (action == &deleteKeyframeAction) {
Shinya Kitaoka 120a6e
    KeyframeSetter::removeKeyframeAt(curve, row);
Shinya Kitaoka 120a6e
  } else if (action == &insertKeyframeAction) {
Shinya Kitaoka 120a6e
    KeyframeSetter(curve).createKeyframe(row);
shun-iwasawa 298c96
  } else if (interpActions.contains(action)) {
shun-iwasawa 298c96
    selection->setSegmentType((TDoubleKeyframe::Type)action->data().toInt());
shun-iwasawa 298c96
  } else if (action == &activateCycleAction)
shun_iwasawa 768e20
    KeyframeSetter::enableCycle(curve, true, sceneHandle);
shun_iwasawa 768e20
  else if (action == &deactivateCycleAction)
shun_iwasawa 768e20
    KeyframeSetter::enableCycle(curve, false, sceneHandle);
shun-iwasawa 260cd7
  else if (action == &hideIbtwnAction)
shun-iwasawa 260cd7
    m_sheet->setIbtwnValueVisible(false);
shun-iwasawa 260cd7
  else if (action == &showIbtwnAction)
shun-iwasawa 260cd7
    m_sheet->setIbtwnValueVisible(true);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  update();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
//    FunctionSheetColumnToCurveMapper  implementation
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class FunctionSheetColumnToCurveMapper final : public ColumnToCurveMapper {
Shinya Kitaoka 120a6e
  FunctionSheet *m_sheet;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  FunctionSheetColumnToCurveMapper(FunctionSheet *sheet) : m_sheet(sheet) {}
Shinya Kitaoka 473e70
  TDoubleParam *getCurve(int columnIndex) const override {
Shinya Kitaoka 120a6e
    FunctionTreeModel::Channel *channel = m_sheet->getChannel(columnIndex);
Shinya Kitaoka 120a6e
    if (channel)
Shinya Kitaoka 120a6e
      return channel->getParam();
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      return 0;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
//    FunctionSheet  implementation
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
Jeremy Bullock 4ce953
FunctionSheet::FunctionSheet(QWidget *parent, bool isFloating)
Jeremy Bullock 4ce953
    : SpreadsheetViewer(parent)
Jeremy Bullock 4ce953
    , m_selectedCells()
Jeremy Bullock 4ce953
    , m_selection(0)
Jeremy Bullock 4ce953
    , m_isFloating(isFloating) {
Shinya Kitaoka 120a6e
  setColumnsPanel(m_columnHeadViewer = new FunctionSheetColumnHeadViewer(this));
Shinya Kitaoka 120a6e
  setRowsPanel(m_rowViewer = new FunctionSheetRowViewer(this));
Shinya Kitaoka 120a6e
  setCellsPanel(m_cellViewer = new FunctionSheetCellViewer(this));
Toshihiro Shimizu 890ddd
Jeremy Bullock 4ce953
  setWindowFlag(Qt::Window);
Shinya Kitaoka 120a6e
  setColumnCount(20);
Jeremy Bullock 4ce953
  setWindowTitle(tr("Function Editor"));
Jeremy Bullock 4ce953
  setFocusPolicy(Qt::ClickFocus);
Jeremy Bullock 4ce953
Jeremy Bullock 4ce953
  if (m_isFloating) {
Jeremy Bullock 4ce953
    // load the dialog size
shun-iwasawa 784640
    TFilePath fp(ToonzFolder::getMyModuleDir() + TFilePath("popups.ini"));
shun-iwasawa 784640
    QSettings settings(toQString(fp), QSettings::IniFormat);
shun-iwasawa 784640
shun-iwasawa 784640
    setGeometry(settings.value("FunctionSpreadsheet", QRect(500, 500, 400, 300))
shun-iwasawa 784640
                    .toRect());
Jeremy Bullock 4ce953
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Jeremy Bullock 4ce953
FunctionSheet::~FunctionSheet() {
Jeremy Bullock 4ce953
  if (m_isFloating) {
shun-iwasawa 784640
    TFilePath fp(ToonzFolder::getMyModuleDir() + TFilePath("popups.ini"));
shun-iwasawa 784640
    QSettings settings(toQString(fp), QSettings::IniFormat);
Jeremy Bullock 4ce953
shun-iwasawa 784640
    settings.setValue("FunctionSpreadsheet", geometry());
Jeremy Bullock 4ce953
  }
Jeremy Bullock 4ce953
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool FunctionSheet::anyWidgetHasFocus() {
Shinya Kitaoka 120a6e
  return hasFocus() || m_rowViewer->hasFocus() ||
Shinya Kitaoka 120a6e
         m_columnHeadViewer->hasFocus() || m_cellViewer->hasFocus();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionSheet::setSelection(FunctionSelection *selection) {
Shinya Kitaoka 120a6e
  m_selection = selection;
Shinya Kitaoka 120a6e
  m_selection->setColumnToCurveMapper(
Shinya Kitaoka 120a6e
      new FunctionSheetColumnToCurveMapper(this));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionSheet::showEvent(QShowEvent *e) {
Jaroslav 203cc8
  m_frameScroller.registerFrameScroller();
Shinya Kitaoka 120a6e
  SpreadsheetViewer::showEvent(e);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionSheet::hideEvent(QHideEvent *e) {
Jaroslav 203cc8
  m_frameScroller.unregisterFrameScroller();
Shinya Kitaoka 120a6e
  SpreadsheetViewer::hideEvent(e);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionSheet::onFrameSwitched() {
Shinya Kitaoka 120a6e
  setCurrentRow(getCurrentFrame());
Shinya Kitaoka 120a6e
  m_rowViewer->update();
Shinya Kitaoka 120a6e
  m_cellViewer->update();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionSheet::setCurrentFrame(int frame) {
Shinya Kitaoka 120a6e
  if (getFrameHandle()) getFrameHandle()->setFrame(frame);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int FunctionSheet::getCurrentFrame() const {
Shinya Kitaoka 120a6e
  return getFrameHandle() ? getFrameHandle()->getFrame() : 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int FunctionSheet::getChannelCount() {
Shinya Kitaoka 120a6e
  if (m_functionTreeModel == 0)
Shinya Kitaoka 120a6e
    return 0;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return m_functionTreeModel->getActiveChannelCount();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
FunctionTreeModel::Channel *FunctionSheet::getChannel(int column) {
Shinya Kitaoka 120a6e
  if (m_functionTreeModel == 0)
Shinya Kitaoka 120a6e
    return 0;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return m_functionTreeModel->getActiveChannel(column);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TDoubleParam *FunctionSheet::getCurve(int column) {
Shinya Kitaoka 120a6e
  FunctionTreeModel::Channel *channel = getChannel(column);
Shinya Kitaoka 120a6e
  return channel ? channel->getParam() : 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionSheet::setModel(FunctionTreeModel *model) {
Shinya Kitaoka 120a6e
  m_functionTreeModel = model;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionSheet::setViewer(FunctionViewer *viewer) {
Shinya Kitaoka 120a6e
  m_functionViewer = viewer;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QRect FunctionSheet::getSelectedCells() const {
Shinya Kitaoka 120a6e
  if (getSelection())
Shinya Kitaoka 120a6e
    return getSelection()->getSelectedCells();
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return QRect();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionSheet::selectCells(const QRect &selectedCells) {
Shinya Kitaoka 120a6e
  m_selectedCells = selectedCells;
Shinya Kitaoka 120a6e
  if (getSelection()) {
Shinya Kitaoka 120a6e
    QList<tdoubleparam *=""> curves;</tdoubleparam>
Shinya Kitaoka 120a6e
    for (int c = selectedCells.left(); c <= selectedCells.right(); c++) {
shun-iwasawa 260cd7
      TDoubleParam *param = 0;
Shinya Kitaoka 120a6e
      if (c < getChannelCount()) param = getChannel(c)->getParam();
Shinya Kitaoka 120a6e
      curves.push_back(param);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    getSelection()->selectCells(selectedCells, curves);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (selectedCells.width() == 1 && curves[0] &&
Shinya Kitaoka 120a6e
        !getChannel(selectedCells.x())->isCurrent())
Shinya Kitaoka 120a6e
      getChannel(selectedCells.x())->setIsCurrent(true);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  updateAll();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionSheet::updateAll() {
Shinya Kitaoka 120a6e
  m_rowViewer->update();
Shinya Kitaoka 120a6e
  m_columnHeadViewer->update();
Shinya Kitaoka 120a6e
  m_cellViewer->update();
Shinya Kitaoka 120a6e
  setColumnCount(getChannelCount());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Display expression name of the current segment
shun-iwasawa 260cd7
 */
Shinya Kitaoka 120a6e
QString FunctionSheet::getSelectedParamName() {
Shinya Kitaoka 120a6e
  if (m_functionTreeModel->getCurrentChannel())
Shinya Kitaoka 120a6e
    return m_functionTreeModel->getCurrentChannel()->getExprRefName();
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return QString();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int FunctionSheet::getColumnIndexByCurve(TDoubleParam *param) const {
Shinya Kitaoka 120a6e
  return m_functionTreeModel->getColumnIndexByCurve(param);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
/*! scroll column to show the current one
shun-iwasawa 260cd7
 */
Shinya Kitaoka 120a6e
void FunctionSheet::onCurrentChannelChanged(
Shinya Kitaoka 120a6e
    FunctionTreeModel::Channel *channel) {
Shinya Kitaoka 120a6e
  if (!channel) return;
Shinya Kitaoka 120a6e
  for (int c = 0; c < getChannelCount(); c++) {
Shinya Kitaoka 120a6e
    FunctionTreeModel::Channel *tmpChan = getChannel(c);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (tmpChan == channel) {
Shinya Kitaoka 120a6e
      ensureVisibleCol(c);
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
shun_iwasawa 768e20
shun_iwasawa 768e20
//-----------------------------------------------------------------------------
shun_iwasawa 768e20
/*! Obtains a pointer to the stage object containing the parameter of specified
shun_iwasawa 768e20
 * column
shun-iwasawa 260cd7
 */
shun_iwasawa 768e20
TStageObject *FunctionSheet::getStageObject(int column) {
shun_iwasawa 768e20
  FunctionTreeModel::Channel *channel = getChannel(column);
shun_iwasawa 768e20
  if (!channel) return nullptr;
shun_iwasawa 768e20
shun_iwasawa 768e20
  FunctionTreeModel::ChannelGroup *channelGroup = channel->getChannelGroup();
shun_iwasawa 768e20
  if (!channelGroup) return nullptr;
shun_iwasawa 768e20
shun_iwasawa 768e20
  // returns nullptr if the channel is a fx parameter
shun_iwasawa 768e20
  StageObjectChannelGroup *stageItem =
shun_iwasawa 768e20
      dynamic_cast<stageobjectchannelgroup *="">(channelGroup);</stageobjectchannelgroup>
shun_iwasawa 768e20
  if (!stageItem) return nullptr;
shun_iwasawa 768e20
shun_iwasawa 768e20
  return stageItem->getStageObject();
shun_iwasawa 768e20
}