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:
Rodney 2019-08-06 16:41:26 -05:00 committed by GitHub
commit 3ca92c27e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 163 additions and 44 deletions

View file

@ -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

View file

@ -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;

View file

@ -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
//*****************************************************************************************

View file

@ -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;

View file

@ -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) {

View file

@ -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));
}

View file

@ -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();
}

View file

@ -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

View file

@ -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();
}