Merge pull request #2655 from shun-iwasawa/display_cycle_in_function_sheet
Display Cycled Values in Function Editor Spread Sheet
This commit is contained in:
commit
3ca92c27e4
9 changed files with 163 additions and 44 deletions
|
@ -18,6 +18,7 @@
|
|||
#endif
|
||||
|
||||
class KeyframesUndo;
|
||||
class TSceneHandle;
|
||||
|
||||
class DVAPI KeyframeSetter {
|
||||
TDoubleParamP m_param;
|
||||
|
@ -101,7 +102,8 @@ public:
|
|||
}
|
||||
static void removeKeyframeAt(TDoubleParam *curve, double frame);
|
||||
|
||||
static void enableCycle(TDoubleParam *curve, bool enabled);
|
||||
static void enableCycle(TDoubleParam *curve, bool enabled,
|
||||
TSceneHandle *sceneHandle = nullptr);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -124,6 +124,11 @@ public:
|
|||
int getColumnIndexByCurve(TDoubleParam *param) const;
|
||||
bool anyWidgetHasFocus();
|
||||
|
||||
// Obtains a pointer to the stage object containing the
|
||||
// parameter of specified column. Returns nullptr for
|
||||
// fx parameter columns.
|
||||
TStageObject *getStageObject(int column);
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *e) override;
|
||||
void hideEvent(QHideEvent *e) override;
|
||||
|
|
|
@ -336,6 +336,31 @@ public:
|
|||
void refresh() override;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
|
||||
class StageObjectChannelGroup final : public FunctionTreeModel::ChannelGroup {
|
||||
public:
|
||||
TStageObject *m_stageObject; //!< (not owned) Referenced stage object
|
||||
FunctionTreeModel::ChannelGroup
|
||||
*m_plasticGroup; //!< (not owned) Eventual plastic channels group
|
||||
|
||||
public:
|
||||
StageObjectChannelGroup(TStageObject *pegbar);
|
||||
~StageObjectChannelGroup();
|
||||
|
||||
QString getShortName() const override;
|
||||
QString getLongName() const override;
|
||||
|
||||
QString getIdName() const override;
|
||||
|
||||
void *getInternalPointer() const override {
|
||||
return static_cast<void *>(m_stageObject);
|
||||
}
|
||||
|
||||
TStageObject *getStageObject() const { return m_stageObject; }
|
||||
QVariant data(int role) const override;
|
||||
};
|
||||
|
||||
//*****************************************************************************************
|
||||
// FunctionTreeView declaration
|
||||
//*****************************************************************************************
|
||||
|
|
|
@ -120,6 +120,8 @@ public:
|
|||
void clearFocusColumnsAndGraph();
|
||||
bool columnsOrGraphHasFocus();
|
||||
void setSceneHandle(TSceneHandle *sceneHandle);
|
||||
TSceneHandle *getSceneHandle() const { return m_sceneHandle; }
|
||||
|
||||
// SaveLoadQSettings
|
||||
virtual void save(QSettings &settings) const override;
|
||||
virtual void load(QSettings &settings) override;
|
||||
|
|
|
@ -2512,6 +2512,8 @@ public:
|
|||
void undo() const override {
|
||||
m_pegbar->enableCycle(!m_pegbar->isCycleEnabled());
|
||||
m_area->update();
|
||||
TApp::instance()->getCurrentScene()->setDirtyFlag(true);
|
||||
TApp::instance()->getCurrentObject()->notifyObjectIdChanged(false);
|
||||
}
|
||||
void redo() const override { undo(); }
|
||||
int getSize() const override { return sizeof *this; }
|
||||
|
@ -2675,8 +2677,9 @@ void CellArea::mousePressEvent(QMouseEvent *event) {
|
|||
} else if (isKeyframeFrame && row == k1 + 1 &&
|
||||
o->rect(PredefinedRect::LOOP_ICON)
|
||||
.contains(mouseInCell)) { // cycle toggle
|
||||
pegbar->enableCycle(!pegbar->isCycleEnabled());
|
||||
TUndoManager::manager()->add(new CycleUndo(pegbar, this));
|
||||
CycleUndo *undo = new CycleUndo(pegbar, this);
|
||||
undo->redo();
|
||||
TUndoManager::manager()->add(undo);
|
||||
accept = true;
|
||||
}
|
||||
if (accept) {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "toonz/doubleparamcmd.h"
|
||||
#include "toonz/preferences.h"
|
||||
#include "toonz/tscenehandle.h"
|
||||
#include "tdoubleparam.h"
|
||||
#include "tdoublekeyframe.h"
|
||||
#include "tundo.h"
|
||||
|
@ -830,13 +831,23 @@ void KeyframeSetter::removeKeyframeAt(TDoubleParam *curve, double frame) {
|
|||
|
||||
class EnableCycleUndo final : public TUndo {
|
||||
TDoubleParam *m_param;
|
||||
TSceneHandle *m_sceneHandle;
|
||||
|
||||
public:
|
||||
EnableCycleUndo(TDoubleParam *param) : m_param(param) { m_param->addRef(); }
|
||||
EnableCycleUndo(TDoubleParam *param, TSceneHandle *sceneHandle)
|
||||
: m_param(param), m_sceneHandle(sceneHandle) {
|
||||
m_param->addRef();
|
||||
}
|
||||
~EnableCycleUndo() { m_param->release(); }
|
||||
void invertCycleEnabled() const {
|
||||
bool isEnabled = m_param->isCycleEnabled();
|
||||
m_param->enableCycle(!isEnabled);
|
||||
// for now the scene handle is only available when RMB click in function
|
||||
// sheet
|
||||
if (m_sceneHandle) {
|
||||
m_sceneHandle->setDirtyFlag(true);
|
||||
m_sceneHandle->notifySceneChanged();
|
||||
}
|
||||
}
|
||||
void undo() const override { invertCycleEnabled(); }
|
||||
void redo() const override { invertCycleEnabled(); }
|
||||
|
@ -847,7 +858,9 @@ public:
|
|||
|
||||
//=============================================================================
|
||||
|
||||
void KeyframeSetter::enableCycle(TDoubleParam *curve, bool enabled) {
|
||||
void KeyframeSetter::enableCycle(TDoubleParam *curve, bool enabled,
|
||||
TSceneHandle *sceneHandle) {
|
||||
curve->enableCycle(enabled);
|
||||
TUndoManager::manager()->add(new EnableCycleUndo(curve));
|
||||
sceneHandle->notifySceneChanged();
|
||||
TUndoManager::manager()->add(new EnableCycleUndo(curve, sceneHandle));
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "toonz/doubleparamcmd.h"
|
||||
#include "toonz/preferences.h"
|
||||
#include "toonz/toonzfolders.h"
|
||||
#include "toonz/tstageobject.h"
|
||||
|
||||
// TnzBase includes
|
||||
#include "tunit.h"
|
||||
|
@ -579,6 +580,13 @@ void FunctionSheetCellViewer::drawCells(QPainter &painter, int r0, int c0,
|
|||
TMeasure *measure = curve->getMeasure();
|
||||
const TUnit *unit = measure ? measure->getCurrentUnit() : 0;
|
||||
|
||||
bool isStageObjectCycled = false;
|
||||
TStageObject *obj = m_sheet->getStageObject(c);
|
||||
if (obj && obj->isCycleEnabled()) isStageObjectCycled = true;
|
||||
|
||||
bool isParamCycled = curve->isCycleEnabled();
|
||||
int rowCount = getViewer()->getRowCount();
|
||||
|
||||
// draw each cell
|
||||
for (int row = r0; row <= r1; row++) {
|
||||
int ya = m_sheet->rowToY(row);
|
||||
|
@ -586,8 +594,11 @@ void FunctionSheetCellViewer::drawCells(QPainter &painter, int r0, int c0,
|
|||
|
||||
bool isSelected = getViewer()->isSelectedCell(row, c);
|
||||
|
||||
double value = curve->getValue(row);
|
||||
double value = (isStageObjectCycled)
|
||||
? curve->getValue(obj->paramsTime((double)row))
|
||||
: curve->getValue(row);
|
||||
if (unit) value = unit->convertTo(value);
|
||||
enum { None, KeyRange, CycleRange } drawValue = None;
|
||||
|
||||
QRect cellRect(x0, ya, x1 - x0 + 1, yb - ya + 1);
|
||||
QRect borderRect(x0, ya, 7, yb - ya + 1);
|
||||
|
@ -622,8 +633,42 @@ void FunctionSheetCellViewer::drawCells(QPainter &painter, int r0, int c0,
|
|||
}
|
||||
}
|
||||
|
||||
drawValue = KeyRange;
|
||||
|
||||
}
|
||||
// empty cells
|
||||
else {
|
||||
// show values for cycled parameter.
|
||||
// cycle option can be set in two ways; one is as TStageObject,
|
||||
// the other is as TDoubleParam.
|
||||
// - TStageObject cycle literally cycles values with no offset.
|
||||
// Applied to all transformation parameters of the cycled object.
|
||||
// - TDoubleParam cycle includes value offset so that the curve
|
||||
// connects smoothly.
|
||||
// - TStageObject cycle option has a priority to TDoubleParam one.
|
||||
// (see TStageObject::paramsTime() in tstageobject.cpp)
|
||||
if (kCount > 0 && row > kr1 && (isStageObjectCycled || isParamCycled) &&
|
||||
(row < rowCount)) {
|
||||
drawValue = CycleRange;
|
||||
}
|
||||
// empty and selected cell
|
||||
if (isSelected) {
|
||||
cellColor = (row >= rowCount) ? SelectedEmptyColor
|
||||
: SelectedSceneRangeEmptyColor;
|
||||
painter.setPen(Qt::NoPen);
|
||||
painter.fillRect(cellRect, cellColor);
|
||||
}
|
||||
}
|
||||
|
||||
if (drawValue != None) {
|
||||
// draw cell value
|
||||
painter.setPen(getViewer()->getTextColor());
|
||||
if (drawValue == KeyRange)
|
||||
painter.setPen(getViewer()->getTextColor());
|
||||
else {
|
||||
QColor semiTranspTextColor = getViewer()->getTextColor();
|
||||
semiTranspTextColor.setAlpha(128);
|
||||
painter.setPen(semiTranspTextColor);
|
||||
}
|
||||
|
||||
/*--- 整数から小数点以下3桁以内の場合はそれ以降の0000を描かない ---*/
|
||||
QString text;
|
||||
|
@ -653,19 +698,31 @@ void FunctionSheetCellViewer::drawCells(QPainter &painter, int r0, int c0,
|
|||
fontName = "Helvetica";
|
||||
#endif
|
||||
}
|
||||
static QFont font(fontName, -1, QFont::Bold);
|
||||
static QFont font(fontName, -1);
|
||||
font.setBold(drawValue == KeyRange);
|
||||
font.setPixelSize(12);
|
||||
painter.setFont(font);
|
||||
painter.drawText(cellRect.adjusted(10, 0, 0, 0),
|
||||
Qt::AlignVCenter | Qt::AlignLeft, text);
|
||||
Qt::AlignVCenter | Qt::AlignRight, text);
|
||||
}
|
||||
// empty and selected cell
|
||||
else if (isSelected) {
|
||||
int rowCount = getViewer()->getRowCount();
|
||||
cellColor = (row >= rowCount) ? SelectedEmptyColor
|
||||
: SelectedSceneRangeEmptyColor;
|
||||
painter.setPen(Qt::NoPen);
|
||||
painter.fillRect(cellRect, cellColor);
|
||||
}
|
||||
|
||||
if (kCount > 0 && (isStageObjectCycled || isParamCycled)) {
|
||||
// draw the row zigzag
|
||||
int ymax = m_sheet->rowToY(r1 + 1);
|
||||
int qx = x0 + 4;
|
||||
int qy = m_sheet->rowToY(kr1 + 1);
|
||||
int zig = 2;
|
||||
QColor zigzagColor = (isStageObjectCycled) ? getViewer()->getTextColor()
|
||||
: KeyFrameBorderColor;
|
||||
painter.setPen(zigzagColor);
|
||||
painter.drawLine(QPoint(qx, qy), QPoint(qx - zig, qy + zig));
|
||||
qy += zig;
|
||||
while (qy < ymax) {
|
||||
painter.drawLine(QPoint(qx - zig, qy), QPoint(qx + zig, qy + 2 * zig));
|
||||
painter.drawLine(QPoint(qx + zig, qy + 2 * zig),
|
||||
QPoint(qx - zig, qy + 4 * zig));
|
||||
qy += 4 * zig;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -835,6 +892,8 @@ void FunctionSheetCellViewer::openContextMenu(QMouseEvent *e) {
|
|||
QAction setStep2Action(tr("Step 2"), 0);
|
||||
QAction setStep3Action(tr("Step 3"), 0);
|
||||
QAction setStep4Action(tr("Step 4"), 0);
|
||||
QAction activateCycleAction(tr("Activate Cycle"), 0);
|
||||
QAction deactivateCycleAction(tr("Deactivate Cycle"), 0);
|
||||
|
||||
CellPosition cellPosition = getViewer()->xyToPosition(e->pos());
|
||||
int row = cellPosition.frame();
|
||||
|
@ -858,6 +917,15 @@ void FunctionSheetCellViewer::openContextMenu(QMouseEvent *e) {
|
|||
|
||||
// build menu
|
||||
QMenu menu(0);
|
||||
|
||||
// on clicking after last keyframe
|
||||
if (kCount > 0 && isEmpty && kIndex == kCount - 1) {
|
||||
if (curve->isCycleEnabled())
|
||||
menu.addAction(&deactivateCycleAction);
|
||||
else
|
||||
menu.addAction(&activateCycleAction);
|
||||
}
|
||||
|
||||
if (!isKeyframe) // menu.addAction(&deleteKeyframeAction); else
|
||||
menu.addAction(&insertKeyframeAction);
|
||||
|
||||
|
@ -896,7 +964,7 @@ void FunctionSheetCellViewer::openContextMenu(QMouseEvent *e) {
|
|||
menu.addAction(cmdManager->getAction("MI_Insert"));
|
||||
|
||||
FunctionSelection *selection = m_sheet->getSelection();
|
||||
|
||||
TSceneHandle *sceneHandle = m_sheet->getViewer()->getSceneHandle();
|
||||
// execute menu
|
||||
QAction *action = menu.exec(e->globalPos()); // QCursor::pos());
|
||||
if (action == &deleteKeyframeAction) {
|
||||
|
@ -935,6 +1003,10 @@ void FunctionSheetCellViewer::openContextMenu(QMouseEvent *e) {
|
|||
KeyframeSetter(curve, kIndex).setStep(3);
|
||||
else if (action == &setStep4Action)
|
||||
KeyframeSetter(curve, kIndex).setStep(4);
|
||||
else if (action == &activateCycleAction)
|
||||
KeyframeSetter::enableCycle(curve, true, sceneHandle);
|
||||
else if (action == &deactivateCycleAction)
|
||||
KeyframeSetter::enableCycle(curve, false, sceneHandle);
|
||||
|
||||
update();
|
||||
}
|
||||
|
@ -1152,3 +1224,22 @@ void FunctionSheet::onCurrentChannelChanged(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/*! Obtains a pointer to the stage object containing the parameter of specified
|
||||
* column
|
||||
*/
|
||||
TStageObject *FunctionSheet::getStageObject(int column) {
|
||||
FunctionTreeModel::Channel *channel = getChannel(column);
|
||||
if (!channel) return nullptr;
|
||||
|
||||
FunctionTreeModel::ChannelGroup *channelGroup = channel->getChannelGroup();
|
||||
if (!channelGroup) return nullptr;
|
||||
|
||||
// returns nullptr if the channel is a fx parameter
|
||||
StageObjectChannelGroup *stageItem =
|
||||
dynamic_cast<StageObjectChannelGroup *>(channelGroup);
|
||||
if (!stageItem) return nullptr;
|
||||
|
||||
return stageItem->getStageObject();
|
||||
}
|
|
@ -64,31 +64,6 @@ public:
|
|||
|
||||
//=============================================================================
|
||||
|
||||
class StageObjectChannelGroup final : public FunctionTreeModel::ChannelGroup {
|
||||
public:
|
||||
TStageObject *m_stageObject; //!< (not owned) Referenced stage object
|
||||
FunctionTreeModel::ChannelGroup
|
||||
*m_plasticGroup; //!< (not owned) Eventual plastic channels group
|
||||
|
||||
public:
|
||||
StageObjectChannelGroup(TStageObject *pegbar);
|
||||
~StageObjectChannelGroup();
|
||||
|
||||
QString getShortName() const override;
|
||||
QString getLongName() const override;
|
||||
|
||||
QString getIdName() const override;
|
||||
|
||||
void *getInternalPointer() const override {
|
||||
return static_cast<void *>(m_stageObject);
|
||||
}
|
||||
|
||||
TStageObject *getStageObject() const { return m_stageObject; }
|
||||
QVariant data(int role) const override;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
|
||||
class SkVDChannelGroup final : public FunctionTreeModel::ChannelGroup {
|
||||
public:
|
||||
StageObjectChannelGroup *m_stageObjectGroup; //!< Parent stage object group
|
||||
|
|
|
@ -582,7 +582,10 @@ void FunctionViewer::onStageObjectChanged(bool isDragging) {
|
|||
static_cast<FunctionTreeModel *>(m_treeView->model())
|
||||
->setCurrentStageObject(obj);
|
||||
|
||||
if (!isDragging) m_treeView->updateAll();
|
||||
if (!isDragging) {
|
||||
m_treeView->updateAll();
|
||||
m_numericalColumns->updateAll();
|
||||
}
|
||||
|
||||
m_functionGraph->update();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue