You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/LyShine/Code/Editor/Animation/UiAnimViewDialog.cpp

1831 lines
61 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
//----- UI_ANIMATION_REVISIT - this is required to compile since something we include still uses MFC
// prevent inclusion of conflicting definitions of INT8_MIN etc
#define _INTSAFE_H_INCLUDED_
// ----- End UI_ANIMATION_REVISIT
#include "EditorDefs.h"
#include "Resource.h"
#include "UiAnimViewDialog.h"
#include "ViewPane.h"
#include "StringDlg.h"
#include "UiAVSequenceProps.h"
#include "ViewManager.h"
#include "AnimationContext.h"
#include "UiAnimViewFindDlg.h"
#include "UiAnimViewUndo.h"
#include "UiAnimViewAnimNode.h"
#include "UiAnimViewTrack.h"
#include "UiAnimViewSequence.h"
#include "UiAnimViewSequenceManager.h"
#include "UiAVCustomizeTrackColorsDlg.h"
#include "QtUtilWin.h"
#include <AzQtComponents/Components/StyledDockWidget.h>
#include <AzQtComponents/Components/Widgets/ToolBar.h>
#include "Objects/EntityObject.h"
#include "IViewPane.h"
#include "PluginManager.h"
#include "Util/3DConnexionDriver.h"
#include "UiAnimViewNewSequenceDialog.h"
#include "UiAnimViewCurveEditor.h"
#include <LyShine/Animation/IUiAnimation.h>
#include "UiAnimViewKeyPropertiesDlg.h"
#include "UiEditorAnimationBus.h"
#include "EditorCommon.h"
#include <QtViewPane.h>
#include <QAction>
#include <QComboBox>
#include <QKeyEvent>
#include <QLabel>
#include <QMenu>
#include <QMenuBar>
#include <QMessageBox>
#include <QSettings>
#include <QSplitter>
#include <QTimer>
#include <QToolBar>
#include <QToolButton>
#include <QVBoxLayout>
#include <QTextDocumentFragment>
//////////////////////////////////////////////////////////////////////////
namespace
{
const char* s_kUiAnimViewLayoutSection = "UiAnimViewLayout";
const char* s_kUiAnimViewSection = "DockingPaneLayouts\\UiAnimView";
const char* s_kSplitterEntry = "Splitter";
const char* s_kVersionEntry = "UiAnimViewLayoutVersion";
const char* s_kUiAnimViewSettingsSection = "UiAnimView";
const char* s_kSnappingModeEntry = "SnappingMode";
const char* s_kFrameSnappingFPSEntry = "FrameSnappingFPS";
const char* s_kTickDisplayModeEntry = "TickDisplayMode";
const char* s_kDefaultTracksEntry = "DefaultTracks";
const char* s_kRebarVersionEntry = "UiAnimViewReBarVersion";
const char* s_kRebarBandEntryPrefix = "ReBarBand";
const char* s_kNoSequenceComboBoxEntry = "--- No Sequence ---";
const int TRACKVIEW_LAYOUT_VERSION = 0x0001; // Bump this up on every substantial pane layout change
const int TRACKVIEW_REBAR_VERSION = 0x0002; // Bump this up on every substantial rebar change
}
//////////////////////////////////////////////////////////////////////////
CUiAnimViewDialog* CUiAnimViewDialog::s_pUiAnimViewDialog = NULL;
//////////////////////////////////////////////////////////////////////////
class CUiAnimViewExpanderWatcher
: public QObject
{
public:
CUiAnimViewExpanderWatcher(QObject* parent = nullptr)
: QObject(parent)
{
}
bool eventFilter(QObject* obj, QEvent* event) override
{
switch (event->type())
{
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
{
if (qobject_cast<QToolButton*>(obj))
{
auto mouseEvent = static_cast<QMouseEvent*>(event);
auto expansion = qobject_cast<QToolButton*>(obj);
expansion->setPopupMode(QToolButton::InstantPopup);
auto menu = new QMenu(expansion);
auto toolbar = qobject_cast<QToolBar*>(expansion->parentWidget());
for (auto toolbarAction : toolbar->actions())
{
auto actionWidget = toolbar->widgetForAction(toolbarAction);
if (actionWidget && !actionWidget->isVisible() && !toolbarAction->text().isEmpty())
{
QString plainText = QTextDocumentFragment::fromHtml(actionWidget->toolTip()).toPlainText();
toolbarAction->setText(plainText);
menu->addAction(toolbarAction);
}
}
menu->exec(mouseEvent->globalPos());
return true;
}
break;
}
}
return QObject::eventFilter(obj, event);
}
};
//////////////////////////////////////////////////////////////////////////
CUiAnimViewDialog::CUiAnimViewDialog(QWidget* pParent /*=NULL*/)
: QMainWindow(pParent)
, m_animationSystem(nullptr)
{
s_pUiAnimViewDialog = this;
m_bRecord = false;
m_bPause = false;
m_bPlay = false;
m_fLastTime = -1.0f;
m_bNeedReloadSequence = false;
m_bIgnoreUpdates = false;
m_bDoingUndoOperation = false;
m_findDlg = nullptr;
m_lazyInitDone = false;
m_bEditLock = false;
m_currentToolBarParamTypeId = 0;
m_expanderWatcher = new CUiAnimViewExpanderWatcher(this);
UiEditorAnimationStateBus::Handler::BusConnect();
UiEditorAnimListenerBus::Handler::BusConnect();
GetIEditor()->RegisterNotifyListener(this);
m_sequenceManager = CUiAnimViewSequenceManager::GetSequenceManager();
if (m_sequenceManager)
{
m_animationContext = m_sequenceManager->GetAnimationContext();
m_animationContext->AddListener(this);
CUiAnimViewSequenceManager::GetSequenceManager()->AddListener(this);
}
else
{
m_animationContext = nullptr;
}
UiAnimUndoManager::Get()->AddListener(this);
// There may already be a loaded canvas (since UI Editor is a separate window)
m_animationSystem = CUiAnimViewSequenceManager::GetSequenceManager()->GetAnimationSystem();
OnInitDialog();
// update the status of the actions
UpdateActions();
if (!m_animationSystem)
{
setEnabled(false);
}
}
CUiAnimViewDialog::~CUiAnimViewDialog()
{
SaveLayouts();
SaveMiscSettings();
SaveTrackColors();
if (m_findDlg)
{
m_findDlg->deleteLater();
m_findDlg = nullptr;
}
s_pUiAnimViewDialog = 0;
const CUiAnimViewSequenceManager* pSequenceManager = CUiAnimViewSequenceManager::GetSequenceManager();
CUiAnimViewSequence* pSequence = pSequenceManager->GetSequenceByName(m_currentSequenceName);
if (pSequence)
{
pSequence->RemoveListener(this);
pSequence->RemoveListener(m_wndNodesCtrl);
pSequence->RemoveListener(m_wndKeyProperties);
pSequence->RemoveListener(m_wndCurveEditor);
pSequence->RemoveListener(m_wndDopeSheet);
}
UiAnimUndoManager::Get()->RemoveListener(this);
CUiAnimViewSequenceManager::GetSequenceManager()->RemoveListener(this);
m_animationContext->RemoveListener(this);
GetIEditor()->UnregisterNotifyListener(this);
// UI_ANIMATION_REVISIT it seems something should be deleting these
delete m_wndCurveEditor;
delete m_wndCurveEditorDock;
UiEditorAnimationStateBus::Handler::BusDisconnect();
UiEditorAnimListenerBus::Handler::BusDisconnect();
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnAddEntityNodeMenu()
{
// UI_ANIMATION_REVISIT - is there any need for this function?
}
//////////////////////////////////////////////////////////////////////////
BOOL CUiAnimViewDialog::OnInitDialog()
{
InitToolbar();
InitMenu();
QWidget* w = new QWidget();
QVBoxLayout* l = new QVBoxLayout;
l->setMargin(0);
m_wndSplitter = new QSplitter(w);
m_wndSplitter->setOrientation(Qt::Horizontal);
m_wndNodesCtrl = new CUiAnimViewNodesCtrl(this, this);
m_wndNodesCtrl->SetUiAnimViewDialog(this);
m_wndDopeSheet = new CUiAnimViewDopeSheetBase(this);
m_wndDopeSheet->SetTimeRange(0, 20);
m_wndDopeSheet->SetTimeScale(100, 0);
m_wndDopeSheet->SetNodesCtrl(m_wndNodesCtrl);
m_wndNodesCtrl->SetDopeSheet(m_wndDopeSheet);
m_wndSplitter->addWidget(m_wndNodesCtrl);
m_wndSplitter->addWidget(m_wndDopeSheet);
m_wndSplitter->setStretchFactor(0, 1);
m_wndSplitter->setStretchFactor(1, 10);
l->addWidget(m_wndSplitter);
w->setLayout(l);
setCentralWidget(w);
m_wndKeyProperties = new CUiAnimViewKeyPropertiesDlg(this);
QDockWidget* dw = new AzQtComponents::StyledDockWidget(this);
dw->setObjectName("m_wndKeyProperties");
dw->setWindowTitle("Key");
dw->setWidget(m_wndKeyProperties);
addDockWidget(Qt::RightDockWidgetArea, dw);
m_wndKeyProperties->PopulateVariables();
m_wndKeyProperties->SetKeysCtrl(m_wndDopeSheet);
m_wndCurveEditorDock = new AzQtComponents::StyledDockWidget(this);
m_wndCurveEditorDock->setObjectName("m_wndCurveEditorDock");
m_wndCurveEditorDock->setWindowTitle("Curve Editor");
m_wndCurveEditor = new UiAnimViewCurveEditorDialog(this);
m_wndCurveEditorDock->setWidget(m_wndCurveEditor);
addDockWidget(Qt::BottomDockWidgetArea, m_wndCurveEditorDock);
m_wndCurveEditor->SetPlayCallback([this] { OnPlay();
});
// Close/hide by default to avoid the pane to show up as a standalone, white window when not displayed in a layout.
m_wndCurveEditorDock->setVisible(false);
m_wndCurveEditorDock->setEnabled(false);
InitSequences();
m_lazyInitDone = false;
QTimer::singleShot(0, this, SLOT(ReadLayouts()));
// ReadLayouts();
ReadMiscSettings();
ReadTrackColors();
QString cursorPosText = QString("0.000(%1fps)").arg(FloatToIntRet(m_wndCurveEditor->GetFPS()));
m_cursorPos->setText(cursorPosText);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CUiAnimViewDialog::InitToolbar()
{
m_mainToolBar = addToolBar("Sequence/Node Toolbar");
m_mainToolBar->setObjectName("m_mainToolBar");
m_mainToolBar->setFloatable(false);
m_mainToolBar->addWidget(new QLabel("Sequence/Node:"));
QAction* qaction = m_mainToolBar->addAction(QIcon(":/Trackview/main/tvmain-00.png"), "Add Sequence");
qaction->setData(ID_TV_ADD_SEQUENCE);
m_actions[ID_TV_ADD_SEQUENCE] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnAddSequence);
qaction = m_mainToolBar->addAction(QIcon(":/Trackview/main/tvmain-01.png"), "Delete Sequence");
qaction->setData(ID_TV_DEL_SEQUENCE);
m_actions[ID_TV_DEL_SEQUENCE] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnDelSequence);
qaction = m_mainToolBar->addAction(QIcon(":/Trackview/main/tvmain-02.png"), "Edit Sequence");
qaction->setData(ID_TV_EDIT_SEQUENCE);
m_actions[ID_TV_EDIT_SEQUENCE] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnEditSequence);
m_sequencesComboBox = new QComboBox(this);
connect(m_sequencesComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSequenceComboBox()));
m_mainToolBar->addWidget(m_sequencesComboBox);
m_mainToolBar->addSeparator();
qaction = m_mainToolBar->addAction(QIcon(":/Trackview/main/tvmain-03.png"), "Add Selected Node");
qaction->setData(ID_ADDNODE);
m_actions[ID_ADDNODE] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnAddSelectedNode);
qaction = m_mainToolBar->addAction(QIcon(":/Trackview/main/tvmain-05.png"), "Find");
qaction->setData(ID_FIND);
m_actions[ID_FIND] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnFindNode);
qaction = m_mainToolBar->addAction(QIcon(":/Trackview/main/tvmain-06.png"), "Toggle Disable");
qaction->setCheckable(true);
qaction->setData(ID_TRACKVIEW_TOGGLE_DISABLE);
m_actions[ID_TRACKVIEW_TOGGLE_DISABLE] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnToggleDisable);
if (QToolButton* expansion = AzQtComponents::ToolBar::getToolBarExpansionButton(m_mainToolBar))
{
expansion->installEventFilter(m_expanderWatcher);
}
m_viewToolBar = addToolBar("View Toolbar");
m_viewToolBar->setObjectName("m_viewToolBar");
m_viewToolBar->setFloatable(false);
m_viewToolBar->addWidget(new QLabel("View:"));
qaction = m_viewToolBar->addAction(QIcon(":/Trackview/view/tvview-00.png"), "Track Editor");
qaction->setData(ID_TV_MODE_DOPESHEET);
qaction->setShortcut(QKeySequence("Ctrl+D"));
qaction->setCheckable(true);
qaction->setChecked(true);
m_actions[ID_TV_MODE_DOPESHEET] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnModeDopeSheet);
qaction = m_viewToolBar->addAction(QIcon(":/Trackview/view/tvview-01.png"), "Curve Editor");
qaction->setData(ID_TV_MODE_CURVEEDITOR);
qaction->setShortcut(QKeySequence("Ctrl+R"));
qaction->setCheckable(true);
m_actions[ID_TV_MODE_CURVEEDITOR] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnModeCurveEditor);
qaction = m_viewToolBar->addAction(QIcon(":/Trackview/view/tvview-02.png"), "Both");
qaction->setData(ID_TV_MODE_OPENCURVEEDITOR);
qaction->setShortcut(QKeySequence("Ctrl+B"));
m_actions[ID_TV_MODE_OPENCURVEEDITOR] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnOpenCurveEditor);
if (QToolButton* expansion = AzQtComponents::ToolBar::getToolBarExpansionButton(m_viewToolBar))
{
expansion->installEventFilter(m_expanderWatcher);
}
m_playToolBar = addToolBar("Play Toolbar");
m_playToolBar->setObjectName("m_playToolBar");
m_playToolBar->setFloatable(false);
m_playToolBar->addWidget(new QLabel("Play:"));
qaction = m_playToolBar->addAction(QIcon(":/Trackview/play/tvplay-00.png"), "Go to start of sequence");
qaction->setData(ID_TV_JUMPSTART);
m_actions[ID_TV_JUMPSTART] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnGoToStart);
QToolButton* toolButton = new QToolButton(m_playToolBar);
toolButton->setPopupMode(QToolButton::MenuButtonPopup);
qaction = new QAction(QIcon(":/Trackview/play/tvplay-01.png"), "Play Animation", this);
qaction->setData(ID_TV_PLAY);
qaction->setCheckable(true);
m_actions[ID_TV_PLAY] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnPlay);
qaction->setShortcut(QKeySequence(Qt::Key_Space));
qaction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
toolButton->setDefaultAction(qaction);
{
QMenu* buttonMenu = new QMenu(this);
toolButton->setMenu(buttonMenu);
QActionGroup* ag = new QActionGroup(buttonMenu);
for (auto i : { .5, 1., 2., 4., 8. })
{
if (i == .5)
{
qaction = buttonMenu->addAction(" 2 ");
}
else if (i == 1.)
{
qaction = buttonMenu->addAction(" 1 ");
}
else
{
qaction = buttonMenu->addAction(QString("1/%1").arg((int)i));
}
qaction->setData(i);
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnPlaySetScale);
qaction->setCheckable(true);
qaction->setChecked(i == 1.);
ag->addAction(qaction);
}
buttonMenu->addSeparator();
}
m_playToolBar->addWidget(toolButton);
toolButton = new QToolButton(m_playToolBar);
toolButton->setPopupMode(QToolButton::MenuButtonPopup);
qaction = new QAction(QIcon(":/Trackview/play/tvplay-02.png"), "Stop", this);
qaction->setData(ID_TV_STOP);
m_actions[ID_TV_STOP] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnStop);
toolButton->setDefaultAction(qaction);
{
QMenu* buttonMenu = new QMenu(this);
toolButton->setMenu(buttonMenu);
qaction = buttonMenu->addAction("Stop");
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnStop);
toolButton->addAction(qaction);
qaction = buttonMenu->addAction("Stop with Hard Reset");
qaction->setData(true);
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnStopHardReset);
}
m_playToolBar->addWidget(toolButton);
m_playToolBar->addSeparator();
qaction = m_playToolBar->addAction(QIcon(":/Trackview/play/tvplay-03.png"), "Pause");
qaction->setData(ID_TV_PAUSE);
qaction->setCheckable(true);
m_actions[ID_TV_PAUSE] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnPause);
qaction = m_playToolBar->addAction(QIcon(":/Trackview/play/tvplay-04.png"), "Go to end of sequence");
qaction->setData(ID_TV_JUMPEND);
m_actions[ID_TV_JUMPEND] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnGoToEnd);
qaction = m_playToolBar->addAction(QIcon(":/Trackview/play/tvplay-05.png"), "Start Animation Recording");
qaction->setData(ID_TV_RECORD);
qaction->setCheckable(true);
m_actions[ID_TV_RECORD] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnRecord);
m_playToolBar->addSeparator();
qaction = m_playToolBar->addAction(QIcon(":/Trackview/play/tvplay-07.png"), "Loop");
qaction->setData(ID_PLAY_LOOP);
qaction->setCheckable(true);
m_actions[ID_PLAY_LOOP] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnLoop);
m_playToolBar->addSeparator();
m_cursorPos = new QLabel(this);
m_playToolBar->addWidget(m_cursorPos);
m_playToolBar->addSeparator();
qaction = m_playToolBar->addAction(QIcon(":/Trackview/play/tvplay-09.png"), "Undo");
qaction->setData(ID_UNDO);
m_actions[ID_UNDO] = qaction;
connect(qaction, &QAction::triggered, this, []()
{
UiAnimUndoManager::Get()->Undo();
});
qaction = m_playToolBar->addAction(QIcon(":/Trackview/play/tvplay-10.png"), "Redo");
qaction->setData(ID_REDO);
m_actions[ID_REDO] = qaction;
connect(qaction, &QAction::triggered, this, []()
{
UiAnimUndoManager::Get()->Redo();
});
addToolBarBreak(Qt::TopToolBarArea);
if (QToolButton* expansion = AzQtComponents::ToolBar::getToolBarExpansionButton(m_playToolBar))
{
expansion->installEventFilter(m_expanderWatcher);
}
m_keysToolBar = addToolBar("Keys Toolbar");
m_keysToolBar->setObjectName("m_keysToolBar");
m_keysToolBar->setFloatable(false);
m_keysToolBar->addWidget(new QLabel("Keys:"));
qaction = m_keysToolBar->addAction(QIcon(":/Trackview/keys/tvkeys-00.png"), "Go to previous key");
qaction->setData(ID_TV_PREVKEY);
m_actions[ID_TV_PREVKEY] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnGoToPrevKey);
qaction = m_keysToolBar->addAction(QIcon(":/Trackview/keys/tvkeys-01.png"), "Go to next key");
qaction->setData(ID_TV_NEXTKEY);
m_actions[ID_TV_NEXTKEY] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnGoToNextKey);
m_keysToolBar->addSeparator();
qaction = m_keysToolBar->addAction(QIcon(":/Trackview/keys/tvkeys-02.png"), "Move Keys");
qaction->setData(ID_TV_MOVEKEY);
m_actions[ID_TV_MOVEKEY] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnMoveKey);
qaction = m_keysToolBar->addAction(QIcon(":/Trackview/keys/tvkeys-03.png"), "Slide Keys");
qaction->setData(ID_TV_SLIDEKEY);
m_actions[ID_TV_SLIDEKEY] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnSlideKey);
qaction = m_keysToolBar->addAction(QIcon(":/Trackview/keys/tvkeys-04.png"), "Scale Keys");
qaction->setData(ID_TV_SCALEKEY);
m_actions[ID_TV_SCALEKEY] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnScaleKey);
qaction = m_keysToolBar->addAction(QIcon(":/Trackview/keys/tvkeys-05.png"), "Add Keys");
qaction->setData(ID_TV_ADDKEY);
m_actions[ID_TV_ADDKEY] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnAddKey);
qaction = m_keysToolBar->addAction(QIcon(":/Trackview/keys/tvkeys-06.png"), "Delete Keys");
qaction->setData(ID_TV_DELKEY);
m_actions[ID_TV_DELKEY] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnDelKey);
m_keysToolBar->addSeparator();
qaction = m_keysToolBar->addAction(QIcon(":/Trackview/keys/tvkeys-07.png"), "No Snapping");
qaction->setData(ID_TV_SNAP_NONE);
m_actions[ID_TV_SNAP_NONE] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnSnapNone);
qaction = m_keysToolBar->addAction(QIcon(":/Trackview/keys/tvkeys-08.png"), "Magnet Snapping");
qaction->setData(ID_TV_SNAP_MAGNET);
m_actions[ID_TV_SNAP_MAGNET] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnSnapMagnet);
qaction = m_keysToolBar->addAction(QIcon(":/Trackview/keys/tvkeys-09.png"), "Frame Snapping");
qaction->setData(ID_TV_SNAP_FRAME);
m_actions[ID_TV_SNAP_FRAME] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnSnapFrame);
qaction = m_keysToolBar->addAction(QIcon(":/Trackview/keys/tvkeys-10.png"), "Tick Snapping");
qaction->setData(ID_TV_SNAP_TICK);
m_actions[ID_TV_SNAP_TICK] = qaction;
connect(qaction, &QAction::triggered, this, &CUiAnimViewDialog::OnSnapTick);
if (QToolButton* expansion = AzQtComponents::ToolBar::getToolBarExpansionButton(m_keysToolBar))
{
expansion->installEventFilter(m_expanderWatcher);
}
QActionGroup* ag = new QActionGroup(this);
ag->addAction(m_actions[ID_TV_ADDKEY]);
ag->addAction(m_actions[ID_TV_MOVEKEY]);
ag->addAction(m_actions[ID_TV_SLIDEKEY]);
ag->addAction(m_actions[ID_TV_SCALEKEY]);
foreach(QAction* qaction2, ag->actions())
{
qaction2->setCheckable(true);
}
m_actions[ID_TV_MOVEKEY]->setChecked(true);
ag = new QActionGroup(this);
ag->addAction(m_actions[ID_TV_SNAP_NONE]);
ag->addAction(m_actions[ID_TV_SNAP_MAGNET]);
ag->addAction(m_actions[ID_TV_SNAP_FRAME]);
ag->addAction(m_actions[ID_TV_SNAP_TICK]);
foreach(QAction* qaction2, ag->actions())
{
qaction2->setCheckable(true);
}
m_actions[ID_TV_SNAP_NONE]->setChecked(true);
m_bRecord = false;
m_bPause = false;
m_bPlay = false;
}
void CUiAnimViewDialog::InitMenu()
{
QMenuBar* mb = this->menuBar();
QMenu* m = mb->addMenu("&Sequence");
QAction* a = m->addAction("New Sequence...");
a->setData(ID_TV_SEQUENCE_NEW);
m_actions[ID_TV_SEQUENCE_NEW] = a;
connect(a, &QAction::triggered, this, &CUiAnimViewDialog::OnAddSequence);
m = mb->addMenu("&View");
m->addAction(m_actions[ID_TV_MODE_DOPESHEET]);
m->addAction(m_actions[ID_TV_MODE_CURVEEDITOR]);
m->addAction(m_actions[ID_TV_MODE_OPENCURVEEDITOR]);
m->addSeparator();
a = m->addAction("Tick in Seconds");
a->setData(ID_VIEW_TICKINSECONDS);
a->setCheckable(true);
m_actions[ID_VIEW_TICKINSECONDS] = a;
connect(a, &QAction::triggered, this, &CUiAnimViewDialog::OnViewTickInSeconds);
a = m->addAction("Tick in Frames");
a->setData(ID_VIEW_TICKINFRAMES);
a->setCheckable(true);
m_actions[ID_VIEW_TICKINFRAMES] = a;
connect(a, &QAction::triggered, this, &CUiAnimViewDialog::OnViewTickInFrames);
#if UI_ANIMATION_REMOVED
// This dialog makes no sense while we only support component property tracks
// if we add support for event tracks it might make sense
// Currently we do not save the customized track colors
m = mb->addMenu("T&ools");
a = m->addAction("Customize &Track Colors...");
a->setData(ID_TV_TOOLS_CUSTOMIZETRACKCOLORS);
m_actions[ID_TV_TOOLS_CUSTOMIZETRACKCOLORS] = a;
connect(a, &QAction::triggered, this, &CUiAnimViewDialog::OnCustomizeTrackColors);
#endif
}
void CUiAnimViewDialog::UpdateActions()
{
if (m_actions.empty())
{
return;
}
if (m_animationContext->IsRecordMode())
{
m_actions[ID_TV_RECORD]->setChecked(true);
}
else
{
m_actions[ID_TV_RECORD]->setChecked(false);
}
if (m_animationContext->IsPlayMode())
{
m_actions[ID_TV_PLAY]->setChecked(true);
}
else
{
m_actions[ID_TV_PLAY]->setChecked(false);
}
if (m_animationContext->IsPaused())
{
m_actions[ID_TV_PAUSE]->setChecked(true);
}
else
{
m_actions[ID_TV_PAUSE]->setChecked(false);
}
if (m_animationContext->IsLoopMode())
{
m_actions[ID_PLAY_LOOP]->setChecked(true);
}
else
{
m_actions[ID_PLAY_LOOP]->setChecked(false);
}
if (m_wndDopeSheet->GetTickDisplayMode() == eUiAVTickMode_InSeconds)
{
m_actions[ID_VIEW_TICKINSECONDS]->setChecked(true);
}
else
{
m_actions[ID_VIEW_TICKINSECONDS]->setChecked(false);
}
if (m_wndDopeSheet->GetTickDisplayMode() == eUiAVTickMode_InFrames)
{
m_actions[ID_VIEW_TICKINFRAMES]->setChecked(true);
}
else
{
m_actions[ID_VIEW_TICKINFRAMES]->setChecked(false);
}
m_actions[ID_TV_DEL_SEQUENCE]->setEnabled(m_bEditLock ? false : true);
CUiAnimViewSequence* pSequence = m_animationContext->GetSequence();
if (pSequence)
{
bool bLightAnimationSetActive = (m_currentSequenceName == LIGHT_ANIMATION_SET_NAME)
&& (pSequence->GetFlags() & IUiAnimSequence::eSeqFlags_LightAnimationSet);
if (m_bEditLock || bLightAnimationSetActive)
{
m_actions[ID_TV_EDIT_SEQUENCE]->setEnabled(false);
}
else
{
m_actions[ID_TV_EDIT_SEQUENCE]->setEnabled(true);
}
CUiAnimViewAnimNodeBundle selectedNodes = pSequence->GetSelectedAnimNodes();
CUiAnimViewTrackBundle selectedTracks = pSequence->GetSelectedTracks();
const unsigned int selectedNodeCount = selectedNodes.GetCount();
const unsigned int selectedTrackCount = selectedTracks.GetCount();
bool updated_ID_TRACKVIEW_TOGGLE_DISABLE = false;
if (selectedNodeCount + selectedTrackCount == 1)
{
if (selectedNodeCount == 1)
{
CUiAnimViewAnimNode* pAnimNode = selectedNodes.GetNode(0);
m_actions[ID_TRACKVIEW_TOGGLE_DISABLE]->setEnabled(true);
m_actions[ID_TRACKVIEW_TOGGLE_DISABLE]->setChecked(pAnimNode->IsDisabled() ? true : false);
updated_ID_TRACKVIEW_TOGGLE_DISABLE = true;
}
if (selectedTrackCount == 1)
{
CUiAnimViewTrack* pTrack = selectedTracks.GetTrack(0);
m_actions[ID_TRACKVIEW_TOGGLE_DISABLE]->setEnabled(true);
m_actions[ID_TRACKVIEW_TOGGLE_DISABLE]->setChecked(pTrack->IsDisabled() ? true : false);
updated_ID_TRACKVIEW_TOGGLE_DISABLE = true;
}
}
if (!updated_ID_TRACKVIEW_TOGGLE_DISABLE)
{
m_actions[ID_TRACKVIEW_TOGGLE_DISABLE]->setEnabled(false);
}
m_actions[ID_ADDNODE]->setEnabled(true);
m_actions[ID_TV_PLAY]->setShortcut(QKeySequence(Qt::Key_Space)); // re-enable the shortcut
}
else
{
m_actions[ID_TV_DEL_SEQUENCE]->setEnabled(false);
m_actions[ID_TV_EDIT_SEQUENCE]->setEnabled(false);
m_actions[ID_TRACKVIEW_TOGGLE_DISABLE]->setEnabled(false);
m_actions[ID_ADDNODE]->setEnabled(false);
m_actions[ID_TV_PLAY]->setShortcut(QKeySequence()); // clear the shortcut to give parent widgets a chance to handle the same shortcut
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::InitSequences()
{
ReloadSequences();
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::InvalidateSequence()
{
m_bNeedReloadSequence = true;
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::InvalidateDopeSheet()
{
if (m_wndDopeSheet)
{
m_wndDopeSheet->update();
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::Update()
{
if (m_bNeedReloadSequence)
{
m_bNeedReloadSequence = false;
const CUiAnimViewSequenceManager* pSequenceManager = CUiAnimViewSequenceManager::GetSequenceManager();
CUiAnimViewSequence* pSequence = pSequenceManager->GetSequenceByName(m_currentSequenceName);
CUiAnimationContext* pAnimationContext = m_animationContext;
pAnimationContext->SetSequence(pSequence, true, false);
}
CUiAnimationContext* pAnimationContext = m_animationContext;
float fTime = pAnimationContext->GetTime();
if (fTime != m_fLastTime)
{
m_fLastTime = fTime;
SetCursorPosText(fTime);
}
// UI_ANIMATION_REVISIT, render here rather than using pViewport->AddPostRenderer in the animation context
// there may be a better way to do this
m_animationContext->OnPostRender();
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnGoToPrevKey()
{
CUiAnimationContext* pAnimationContext = m_animationContext;
CUiAnimViewSequence* pSequence = pAnimationContext->GetSequence();
if (pSequence)
{
float time = pAnimationContext->GetTime();
CUiAnimViewNode* pNode = pSequence->GetFirstSelectedNode();
pNode = pNode ? pNode : pSequence;
if (pNode->SnapTimeToPrevKey(time))
{
pAnimationContext->SetTime(time);
}
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnGoToNextKey()
{
CUiAnimationContext* pAnimationContext = m_animationContext;
CUiAnimViewSequence* pSequence = pAnimationContext->GetSequence();
if (pSequence)
{
float time = pAnimationContext->GetTime();
CUiAnimViewNode* pNode = pSequence->GetFirstSelectedNode();
pNode = pNode ? pNode : pSequence;
if (pNode->SnapTimeToNextKey(time))
{
pAnimationContext->SetTime(time);
}
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnAddKey()
{
m_wndDopeSheet->SetMouseActionMode(eUiAVActionMode_AddKeys);
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnDelKey()
{
CUiAnimationContext* pAnimationContext = m_animationContext;
CUiAnimViewSequence* pSequence = pAnimationContext->GetSequence();
if (pSequence)
{
UiAnimUndo undo("Delete Keys");
pSequence->DeleteSelectedKeys();
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnMoveKey()
{
m_wndDopeSheet->SetMouseActionMode(eUiAVActionMode_MoveKey);
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnSlideKey()
{
m_wndDopeSheet->SetMouseActionMode(eUiAVActionMode_SlideKey);
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnScaleKey()
{
m_wndDopeSheet->SetMouseActionMode(eUiAVActionMode_ScaleKey);
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnSyncSelectedTracksToBase()
{
CUiAnimViewSequence* pSequence = m_animationContext->GetSequence();
if (pSequence)
{
pSequence->SyncSelectedTracksToBase();
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnSyncSelectedTracksFromBase()
{
CUiAnimViewSequence* pSequence = m_animationContext->GetSequence();
if (pSequence)
{
pSequence->SyncSelectedTracksFromBase();
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnAddSequence()
{
if (!m_animationSystem)
{
// No UI canvas is loaded/active so can't do anything
return;
}
CUiAVNewSequenceDialog dlg(this);
if (dlg.exec() == QDialog::Accepted)
{
QString sequenceName = dlg.GetSequenceName();
if (sequenceName != s_kNoSequenceComboBoxEntry)
{
UiAnimUndo undoAddSequence("Add Sequence");
CUiAnimViewSequenceManager* pSequenceManager = CUiAnimViewSequenceManager::GetSequenceManager();
{
CUiAnimViewSequence* pSequence = pSequenceManager->GetSequenceByName(sequenceName);
if (pSequence)
{
AZ_Error("UiAnimViewDialog", false, "A sequence with this name already exists");
return;
}
UiAnimUndo undo("Create UiAnimView sequence");
pSequenceManager->CreateSequence(sequenceName);
}
CUiAnimViewSequence* pNewSequence = pSequenceManager->GetSequenceByName(sequenceName);
CUiAnimationContext* pAnimationContext = m_animationContext;
pAnimationContext->SetSequence(pNewSequence, true, false, true);
}
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::ReloadSequences()
{
if (!m_animationSystem || m_bIgnoreUpdates || m_bDoingUndoOperation)
{
return;
}
CUiAnimationContext* pAnimationContext = m_animationContext;
CUiAnimViewSequence* pSequence = pAnimationContext->GetSequence();
CUiAnimViewSequenceNoNotificationContext context(pSequence);
if (pSequence)
{
pSequence->UnBindFromEditorObjects();
}
if (pAnimationContext->IsPlaying())
{
pAnimationContext->SetPlaying(false);
}
ReloadSequencesComboBox();
SaveZoomScrollSettings();
if (!m_currentSequenceName.isEmpty())
{
CUiAnimViewSequenceManager* pSequenceManager = CUiAnimViewSequenceManager::GetSequenceManager();
pSequence = pSequenceManager->GetSequenceByName(m_currentSequenceName);
const float prevTime = pAnimationContext->GetTime();
pAnimationContext->SetSequence(pSequence, true, true);
pAnimationContext->SetTime(prevTime);
}
else
{
pAnimationContext->SetSequence(nullptr, true, false);
m_sequencesComboBox->setCurrentIndex(0);
}
if (pSequence)
{
pSequence->BindToEditorObjects();
}
pAnimationContext->ForceAnimation();
UpdateSequenceLockStatus();
UpdateActions();
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::ReloadSequencesComboBox()
{
m_sequencesComboBox->blockSignals(true);
m_sequencesComboBox->clear();
m_sequencesComboBox->addItem(QString(s_kNoSequenceComboBoxEntry));
{
CUiAnimViewSequenceManager* pSequenceManager = CUiAnimViewSequenceManager::GetSequenceManager();
const unsigned int numSequences = pSequenceManager->GetCount();
for (unsigned int k = 0; k < numSequences; ++k)
{
CUiAnimViewSequence* pSequence = pSequenceManager->GetSequenceByIndex(k);
QString fullname = QString::fromUtf8(pSequence->GetName().c_str());
m_sequencesComboBox->addItem(fullname);
}
}
if (m_currentSequenceName.isEmpty())
{
m_sequencesComboBox->setCurrentIndex(0);
}
else
{
m_sequencesComboBox->setCurrentIndex(m_sequencesComboBox->findText(m_currentSequenceName));
}
m_sequencesComboBox->blockSignals(false);
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::UpdateSequenceLockStatus()
{
if (m_bIgnoreUpdates)
{
return;
}
CUiAnimViewSequence* pSequence = m_animationContext->GetSequence();
if (!pSequence)
{
SetEditLock(true);
}
else
{
SetEditLock(false);
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::SetEditLock(bool bLock)
{
m_bEditLock = bLock;
m_wndDopeSheet->SetEditLock(bLock);
m_wndNodesCtrl->SetEditLock(bLock);
m_wndNodesCtrl->update();
m_wndCurveEditor->SetEditLock(bLock);
m_wndCurveEditor->update();
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnDelSequence()
{
if (m_sequencesComboBox->currentIndex() <= 0)
{
return;
}
if (QMessageBox::question(this, "UI Animation", "Delete current sequence?") == QMessageBox::Yes)
{
int sel = m_sequencesComboBox->currentIndex();
QString seq = m_sequencesComboBox->currentText();
m_sequencesComboBox->removeItem(sel);
m_sequencesComboBox->setCurrentIndex(0);
OnSequenceComboBox();
{
CUiAnimViewSequenceManager* pSequenceManager = CUiAnimViewSequenceManager::GetSequenceManager();
CUiAnimViewSequence* pSequence = pSequenceManager->GetSequenceByName(seq);
if (pSequence)
{
pSequenceManager->DeleteSequence(pSequence);
return;
}
AZ_Error("UiAnimViewDialog", false, "Could not find sequence");
return;
}
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnEditSequence()
{
CUiAnimViewSequence* pSequence = m_animationContext->GetSequence();
if (pSequence)
{
float fps = m_wndCurveEditor->GetFPS();
CUiAVSequenceProps dlg(pSequence, fps, this);
if (dlg.exec() == QDialog::Accepted)
{
// Sequence updated.
ReloadSequences();
}
m_wndDopeSheet->update();
UpdateActions();
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnSequenceComboBox()
{
int sel = m_sequencesComboBox->currentIndex();
if (sel == -1)
{
m_animationContext->SetSequence(nullptr, false, false, true);
return;
}
QString name = m_sequencesComboBox->currentText();
// Display current sequence.
CUiAnimViewSequenceManager* pSequenceManager = CUiAnimViewSequenceManager::GetSequenceManager();
CUiAnimViewSequence* pSequence = pSequenceManager->GetSequenceByName(name);
CUiAnimationContext* pAnimationContext = m_animationContext;
pAnimationContext->SetSequence(pSequence, false, false, true);
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnSequenceChanged(CUiAnimViewSequence* pSequence)
{
if (m_bIgnoreUpdates)
{
return;
}
// Remove listeners from previous sequence
CUiAnimViewSequenceManager* pSequenceManager = CUiAnimViewSequenceManager::GetSequenceManager();
CUiAnimViewSequence* pPrevSequence = pSequenceManager->GetSequenceByName(m_currentSequenceName);
if (pPrevSequence)
{
pPrevSequence->RemoveListener(this);
pPrevSequence->RemoveListener(m_wndNodesCtrl);
pPrevSequence->RemoveListener(m_wndKeyProperties);
pPrevSequence->RemoveListener(m_wndCurveEditor);
pPrevSequence->RemoveListener(m_wndDopeSheet);
}
if (pSequence)
{
m_currentSequenceName = QString::fromUtf8(pSequence->GetName().c_str());
pSequence->Reset(true);
SaveZoomScrollSettings();
UpdateDopeSheetTime(pSequence);
m_sequencesComboBox->blockSignals(true);
m_sequencesComboBox->setCurrentText(m_currentSequenceName);
m_sequencesComboBox->blockSignals(false);
pSequence->ClearSelection();
pSequence->AddListener(this);
pSequence->AddListener(m_wndNodesCtrl);
pSequence->AddListener(m_wndKeyProperties);
pSequence->AddListener(m_wndCurveEditor);
pSequence->AddListener(m_wndDopeSheet);
}
else
{
m_currentSequenceName = "";
m_sequencesComboBox->setCurrentIndex(0);
m_wndCurveEditor->GetSplineCtrl().SetEditLock(true);
}
m_wndNodesCtrl->OnSequenceChanged();
m_wndKeyProperties->OnSequenceChanged(pSequence);
m_animationContext->ForceAnimation();
m_wndNodesCtrl->update();
m_wndDopeSheet->update();
UpdateSequenceLockStatus();
UpdateActions();
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnRecord()
{
CUiAnimationContext* pAnimationContext = m_animationContext;
pAnimationContext->SetRecording(!pAnimationContext->IsRecording());
m_wndDopeSheet->update();
UpdateActions();
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnGoToStart()
{
CUiAnimationContext* pAnimationContext = m_animationContext;
pAnimationContext->SetTime(pAnimationContext->GetMarkers().start);
pAnimationContext->SetPlaying(false);
pAnimationContext->SetRecording(false);
CUiAnimViewSequence* pSequence = pAnimationContext->GetSequence();
if (pSequence)
{
// Reset sequence to the beginning.
pSequence->Reset(true);
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnGoToEnd()
{
CUiAnimationContext* pAnimationContext = m_animationContext;
pAnimationContext->SetTime(pAnimationContext->GetMarkers().end);
pAnimationContext->SetPlaying(false);
pAnimationContext->SetRecording(false);
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnPlay()
{
CUiAnimationContext* pAnimationContext = m_animationContext;
if (!pAnimationContext->IsPlaying())
{
CUiAnimViewSequence* pSequence = pAnimationContext->GetSequence();
if (pSequence)
{
{
CUiAnimationContext* pAnimationContext2 = nullptr;
EBUS_EVENT_RESULT(pAnimationContext2, UiEditorAnimationBus, GetAnimationContext);
if (pAnimationContext2->IsPlaying())
{
AZ_Error("UiAnimViewDialog", false, "A sequence is already playing");
return;
}
pAnimationContext2->SetPlaying(true);
}
}
}
else
{
{
CUiAnimationContext* pAnimationContext2 = nullptr;
EBUS_EVENT_RESULT(pAnimationContext2, UiEditorAnimationBus, GetAnimationContext);
if (!pAnimationContext2->IsPlaying())
{
AZ_Error("UiAnimViewDialog", false, "A sequence is playing");
return;
}
pAnimationContext2->SetPlaying(false);
}
}
}
void CUiAnimViewDialog::OnPlaySetScale()
{
QAction* action = static_cast<QAction*>(sender());
float v = action->data().toFloat();
if (v > 0.f)
{
m_animationContext->SetTimeScale(1.f / v);
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnStop()
{
CUiAnimationContext* pAnimationContext = m_animationContext;
if (pAnimationContext->IsPlaying())
{
pAnimationContext->SetPlaying(false);
}
else
{
OnGoToStart();
}
pAnimationContext->SetRecording(false);
UpdateActions();
}
void CUiAnimViewDialog::OnStopHardReset()
{
CUiAnimationContext* pAnimationContext = m_animationContext;
pAnimationContext->SetTime(pAnimationContext->GetMarkers().start);
pAnimationContext->SetPlaying(false);
pAnimationContext->SetRecording(false);
CUiAnimViewSequence* pSequence = m_animationContext->GetSequence();
if (pSequence)
{
pSequence->ResetHard();
}
UpdateActions();
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnPause()
{
CUiAnimationContext* pAnimationContext = m_animationContext;
if (pAnimationContext->IsPaused())
{
pAnimationContext->Resume();
}
else
{
pAnimationContext->Pause();
}
UpdateActions();
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnLoop()
{
CUiAnimationContext* pAnimationContext = m_animationContext;
pAnimationContext->SetLoopMode(!pAnimationContext->IsLoopMode());
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnEditorNotifyEvent(EEditorNotifyEvent event)
{
switch (event)
{
case eNotify_OnBeginNewScene:
case eNotify_OnBeginLoad:
case eNotify_OnBeginSceneSave:
case eNotify_OnBeginGameMode:
m_bIgnoreUpdates = true;
break;
case eNotify_OnEndNewScene:
case eNotify_OnEndLoad:
m_bIgnoreUpdates = false;
ReloadSequences();
break;
case eNotify_OnEndSceneSave:
case eNotify_OnEndGameMode:
m_bIgnoreUpdates = false;
break;
case eNotify_OnIdleUpdate:
if (!m_bIgnoreUpdates)
{
Update();
}
break;
case eNotify_OnQuit:
SaveLayouts();
SaveMiscSettings();
SaveTrackColors();
break;
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnAddSelectedNode()
{
CUiAnimViewSequence* pSequence = m_animationContext->GetSequence();
if (pSequence)
{
UiAnimUndo undo("Add Elements to Animation");
pSequence->AddSelectedUiElements();
UpdateActions();
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnAddDirectorNode()
{
CUiAnimViewSequence* pSequence = m_animationContext->GetSequence();
if (pSequence)
{
UiAnimUndo undo("Create Animation Director Node");
QString name = pSequence->GetAvailableNodeNameStartingWith("Director");
pSequence->CreateSubNode(name, eUiAnimNodeType_Director);
UpdateActions();
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnFindNode()
{
if (!m_findDlg)
{
m_findDlg = new CUiAnimViewFindDlg("Find Node in UI Canvas Sequences", this);
m_findDlg->Init(this);
connect(m_findDlg, SIGNAL(finished(int)), m_wndNodesCtrl->findChild<QTreeView*>(), SLOT(setFocus()), Qt::QueuedConnection);
}
m_findDlg->FillData();
m_findDlg->show();
m_findDlg->raise();
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::keyPressEvent(QKeyEvent* event)
{
if (event->key() == Qt::Key_Space && event->modifiers() == Qt::NoModifier)
{
event->accept();
m_animationContext->TogglePlay();
}
return QMainWindow::keyPressEvent(event);
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnModeDopeSheet()
{
auto sizes = m_wndSplitter->sizes();
m_wndCurveEditorDock->setVisible(false);
m_wndCurveEditorDock->toggleViewAction()->setEnabled(false);
if (m_wndCurveEditorDock->widget() != m_wndCurveEditor)
{
m_wndCurveEditorDock->setWidget(m_wndCurveEditor);
}
m_wndDopeSheet->show();
m_wndSplitter->setSizes(sizes);
m_actions[ID_TV_MODE_DOPESHEET]->setChecked(true);
m_actions[ID_TV_MODE_CURVEEDITOR]->setChecked(false);
m_wndCurveEditor->OnSequenceChanged(m_animationContext->GetSequence());
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnModeCurveEditor()
{
auto sizes = m_wndSplitter->sizes();
m_wndCurveEditorDock->setVisible(false);
m_wndCurveEditorDock->toggleViewAction()->setEnabled(false);
if (m_wndCurveEditorDock->widget() == m_wndCurveEditor)
{
m_wndSplitter->insertWidget(1, m_wndCurveEditor);
}
m_wndDopeSheet->hide();
m_wndSplitter->setSizes(sizes);
m_actions[ID_TV_MODE_DOPESHEET]->setChecked(false);
m_actions[ID_TV_MODE_CURVEEDITOR]->setChecked(true);
m_wndCurveEditor->OnSequenceChanged(m_animationContext->GetSequence());
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnOpenCurveEditor()
{
OnModeDopeSheet();
m_wndCurveEditorDock->show();
m_wndCurveEditorDock->toggleViewAction()->setEnabled(true);
m_actions[ID_TV_MODE_DOPESHEET]->setChecked(true);
m_actions[ID_TV_MODE_CURVEEDITOR]->setChecked(true);
m_wndCurveEditor->OnSequenceChanged(m_animationContext->GetSequence());
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnSnapNone()
{
m_wndDopeSheet->SetSnappingMode(eSnappingMode_SnapNone);
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnSnapMagnet()
{
m_wndDopeSheet->SetSnappingMode(eSnappingMode_SnapMagnet);
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnSnapFrame()
{
m_wndDopeSheet->SetSnappingMode(eSnappingMode_SnapFrame);
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnSnapTick()
{
m_wndDopeSheet->SetSnappingMode(eSnappingMode_SnapTick);
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnSnapFPS()
{
int fps = FloatToIntRet(m_wndCurveEditor->GetFPS());
bool ok = false;
fps = QInputDialog::getInt(this, tr("Frame rate for frame snapping"), QStringLiteral(""), fps, 1, 120, 1, &ok);
if (ok)
{
m_wndDopeSheet->SetSnapFPS(fps);
m_wndCurveEditor->SetFPS(static_cast<float>(fps));
SetCursorPosText(m_animationContext->GetTime());
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnViewTickInSeconds()
{
m_wndDopeSheet->SetTickDisplayMode(eUiAVTickMode_InSeconds);
m_wndCurveEditor->SetTickDisplayMode(eUiAVTickMode_InSeconds);
SetCursorPosText(m_animationContext->GetTime());
UpdateActions();
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnViewTickInFrames()
{
m_wndDopeSheet->SetTickDisplayMode(eUiAVTickMode_InFrames);
m_wndCurveEditor->SetTickDisplayMode(eUiAVTickMode_InFrames);
SetCursorPosText(m_animationContext->GetTime());
UpdateActions();
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::SaveMiscSettings() const
{
#if UI_ANIMATION_REMOVED // we want to save settings using same system as UI editor
QSettings settings;
for (auto g : QString(s_kUiAnimViewSettingsSection).split('\\'))
{
settings.beginGroup(g);
}
settings.setValue(s_kSnappingModeEntry, (int)m_wndDopeSheet->GetSnappingMode());
settings.setValue(s_kFrameSnappingFPSEntry, m_wndCurveEditor->GetFPS());
settings.setValue(s_kTickDisplayModeEntry, (int)m_wndDopeSheet->GetTickDisplayMode());
#endif
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::ReadMiscSettings()
{
QSettings settings;
for (auto g : QString(s_kUiAnimViewSettingsSection).split('\\'))
{
settings.beginGroup(g);
}
ESnappingMode snapMode = static_cast<ESnappingMode>(settings.value(s_kSnappingModeEntry, eSnappingMode_SnapNone).toInt());
m_wndDopeSheet->SetSnappingMode(snapMode);
if (snapMode == eSnappingMode_SnapNone)
{
m_actions[ID_TV_SNAP_NONE]->setChecked(true);
}
else if (snapMode == eSnappingMode_SnapMagnet)
{
m_actions[ID_TV_SNAP_MAGNET]->setChecked(true);
}
else if (snapMode == eSnappingMode_SnapTick)
{
m_actions[ID_TV_SNAP_TICK]->setChecked(true);
}
else if (snapMode == eSnappingMode_SnapFrame)
{
m_actions[ID_TV_SNAP_FRAME]->setChecked(true);
}
if (settings.contains(s_kFrameSnappingFPSEntry))
{
float fps = settings.value(s_kFrameSnappingFPSEntry).toFloat();
m_wndDopeSheet->SetSnapFPS(FloatToIntRet(fps));
m_wndCurveEditor->SetFPS(fps);
}
EUiAVTickMode tickMode = static_cast<EUiAVTickMode>(settings.value(s_kTickDisplayModeEntry, eUiAVTickMode_InSeconds).toInt());
m_wndDopeSheet->SetTickDisplayMode(tickMode);
m_wndCurveEditor->SetTickDisplayMode(tickMode);
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::SaveLayouts()
{
QSettings settings("O3DE", "O3DE");
settings.beginGroup("UiAnimView");
QByteArray stateData = this->saveState();
settings.setValue("layout", stateData);
QStringList sl;
foreach(int i, m_wndSplitter->sizes())
sl << QString::number(i);
settings.setValue("splitter", sl.join(","));
settings.endGroup();
settings.sync();
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::ReadLayouts()
{
QSettings settings("O3DE", "O3DE");
settings.beginGroup("UiAnimView");
if (settings.contains("layout"))
{
QByteArray layoutData = settings.value("layout").toByteArray();
if (!layoutData.isEmpty())
{
restoreState(layoutData);
}
}
if (settings.contains("splitter"))
{
QStringList sl = settings.value("splitter").toString().split(",");
QList<int> szl;
foreach(QString s, sl)
szl << s.toInt();
if (!sl.isEmpty())
{
m_wndSplitter->setSizes(szl);
}
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::SaveTrackColors() const
{
CUiAVCustomizeTrackColorsDlg::SaveColors(s_kUiAnimViewSettingsSection);
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::ReadTrackColors()
{
CUiAVCustomizeTrackColorsDlg::LoadColors(s_kUiAnimViewSettingsSection);
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::SetCursorPosText(float fTime)
{
QString sText;
int fps = FloatToIntRet(m_wndCurveEditor->GetFPS());
int nMins = int ( fTime / 60.0f );
int nSecs = int (fTime - float ( nMins ) * 60.0f);
int nFrames = int(fTime * m_wndCurveEditor->GetFPS()) % fps;
sText = QString("%1:%2:%3 (%4fps)").arg(nMins).arg(nSecs, 2, 10, QLatin1Char('0')).arg(nFrames, 2, 10, QLatin1Char('0')).arg(fps);
m_cursorPos->setText(sText);
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnCustomizeTrackColors()
{
CUiAVCustomizeTrackColorsDlg dlg(this);
dlg.exec();
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnBatchRender()
{
#if UI_ANIMATION_REMOVED // not supporting batch render
CSequenceBatchRenderDialog dlg(m_wndCurveEditor->GetFPS(), this);
dlg.exec();
#endif
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnToggleDisable()
{
CUiAnimViewSequence* pSequence = m_animationContext->GetSequence();
if (pSequence)
{
CUiAnimViewAnimNodeBundle selectedNodes = pSequence->GetSelectedAnimNodes();
const unsigned int numSelectedNodes = selectedNodes.GetCount();
for (unsigned int i = 0; i < numSelectedNodes; ++i)
{
CUiAnimViewAnimNode* pNode = selectedNodes.GetNode(i);
pNode->SetDisabled(!pNode->IsDisabled());
}
CUiAnimViewTrackBundle selectedTracks = pSequence->GetSelectedTracks();
const unsigned int numSelectedTracks = selectedTracks.GetCount();
for (unsigned int i = 0; i < numSelectedTracks; ++i)
{
CUiAnimViewTrack* pTrack = selectedTracks.GetTrack(i);
pTrack->SetDisabled(!pTrack->IsDisabled());
}
UpdateActions();
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnToggleMute()
{
CUiAnimViewSequence* pSequence = m_animationContext->GetSequence();
if (pSequence)
{
CUiAnimViewTrackBundle selectedTracks = pSequence->GetSelectedTracks();
const unsigned int numSelectedTracks = selectedTracks.GetCount();
for (unsigned int i = 0; i < numSelectedTracks; ++i)
{
CUiAnimViewTrack* pTrack = selectedTracks.GetTrack(i);
pTrack->SetMuted(!pTrack->IsMuted());
}
UpdateActions();
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnMuteAll()
{
CUiAnimViewSequence* pSequence = m_animationContext->GetSequence();
if (pSequence)
{
CUiAnimViewTrackBundle selectedTracks = pSequence->GetSelectedTracks();
const unsigned int numSelectedTracks = selectedTracks.GetCount();
for (unsigned int i = 0; i < numSelectedTracks; ++i)
{
CUiAnimViewTrack* pTrack = selectedTracks.GetTrack(i);
pTrack->SetMuted(true);
}
UpdateActions();
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnUnmuteAll()
{
CUiAnimViewSequence* pSequence = m_animationContext->GetSequence();
if (pSequence)
{
CUiAnimViewTrackBundle selectedTracks = pSequence->GetSelectedTracks();
const unsigned int numSelectedTracks = selectedTracks.GetCount();
for (unsigned int i = 0; i < numSelectedTracks; ++i)
{
CUiAnimViewTrack* pTrack = selectedTracks.GetTrack(i);
pTrack->SetMuted(false);
}
UpdateActions();
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::SaveZoomScrollSettings()
{
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnNodeSelectionChanged(CUiAnimViewSequence* pSequence)
{
CUiAnimViewSequence* pCurrentSequence = m_animationContext->GetSequence();
if (pCurrentSequence && pCurrentSequence == pSequence)
{
UpdateActions();
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnNodeRenamed(CUiAnimViewNode* pNode, const char* pOldName)
{
// React to sequence name changes
if (pNode->GetNodeType() == eUiAVNT_Sequence)
{
if (m_currentSequenceName == QString(pOldName))
{
m_currentSequenceName = QString::fromUtf8(pNode->GetName().c_str());
}
ReloadSequencesComboBox();
}
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::UpdateDopeSheetTime(CUiAnimViewSequence* pSequence)
{
Range timeRange = pSequence->GetTimeRange();
m_wndDopeSheet->SetTimeRange(timeRange.start, timeRange.end);
m_wndDopeSheet->SetStartMarker(timeRange.start);
m_wndDopeSheet->SetEndMarker(timeRange.end);
m_wndDopeSheet->SetTimeScale(m_wndDopeSheet->GetTimeScale(), 0);
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnSequenceSettingsChanged(CUiAnimViewSequence* pSequence)
{
CUiAnimViewSequence* pCurrentSequence = m_animationContext->GetSequence();
if (pCurrentSequence && pCurrentSequence == pSequence)
{
UpdateDopeSheetTime(pSequence);
m_wndNodesCtrl->update();
}
}
//////////////////////////////////////////////////////////////////////////
UiEditorAnimationStateInterface::UiEditorAnimationEditState CUiAnimViewDialog::GetCurrentEditState()
{
UiEditorAnimationStateInterface::UiEditorAnimationEditState animEditState;
animEditState.m_sequenceName = m_animationContext->GetSequence() ? m_animationContext->GetSequence()->GetName() : "";
animEditState.m_time = m_animationContext->GetTime();
animEditState.m_timelineScale = m_wndDopeSheet->GetTimeScale();
animEditState.m_timelineScrollOffset = m_wndDopeSheet->GetScrollOffset();
return animEditState;
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::RestoreCurrentEditState(const UiEditorAnimationStateInterface::UiEditorAnimationEditState& animEditState)
{
CUiAnimViewSequence* pSequence = animEditState.m_sequenceName.empty() ? nullptr : m_sequenceManager->GetSequenceByName(animEditState.m_sequenceName.c_str());
m_animationContext->SetSequence(pSequence, true, false);
m_animationContext->SetTime(animEditState.m_time);
m_wndDopeSheet->SetTimeScale(animEditState.m_timelineScale, 0.0f);
m_wndDopeSheet->SetScrollOffset(animEditState.m_timelineScrollOffset);
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnActiveCanvasChanged()
{
m_animationSystem = CUiAnimViewSequenceManager::GetSequenceManager()->GetAnimationSystem();
setEnabled(m_animationSystem ? true : false);
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnUiElementsDeletedOrReAdded()
{
m_wndNodesCtrl->UpdateAllNodesForElementChanges();
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnSequenceAdded([[maybe_unused]] CUiAnimViewSequence* pSequence)
{
ReloadSequencesComboBox();
UpdateActions();
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::OnSequenceRemoved([[maybe_unused]] CUiAnimViewSequence* pSequence)
{
ReloadSequencesComboBox();
UpdateActions();
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::BeginUndoTransaction()
{
m_bDoingUndoOperation = true;
}
//////////////////////////////////////////////////////////////////////////
void CUiAnimViewDialog::EndUndoTransaction()
{
m_bDoingUndoOperation = false;
}
#include <Animation/moc_UiAnimViewDialog.cpp>