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.
1959 lines
68 KiB
C++
1959 lines
68 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
|
|
#include "StandaloneTools_precompiled.h"
|
|
|
|
#include "DrillerCaptureWindow.hxx"
|
|
#include <Source/Driller/moc_DrillerCaptureWindow.cpp>
|
|
|
|
#include "DrillerMainWindowMessages.h"
|
|
#include "DrillerAggregator.hxx"
|
|
#include "ChannelControl.hxx"
|
|
#include "ChannelProfilerWidget.hxx"
|
|
#include "CombinedEventsControl.hxx"
|
|
#include "DrillerDataContainer.h"
|
|
#include "DrillerMainWindow.hxx"
|
|
#include "DrillerOperationTelemetryEvent.h"
|
|
#include "Workspaces/Workspace.h"
|
|
|
|
#include <AzToolsFramework/UI/LegacyFramework/UIFrameworkAPI.h>
|
|
#include <AzToolsFramework/UI/UICore/ProgressShield.hxx>
|
|
|
|
#include <AzCore/Debug/Trace.h>
|
|
#include <AzCore/std/containers/map.h>
|
|
#include <AzCore/std/delegate/delegate.h>
|
|
#include <AzCore/RTTI/BehaviorContext.h>
|
|
|
|
#include "QtGui/QPalette"
|
|
#include "Annotations/AnnotationHeaderView.hxx"
|
|
#include "Annotations/ConfigureAnnotationsWindow.hxx"
|
|
|
|
#include <AzCore/std/sort.h>
|
|
|
|
#include <Source/Driller/ui_DrillerCaptureWindow.h>
|
|
|
|
#include <QFileDialog>
|
|
#include <QMenu>
|
|
#include <QMessageBox>
|
|
#include <QSignalMapper>
|
|
#include <QStandardPaths>
|
|
#include <QTemporaryFile>
|
|
#include <QTimer>
|
|
#include <QToolTip>
|
|
|
|
void initSharedResources()
|
|
{
|
|
Q_INIT_RESOURCE(sharedResources);
|
|
}
|
|
|
|
namespace
|
|
{
|
|
const char* drillerDebugName = "Driller";
|
|
const char* drillerInfoName = "Driller";
|
|
const char* baseTempFileName = "drillercapture.drl";
|
|
}
|
|
|
|
namespace Driller
|
|
{
|
|
class DrillerCaptureWindowSavedState
|
|
: public AzToolsFramework::MainWindowSavedState
|
|
{
|
|
public:
|
|
AZ_RTTI(DrillerCaptureWindowSavedState, "{19721873-2FB0-4B5B-BCFC-C774FEC7687A}", AzToolsFramework::MainWindowSavedState);
|
|
AZ_CLASS_ALLOCATOR(DrillerCaptureWindowSavedState, AZ::SystemAllocator, 0);
|
|
|
|
AZStd::list<AZ::Uuid> m_ChannelIDs;
|
|
int m_fpsValue;
|
|
FrameNumberType m_scrubberCurrentFrame;
|
|
EventNumberType m_scrubberCurrentEvent;
|
|
FrameNumberType m_playbackLoopBegin;
|
|
FrameNumberType m_playbackLoopEnd;
|
|
AZStd::string m_priorSaveFolder;
|
|
|
|
DrillerCaptureWindowSavedState()
|
|
: m_fpsValue(60)
|
|
, m_scrubberCurrentFrame(0)
|
|
, m_scrubberCurrentEvent(0)
|
|
, m_playbackLoopBegin(0)
|
|
, m_playbackLoopEnd(0)
|
|
{}
|
|
|
|
void Init(const QByteArray& windowState, const QByteArray& windowGeom)
|
|
{
|
|
AzToolsFramework::MainWindowSavedState::Init(windowState, windowGeom);
|
|
}
|
|
|
|
static void Reflect(AZ::ReflectContext* context)
|
|
{
|
|
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
|
if (serialize)
|
|
{
|
|
serialize->Class<DrillerCaptureWindowSavedState, AzToolsFramework::MainWindowSavedState>()
|
|
->Field("m_ChannelIDs", &DrillerCaptureWindowSavedState::m_ChannelIDs)
|
|
->Field("m_fpsValue", &DrillerCaptureWindowSavedState::m_fpsValue)
|
|
->Field("m_scrubberCurrentFrame", &DrillerCaptureWindowSavedState::m_scrubberCurrentFrame)
|
|
->Field("m_scrubberCurrentEvent", &DrillerCaptureWindowSavedState::m_scrubberCurrentEvent)
|
|
->Field("m_playbackLoopBegin", &DrillerCaptureWindowSavedState::m_playbackLoopBegin)
|
|
->Field("m_playbackLoopEnd", &DrillerCaptureWindowSavedState::m_playbackLoopEnd)
|
|
->Field("m_priorSaveFolder", &DrillerCaptureWindowSavedState::m_priorSaveFolder)
|
|
->Version(8);
|
|
}
|
|
}
|
|
};
|
|
|
|
// WORKSPACES are files loaded and stored independent of the global application
|
|
// designed to be used for DRL data specific view settings and to pass around
|
|
class DrillerCaptureWindowWorkspace
|
|
: public AZ::UserSettings
|
|
{
|
|
public:
|
|
AZ_RTTI(DrillerCaptureWindowWorkspace, "{EB67D4B6-41F5-4CED-85F1-E98586036BC6}", AZ::UserSettings);
|
|
AZ_CLASS_ALLOCATOR(DrillerCaptureWindowWorkspace, AZ::SystemAllocator, 0);
|
|
|
|
DrillerCaptureWindowWorkspace() {}
|
|
|
|
AZStd::list<AZ::Uuid> m_ChannelIDs;
|
|
AZStd::string m_matchingDataFileName;
|
|
FrameNumberType m_scrubberCurrentFrame;
|
|
FrameNumberType m_frameRangeBegin;
|
|
FrameNumberType m_frameRangeEnd;
|
|
FrameNumberType m_visibleFrames;
|
|
int m_sliderPosition;
|
|
EventNumberType m_scrubberCurrentEvent;
|
|
|
|
FrameNumberType m_playbackLoopBegin;
|
|
FrameNumberType m_playbackLoopEnd;
|
|
|
|
static void Reflect(AZ::ReflectContext* context)
|
|
{
|
|
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
|
if (serialize)
|
|
{
|
|
serialize->Class<DrillerCaptureWindowWorkspace>()
|
|
->Field("m_ChannelIDs", &DrillerCaptureWindowWorkspace::m_ChannelIDs)
|
|
->Field("m_matchingDataFileName", &DrillerCaptureWindowWorkspace::m_matchingDataFileName)
|
|
->Field("m_scrubberCurrentFrame", &DrillerCaptureWindowWorkspace::m_scrubberCurrentFrame)
|
|
->Field("m_frameRangeBegin", &DrillerCaptureWindowWorkspace::m_frameRangeBegin)
|
|
->Field("m_frameRangeEnd", &DrillerCaptureWindowWorkspace::m_frameRangeEnd)
|
|
->Field("m_visibleFrames", &DrillerCaptureWindowWorkspace::m_visibleFrames)
|
|
->Field("m_playbackLoopBegin", &DrillerCaptureWindowWorkspace::m_playbackLoopBegin)
|
|
->Field("m_playbackLoopEnd", &DrillerCaptureWindowWorkspace::m_playbackLoopEnd)
|
|
->Field("m_sliderPosition", &DrillerCaptureWindowWorkspace::m_sliderPosition)
|
|
->Field("m_scrubberCurrentEvent", &DrillerCaptureWindowWorkspace::m_scrubberCurrentEvent)
|
|
->Version(6);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
namespace Driller
|
|
{
|
|
extern AZ::Uuid ContextID;
|
|
|
|
const int DrillerCaptureWindow::s_availableFrameQuantities[] = { 30, 60, 120, 240, 480, 960, 0 };
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//DrillerCaptureWindow
|
|
DrillerCaptureWindow::DrillerCaptureWindow(CaptureMode captureMode, int identity, QWidget* parent, Qt::WindowFlags flags)
|
|
: QDockWidget(parent, flags)
|
|
, m_captureMode(captureMode)
|
|
, m_identity(identity)
|
|
, m_windowStateCRC(0)
|
|
{
|
|
initSharedResources();
|
|
|
|
AZStd::string windowStateStr = AZStd::string::format("DRILLER CAPTURE WINDOW STATE %i", m_identity);
|
|
m_windowStateCRC = AZ::Crc32(windowStateStr.c_str());
|
|
|
|
m_captureIsDirty = false;
|
|
|
|
m_playbackIsActive = false;
|
|
m_draggingPlaybackLoopBegin = false;
|
|
m_draggingPlaybackLoopEnd = false;
|
|
m_draggingAnything = false;
|
|
m_manipulatingScrollBar = false;
|
|
m_frameRangeEnd = 0;
|
|
m_frameRangeBegin = 0;
|
|
m_ptrConfigureAnnotationsWindow = NULL;
|
|
m_isLoadingFile = false;
|
|
m_TargetConnected = false;
|
|
m_captureIsDirty = false;
|
|
m_bForceNextScrub = true;
|
|
m_captureId = 0;
|
|
|
|
m_gui = azcreate(Ui::DrillerCaptureWindow, ());
|
|
m_gui->setupUi(this);
|
|
|
|
if (IsInCaptureMode(CaptureMode::Inspecting))
|
|
{
|
|
setFeatures(QDockWidget::DockWidgetClosable);
|
|
}
|
|
|
|
m_gui->combinedEventsWidget->SetIdentity(m_identity);
|
|
|
|
// Removing the title bar, since it's meaningless for us.
|
|
setTitleBarWidget(new QWidget());
|
|
|
|
connect(m_gui->playButton, SIGNAL(toggled(bool)), this, SLOT(OnPlayToggled(bool)));
|
|
|
|
if (IsInLiveMode())
|
|
{
|
|
connect(m_gui->captureButton, SIGNAL(toggled(bool)), this, SLOT(OnCaptureToggled(bool)));
|
|
}
|
|
else
|
|
{
|
|
m_gui->captureButton->setDisabled(true);
|
|
}
|
|
|
|
connect(m_gui->frameScrubberBox, SIGNAL(valueChanged(int)), this, SLOT(OnFrameScrubberboxChanged(int)));
|
|
connect(m_gui->controlScrollBar, SIGNAL(sliderPressed()), this, SLOT(OnSliderPressed()));
|
|
connect(m_gui->controlScrollBar, SIGNAL(sliderMoved(int)), this, SLOT(OnNewSliderValue(int)));
|
|
connect(m_gui->controlScrollBar, SIGNAL(valueChanged(int)), this, SLOT(OnNewSliderValue(int)));
|
|
|
|
QMenu* quantMenu = new QMenu(this);
|
|
|
|
QSignalMapper* ptrMapper = new QSignalMapper(this);
|
|
int numQuantsAvailable = sizeof(s_availableFrameQuantities) / sizeof(int);
|
|
for (int idx = 0; idx < numQuantsAvailable; ++idx)
|
|
{
|
|
int thisQuant = s_availableFrameQuantities[idx];
|
|
|
|
QString label = thisQuant ? tr("%1 frames").arg(s_availableFrameQuantities[idx]) : tr("All frames");
|
|
|
|
// connect to mapper:
|
|
QAction* act = new QAction(label, this);
|
|
connect(act, SIGNAL(triggered()), ptrMapper, SLOT(map()));
|
|
ptrMapper->setMapping(act, thisQuant);
|
|
quantMenu->addAction(act);
|
|
}
|
|
connect(ptrMapper, SIGNAL(mapped(int)), this, SLOT(OnQuantMenuFinal(int)));
|
|
|
|
m_gui->quantityButton->setText("120 frames");
|
|
m_gui->quantityButton->setMenu(quantMenu);
|
|
|
|
m_gui->scrollArea->setBackgroundRole(QPalette::Dark);
|
|
DrillerNetworkMessages::Handler::BusConnect(m_identity);
|
|
|
|
m_visibleFrames = 120;
|
|
|
|
QString tmpCapturePath = PrepTempFile(baseTempFileName);
|
|
m_data = aznew DrillerDataContainer(m_identity, tmpCapturePath.toUtf8().data());
|
|
|
|
connect(this, SIGNAL(ScrubberFrameUpdate(FrameNumberType)), m_gui->combinedEventsWidget, SLOT(SetScrubberFrame(FrameNumberType)));
|
|
|
|
m_ptrAnnotationsHeaderView = aznew AnnotationHeaderView(&m_AnnotationProvider, this);
|
|
m_gui->channelLayout->addWidget(m_ptrAnnotationsHeaderView);
|
|
|
|
connect(m_ptrAnnotationsHeaderView, SIGNAL(OnOptionsClick()), this, SLOT(OnAnnotationOptionsClick()));
|
|
connect(m_ptrAnnotationsHeaderView, SIGNAL(InformOfMouseOverAnnotation(const Annotation&)), this, SLOT(InformOfMouseOverAnnotation(const Annotation&)));
|
|
connect(m_ptrAnnotationsHeaderView, SIGNAL(InformOfClickAnnotation(const Annotation&)), this, SLOT(InformOfClickAnnotation(const Annotation&)));
|
|
connect(&m_AnnotationProvider, SIGNAL(SelectedAnnotationsChanged()), this, SLOT(OnSelectedAnnotationChannelsChanged()));
|
|
|
|
// button state maintenance courtesy of the TargetManagerClient bus message(s) we handle
|
|
m_gui->captureButton->setEnabled(false);
|
|
|
|
if (IsInLiveMode())
|
|
{
|
|
AzFramework::TargetManagerClient::Bus::Handler::BusConnect();
|
|
}
|
|
|
|
StateReset();
|
|
|
|
m_gui->combinedEventsWidget->SetAnnotationsProvider(&m_AnnotationProvider);
|
|
|
|
connect(m_gui->combinedEventsWidget->m_annotationHeaderView, SIGNAL(InformOfMouseOverAnnotation(const Annotation&)), this, SLOT(InformOfMouseOverAnnotation(const Annotation&)));
|
|
connect(m_gui->combinedEventsWidget->m_annotationHeaderView, SIGNAL(InformOfClickAnnotation(const Annotation&)), this, SLOT(InformOfClickAnnotation(const Annotation&)));
|
|
connect(this, SIGNAL(ScrubberFrameUpdate(FrameNumberType)), m_gui->combinedEventsWidget->m_annotationHeaderView, SLOT(OnScrubberFrameUpdate(FrameNumberType)));
|
|
connect(m_gui->actionClose, SIGNAL(triggered()), this, SLOT(OnCloseFile()));
|
|
|
|
connect(m_gui->combinedEventsWidget, SIGNAL(EventRequestEventFocus(EventNumberType)), this, SLOT(EventRequestEventFocus(EventNumberType)));
|
|
|
|
UpdateLiveControls();
|
|
emit CaptureWindowSetToLive(IsInLiveMode());
|
|
|
|
RestoreWindowState();
|
|
QTimer::singleShot(0, this, SLOT(OnUpdateScrollSize()));
|
|
|
|
DrillerCaptureWindowRequestBus::Handler::BusConnect(m_identity);
|
|
}
|
|
|
|
DrillerCaptureWindow::~DrillerCaptureWindow(void)
|
|
{
|
|
DrillerCaptureWindowRequestBus::Handler::BusDisconnect(m_identity);
|
|
DrillerNetworkMessages::Handler::BusDisconnect(m_identity);
|
|
AzFramework::TargetManagerClient::Bus::Handler::BusDisconnect();
|
|
|
|
delete m_data;
|
|
azdestroy(m_gui);
|
|
}
|
|
|
|
bool DrillerCaptureWindow::event(QEvent* evt)
|
|
{
|
|
if (evt->type() == QEvent::WindowActivate)
|
|
{
|
|
emit CaptureWindowSetToLive(static_cast<bool>(IsInLiveMode()));
|
|
}
|
|
|
|
// parent class
|
|
return QDockWidget::event(evt);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// internal workings
|
|
void DrillerCaptureWindow::StateReset()
|
|
{
|
|
if (m_visibleFrames == m_frameRangeEnd - m_frameRangeBegin + 1)
|
|
{
|
|
// full range was visible.
|
|
OnQuantMenuFinal(120);
|
|
}
|
|
|
|
OnPlayToggled(false);
|
|
SetPlaybackLoopBegin(0);
|
|
SetPlaybackLoopEnd(0);
|
|
SetFrameRangeBegin(0);
|
|
SetFrameRangeEnd(0);
|
|
SetScrubberFrame(0);
|
|
m_bForceNextScrub = true;
|
|
|
|
for (auto iter = m_channels.begin(); iter != m_channels.end(); ++iter)
|
|
{
|
|
(*iter)->SetEndFrame(0);
|
|
}
|
|
|
|
m_ptrAnnotationsHeaderView->SetEndFrame(0);
|
|
}
|
|
|
|
void DrillerCaptureWindow::UpdateLiveControls()
|
|
{
|
|
bool isViewingStoredData = IsInCaptureMode(CaptureMode::Inspecting);
|
|
|
|
// these overlapping frames must be both hidden and then one made visible
|
|
// otherwise the containing window is forced wide enough to support both
|
|
// which overrides previous sizes and leaves a ton of dead space behind
|
|
m_gui->targetFrame->setVisible(!isViewingStoredData);
|
|
|
|
m_gui->playButton->setVisible(isViewingStoredData);
|
|
m_gui->frameFPS->setVisible(isViewingStoredData);
|
|
m_gui->frameScrubberBox->setEnabled(isViewingStoredData);
|
|
|
|
// For now, we're not sure if we want to keep this, or expand on it
|
|
// going ahead. So for now we'll just hide it.
|
|
m_gui->combinedEventsWidget->setVisible(false);
|
|
|
|
if (IsInCaptureMode(CaptureMode::Configuration))
|
|
{
|
|
m_gui->frame->setVisible(false);
|
|
m_gui->quantityButton->setVisible(false);
|
|
}
|
|
else
|
|
{
|
|
m_gui->frame->setVisible(true);
|
|
m_gui->quantityButton->setVisible(true);
|
|
}
|
|
|
|
emit CaptureWindowSetToLive(!isViewingStoredData);
|
|
}
|
|
|
|
void DrillerCaptureWindow::SetCaptureMode(CaptureMode captureMode)
|
|
{
|
|
if (m_captureMode != captureMode)
|
|
{
|
|
m_captureMode = captureMode;
|
|
emit OnCaptureModeChange(m_captureMode);
|
|
}
|
|
}
|
|
|
|
void DrillerCaptureWindow::ResetCaptureControls()
|
|
{
|
|
// Reset the state of the UI Controls
|
|
m_currentDataFilename = "";
|
|
SetCaptureMode(CaptureMode::Configuration);
|
|
OnCloseFile();
|
|
m_data->CloseCaptureData();
|
|
m_data->CreateAggregators();
|
|
UpdateLiveControls();
|
|
}
|
|
|
|
bool DrillerCaptureWindow::IsInLiveMode() const
|
|
{
|
|
return IsInCaptureMode(CaptureMode::Capturing) || IsInCaptureMode(CaptureMode::Configuration);
|
|
}
|
|
|
|
bool DrillerCaptureWindow::IsInCaptureMode(CaptureMode captureMode) const
|
|
{
|
|
return m_captureMode == captureMode;
|
|
}
|
|
|
|
void DrillerCaptureWindow::ClearExistingChannels()
|
|
{
|
|
ClearChannelDisplay(true);
|
|
}
|
|
|
|
void DrillerCaptureWindow::ClearChannelDisplay(bool withDeletion)
|
|
{
|
|
if (withDeletion)
|
|
{
|
|
m_gui->combinedEventsWidget->ClearAggregatorList();
|
|
|
|
for (auto iter = m_channels.begin(); iter != m_channels.end(); ++iter)
|
|
{
|
|
m_gui->channelLayout->removeWidget(*iter);
|
|
delete *iter;
|
|
}
|
|
m_channels.clear();
|
|
}
|
|
else
|
|
{
|
|
for (auto iter = m_channels.begin(); iter != m_channels.end(); ++iter)
|
|
{
|
|
m_gui->channelLayout->removeWidget(*iter);
|
|
}
|
|
}
|
|
|
|
// layouts take one message process to update their sizes, we need to queue a refresh of our scroll area at the end of the event queue
|
|
// so that the sizeHint() will be correct.
|
|
QTimer::singleShot(0, this, SLOT(OnUpdateScrollSize()));
|
|
}
|
|
|
|
void DrillerCaptureWindow::SortChannels()
|
|
{
|
|
SortedChannels temp;
|
|
|
|
// two passes, first pushes active channels and second pushes the remaining inactive channels
|
|
// this maintains the relative order of the list within categories to avoid surprises
|
|
for (ChannelControl* channelControl : m_channels)
|
|
{
|
|
if (channelControl->IsActive())
|
|
{
|
|
temp.push_back(channelControl);
|
|
}
|
|
}
|
|
|
|
for (ChannelControl* channelControl : m_channels)
|
|
{
|
|
if (!channelControl->IsActive())
|
|
{
|
|
channelControl->OnContractedToggled(false);
|
|
temp.push_back(channelControl);
|
|
}
|
|
}
|
|
|
|
m_channels.clear();
|
|
m_channels = temp;
|
|
temp.clear();
|
|
}
|
|
|
|
void DrillerCaptureWindow::PopulateChannelDisplay()
|
|
{
|
|
for (auto iter = m_channels.begin(); iter != m_channels.end(); ++iter)
|
|
{
|
|
m_gui->channelLayout->addWidget(*iter);
|
|
(*iter)->SetDataPointsInView(m_visibleFrames);
|
|
}
|
|
// layouts take one message process to update their sizes, we need to queue a refresh of our scroll area at the end of the event queue
|
|
// so that the sizeHint() will be correct.
|
|
QTimer::singleShot(0, this, SLOT(OnUpdateScrollSize()));
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnUpdateScrollSize()
|
|
{
|
|
// this just tells the scroll area to tell its layout that it has a new sizehint
|
|
m_gui->scrollArea->updateGeometry();
|
|
}
|
|
|
|
ChannelControl* DrillerCaptureWindow::FindChannelControl(Aggregator* aggregator)
|
|
{
|
|
ChannelControl* retVal = nullptr;
|
|
|
|
QString channelName = aggregator->GetChannelName();
|
|
AZ::Crc32 groupCRC = AZ::Crc32(channelName.toStdString().c_str());
|
|
|
|
for (ChannelControl* channelControl : m_channels)
|
|
{
|
|
if (groupCRC == channelControl->GetChannelId())
|
|
{
|
|
retVal = channelControl;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (retVal == nullptr)
|
|
{
|
|
retVal = aznew ChannelControl(channelName.toStdString().c_str(), &m_AnnotationProvider);
|
|
|
|
if (retVal)
|
|
{
|
|
m_channels.push_back(retVal);
|
|
}
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
void DrillerCaptureWindow::AddChannelDisplay(ChannelControl* cc)
|
|
{
|
|
m_gui->channelLayout->addWidget(cc);
|
|
|
|
// layouts take one message process to update their sizes, we need to queue a refresh of our scroll area at the end of the event queue
|
|
// so that the sizeHint() will be correct.
|
|
QTimer::singleShot(0, this, SLOT(OnUpdateScrollSize()));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Driller Network Messages
|
|
void DrillerCaptureWindow::ConnectedToNetwork()
|
|
{
|
|
if (m_isLoadingFile)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (IsInCaptureMode(CaptureMode::Inspecting))
|
|
{
|
|
return;
|
|
}
|
|
|
|
StateReset();
|
|
}
|
|
|
|
void DrillerCaptureWindow::ConnectChannelControl(ChannelControl* dc)
|
|
{
|
|
if (!dc->IsSetup())
|
|
{
|
|
connect(dc, SIGNAL(GetInspectionFileName()), this, SLOT(GetOpenFileName()));
|
|
connect(dc, SIGNAL(RequestScrollToFrame(FrameNumberType)), this, SLOT(HandleScrollToFrameRequest(FrameNumberType)));
|
|
connect(dc, SIGNAL(InformOfMouseClick(Qt::MouseButton, FrameNumberType, FrameNumberType, int)), this, SLOT(OnChannelControlMouseDown(Qt::MouseButton, FrameNumberType, FrameNumberType, int)));
|
|
connect(dc, SIGNAL(InformOfMouseMove(FrameNumberType, FrameNumberType, int)), this, SLOT(OnChannelControlMouseMove(FrameNumberType, FrameNumberType, int)));
|
|
connect(dc, SIGNAL(InformOfMouseRelease(Qt::MouseButton, FrameNumberType, FrameNumberType, int)), this, SLOT(OnChannelControlMouseUp(Qt::MouseButton, FrameNumberType, FrameNumberType, int)));
|
|
connect(dc, SIGNAL(InformOfMouseWheel(FrameNumberType, int, FrameNumberType, int)), this, SLOT(OnChannelControlMouseWheel(FrameNumberType, int, FrameNumberType, int)));
|
|
connect(dc, SIGNAL(ExpandedContracted()), this, SLOT(OnUpdateScrollSize()));
|
|
|
|
connect(this, SIGNAL(ScrubberFrameUpdate(FrameNumberType)), dc, SLOT(SetScrubberFrame(FrameNumberType)));
|
|
connect(this, SIGNAL(ShowYourself()), dc, SLOT(OnShowCommand()));
|
|
connect(this, SIGNAL(HideYourself()), dc, SLOT(OnHideCommand()));
|
|
connect(this, SIGNAL(OnCaptureModeChange(CaptureMode)), dc, SLOT(SetCaptureMode(CaptureMode)));
|
|
|
|
dc->SetCaptureMode(m_captureMode);
|
|
|
|
dc->SignalSetup();
|
|
}
|
|
}
|
|
|
|
// target that you're connected to knows what aggregators are ready.
|
|
void DrillerCaptureWindow::NewAggregatorsAvailable()
|
|
{
|
|
if (m_isLoadingFile)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (IsInCaptureMode(CaptureMode::Inspecting))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// otherwise, make em, if we're live.
|
|
m_data->CreateAggregators();
|
|
}
|
|
|
|
// incoming driller bus message
|
|
void DrillerCaptureWindow::NewAggregatorList(AggregatorList& theList)
|
|
{
|
|
ClearExistingChannels();
|
|
|
|
if (theList.size())
|
|
{
|
|
for (AggregatorList::iterator iter = theList.begin(); iter != theList.end(); ++iter)
|
|
{
|
|
ChannelControl* channelControl = FindChannelControl((*iter));
|
|
ConnectChannelControl(channelControl);
|
|
|
|
ChannelProfilerWidget* profilerWidget = channelControl->AddAggregator((*iter));
|
|
|
|
if (profilerWidget)
|
|
{
|
|
// defaults to active
|
|
// restore previous inactive state if GUIDs match
|
|
bool wasInactive = (m_inactiveChannels.find(profilerWidget->GetID()) != m_inactiveChannels.end());
|
|
profilerWidget->SetIsActive(!wasInactive);
|
|
}
|
|
}
|
|
|
|
PopulateChannelDisplay();
|
|
|
|
m_gui->combinedEventsWidget->AddAggregatorList(theList);
|
|
m_gui->captureButton->setEnabled(true);
|
|
}
|
|
}
|
|
|
|
void DrillerCaptureWindow::AddAggregator(Aggregator& theAggregator)
|
|
{
|
|
ChannelControl* channelControl = FindChannelControl(&theAggregator);
|
|
|
|
if (!channelControl->IsSetup())
|
|
{
|
|
ConnectChannelControl(channelControl);
|
|
AddChannelDisplay(channelControl);
|
|
}
|
|
|
|
ChannelProfilerWidget* profilerWidget = channelControl->AddAggregator(&theAggregator);
|
|
|
|
if (profilerWidget)
|
|
{
|
|
// defaults to active
|
|
// restore previous inactive state if GUIDs match
|
|
int wasInactive = (m_inactiveChannels.find(profilerWidget->GetID()) != m_inactiveChannels.end());
|
|
profilerWidget->SetIsActive(!wasInactive);
|
|
}
|
|
|
|
m_gui->captureButton->setEnabled(true);
|
|
m_gui->combinedEventsWidget->AddAggregator(theAggregator);
|
|
}
|
|
|
|
void DrillerCaptureWindow::DiscardAggregators()
|
|
{
|
|
ClearExistingChannels();
|
|
m_gui->captureButton->setEnabled(false);
|
|
}
|
|
|
|
// incoming driller bus message
|
|
void DrillerCaptureWindow::DisconnectedFromNetwork()
|
|
{
|
|
//todo: phughes message the user or something
|
|
}
|
|
|
|
void DrillerCaptureWindow::UpdateEndFrameInControls()
|
|
{
|
|
if (!m_isLoadingFile)
|
|
{
|
|
for (auto iter = m_channels.begin(); iter != m_channels.end(); ++iter)
|
|
{
|
|
(*iter)->SetEndFrame(m_frameRangeEnd);
|
|
}
|
|
m_ptrAnnotationsHeaderView->SetEndFrame(m_frameRangeEnd);
|
|
}
|
|
}
|
|
|
|
QString DrillerCaptureWindow::GetOpenFileName() const
|
|
{
|
|
AZ_Error("DrillerCaptureWindow", IsInCaptureMode(CaptureMode::Inspecting), "Trying to get file name in non-inspected case");
|
|
return m_currentDataFilename;
|
|
}
|
|
|
|
// incoming driller bus message
|
|
void DrillerCaptureWindow::EndFrame(FrameNumberType frame)
|
|
{
|
|
// if we're loading a file then we do not scrub these live:
|
|
SetFrameRangeEnd(frame);
|
|
UpdateEndFrameInControls();
|
|
}
|
|
|
|
// incoming driller bus message
|
|
void DrillerCaptureWindow::ScrubberFrame(FrameNumberType frame)
|
|
{
|
|
emit ScrubberFrameUpdate(frame);
|
|
m_gui->frameScrubberBox->setValue(static_cast<int>(frame));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Data Viewer Request Messages
|
|
void DrillerCaptureWindow::EventRequestEventFocus(EventNumberType eventIdx)
|
|
{
|
|
m_scrubberCurrentEvent = eventIdx;
|
|
|
|
EBUS_EVENT_ID(m_identity, Driller::DrillerEventWindowMessages::Bus, EventFocusChanged, eventIdx);
|
|
}
|
|
|
|
void DrillerCaptureWindow::SetScrubberEvent(EventNumberType eventIdx)
|
|
{
|
|
EventRequestEventFocus(eventIdx);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GUI Messages
|
|
void DrillerCaptureWindow::OnCaptureToggled(bool toggleState)
|
|
{
|
|
DrillerOperationTelemetryEvent captureEvent;
|
|
|
|
if (toggleState)
|
|
{
|
|
captureEvent.SetAttribute("StartDataCapture", "");
|
|
captureEvent.SetMetric("CaptureId", m_captureId);
|
|
|
|
QString activeChannels;
|
|
|
|
bool appendComma = false;
|
|
|
|
for (ChannelControl* channel : m_channels)
|
|
{
|
|
const AZStd::list< ChannelProfilerWidget* >& profilers = channel->GetProfilers();
|
|
|
|
for (ChannelProfilerWidget* profiler : profilers)
|
|
{
|
|
if (profiler->IsActive())
|
|
{
|
|
if (appendComma)
|
|
{
|
|
activeChannels.append(",");
|
|
}
|
|
|
|
appendComma = true;
|
|
activeChannels.append(profiler->GetName());
|
|
}
|
|
}
|
|
}
|
|
|
|
captureEvent.SetAttribute("ActiveChannels", activeChannels.toStdString().c_str());
|
|
|
|
AZ_TracePrintf(drillerInfoName, "Capture ON, starting a new data session\n");
|
|
OnPlayToggled(false);
|
|
m_gui->captureButton->setText(tr("Stop Capture"));
|
|
m_gui->captureButton->setToolTip(tr("Stop Capturing Driller Data"));
|
|
StateReset();
|
|
|
|
SetCaptureMode(CaptureMode::Capturing);
|
|
|
|
m_AnnotationProvider.Clear();
|
|
|
|
ClearChannelDisplay(false);
|
|
SortChannels();
|
|
PopulateChannelDisplay();
|
|
|
|
if (m_data)
|
|
{
|
|
m_data->StartDrilling();
|
|
}
|
|
|
|
SetCaptureDirty(true);
|
|
UpdateLiveControls();
|
|
}
|
|
else
|
|
{
|
|
captureEvent.SetAttribute("StopDataCapture", "");
|
|
captureEvent.SetMetric("CaptureId", m_captureId);
|
|
|
|
++m_captureId;
|
|
|
|
AZ_TracePrintf(drillerInfoName, "Capture OFF, freezing data for analysis\n");
|
|
m_gui->captureButton->setText(tr("Capture"));
|
|
m_gui->captureButton->setToolTip(tr("Begin Capturing Driller Data"));
|
|
|
|
bool wascapturing = IsInCaptureMode(CaptureMode::Capturing);
|
|
|
|
CaptureMode::Inspecting;
|
|
emit OnCaptureModeChange(m_captureMode);
|
|
|
|
if (m_data)
|
|
{
|
|
m_data->StopDrilling();
|
|
}
|
|
|
|
if (wascapturing)
|
|
{
|
|
OnSaveDrillerFile();
|
|
ScrubberToEnd();
|
|
SetFrameRangeEnd(0);
|
|
// counting on the OnSave to recognize the TMP file from the capture and copy appropriately
|
|
// and setting it to our currently active data file
|
|
}
|
|
}
|
|
|
|
captureEvent.Log();
|
|
|
|
update();
|
|
}
|
|
|
|
void DrillerCaptureWindow::SetCaptureDirty(bool isDirty)
|
|
{
|
|
m_captureIsDirty = isDirty;
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnMenuCloseCurrentWindow()
|
|
{
|
|
AZ_TracePrintf(drillerDebugName, "Close requested\n");
|
|
|
|
OnCaptureToggled(false);
|
|
OnCloseFile();
|
|
|
|
EBUS_EVENT(AzToolsFramework::FrameworkMessages::Bus, RequestMainWindowClose, ContextID);
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnOpen()
|
|
{
|
|
AZ_TracePrintf(drillerDebugName, "Open requested\n");
|
|
|
|
this->show();
|
|
emit ShowYourself();
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnClose()
|
|
{
|
|
OnCloseFile();
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnCloseFile()
|
|
{
|
|
SaveWindowState();
|
|
|
|
if (IsInCaptureMode(CaptureMode::Inspecting))
|
|
{
|
|
AZ_TracePrintf(drillerDebugName, "Close requested of file\n");
|
|
m_data->CloseCaptureData();
|
|
this->close();
|
|
deleteLater();
|
|
}
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnContractAllChannels()
|
|
{
|
|
for (auto iter = m_channels.begin(); iter != m_channels.end(); ++iter)
|
|
{
|
|
(*iter)->OnContractedToggled(true);
|
|
}
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnExpandAllChannels()
|
|
{
|
|
for (auto iter = m_channels.begin(); iter != m_channels.end(); ++iter)
|
|
{
|
|
(*iter)->OnContractedToggled(false);
|
|
}
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnDisableAllChannels()
|
|
{
|
|
for (ChannelControl* channelControl : m_channels)
|
|
{
|
|
channelControl->SetAllProfilersEnabled(false);
|
|
}
|
|
}
|
|
void DrillerCaptureWindow::OnEnableAllChannels()
|
|
{
|
|
for (ChannelControl* channelControl : m_channels)
|
|
{
|
|
channelControl->SetAllProfilersEnabled(true);
|
|
}
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnToBegin()
|
|
{
|
|
ScrubberToBegin();
|
|
m_gui->controlScrollBar->setValue(m_frameRangeBegin);
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnToEnd()
|
|
{
|
|
// set the scroll view to scroll to the end:
|
|
ScrubberToEnd();
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnPlayToggled(bool toggleState)
|
|
{
|
|
if (toggleState)
|
|
{
|
|
m_gui->playButton->setText(tr("Stop"));
|
|
m_gui->playButton->setToolTip(tr("Stop recorded session playback"));
|
|
m_playbackIsActive = true;
|
|
OnCaptureToggled(false);
|
|
int msec = 1000 / m_gui->fpsBox->value();
|
|
QTimer::singleShot(msec, this, SLOT(PlaybackTick()));
|
|
}
|
|
else
|
|
{
|
|
m_gui->playButton->setText(tr("Play"));
|
|
m_gui->playButton->setToolTip(tr("Playback recorded session"));
|
|
m_gui->playButton->blockSignals(true);
|
|
m_gui->playButton->setChecked(false);
|
|
m_gui->playButton->blockSignals(false);
|
|
m_playbackIsActive = false;
|
|
}
|
|
}
|
|
|
|
void DrillerCaptureWindow::PlaybackTick()
|
|
{
|
|
if (m_playbackIsActive)
|
|
{
|
|
if (m_scrubberCurrentFrame >= m_playbackLoopEnd)
|
|
{
|
|
SetScrubberFrame(m_playbackLoopBegin);
|
|
}
|
|
else if (m_scrubberCurrentFrame < m_playbackLoopBegin)
|
|
{
|
|
SetScrubberFrame(m_playbackLoopBegin);
|
|
}
|
|
else
|
|
{
|
|
SetScrubberFrame(m_scrubberCurrentFrame + 1);
|
|
}
|
|
|
|
FocusScrollbar(m_scrubberCurrentFrame - (m_visibleFrames / 2));
|
|
|
|
int msec = 1000 / m_gui->fpsBox->value();
|
|
QTimer::singleShot(msec, this, SLOT(PlaybackTick()));
|
|
}
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnSliderPressed()
|
|
{
|
|
if (m_playbackIsActive)
|
|
{
|
|
OnPlayToggled(false);
|
|
}
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnNewSliderValue(int newValue)
|
|
{
|
|
if (!m_manipulatingScrollBar && m_playbackIsActive)
|
|
{
|
|
OnPlayToggled(false);
|
|
}
|
|
|
|
for (auto iter = m_channels.begin(); iter != m_channels.end(); ++iter)
|
|
{
|
|
(*iter)->SetSliderOffset(newValue);
|
|
}
|
|
|
|
m_ptrAnnotationsHeaderView->SetSliderOffset(newValue);
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnFrameScrubberboxChanged(int newValue)
|
|
{
|
|
SetScrubberFrame(newValue);
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnQuantMenuFinal(int range)
|
|
{
|
|
FrameNumberType frameRange = static_cast<FrameNumberType>(range);
|
|
|
|
if (frameRange <= 1)
|
|
{
|
|
frameRange = m_frameRangeEnd - m_frameRangeBegin + 1;
|
|
}
|
|
m_visibleFrames = frameRange;
|
|
|
|
m_gui->quantityButton->setText(QString("%1 frames").arg(frameRange));
|
|
|
|
for (auto iter = m_channels.begin(); iter != m_channels.end(); ++iter)
|
|
{
|
|
(*iter)->SetDataPointsInView(frameRange);
|
|
}
|
|
m_ptrAnnotationsHeaderView->SetDataPointsInView(frameRange);
|
|
}
|
|
|
|
void DrillerCaptureWindow::FocusScrollbar(FrameNumberType focusFrame)
|
|
{
|
|
m_manipulatingScrollBar = true;
|
|
|
|
// range of motion for the scrollbar covers the off-window area, not the total
|
|
FrameNumberType range = m_frameRangeEnd - m_visibleFrames + 1;
|
|
range = range >= m_frameRangeBegin ? range : m_frameRangeBegin;
|
|
|
|
m_gui->controlScrollBar->setRange(m_frameRangeBegin, range);
|
|
|
|
FrameNumberType curVal = focusFrame < 0 ? 0 : focusFrame;
|
|
curVal = focusFrame > range ? range : focusFrame;
|
|
m_gui->controlScrollBar->setValue(curVal);
|
|
|
|
m_manipulatingScrollBar = false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// State Control and Maintenance
|
|
void DrillerCaptureWindow::ScrubberToBegin()
|
|
{
|
|
SetScrubberFrame(GetFrameRangeBegin());
|
|
}
|
|
|
|
void DrillerCaptureWindow::ScrubberToEnd()
|
|
{
|
|
SetScrubberFrame(GetFrameRangeEnd());
|
|
}
|
|
|
|
void DrillerCaptureWindow::HandleScrollToFrameRequest(FrameNumberType frame)
|
|
{
|
|
FocusScrollbar(frame);
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnChannelControlMouseDown(Qt::MouseButton whichButton, FrameNumberType frame, FrameNumberType range, int modifiers)
|
|
{
|
|
// If we aren't inspecting data, we don't to mess around with anything.
|
|
if (!IsInCaptureMode(CaptureMode::Inspecting))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (modifiers & Qt::AltModifier)
|
|
{
|
|
if (whichButton == Qt::LeftButton)
|
|
{
|
|
SetPlaybackLoopBegin(frame);
|
|
}
|
|
if (whichButton == Qt::RightButton)
|
|
{
|
|
SetPlaybackLoopEnd(frame);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Don't want to fight the user for control, relinquish our manipulation once they start doing stuff.
|
|
if (m_playbackIsActive)
|
|
{
|
|
OnPlayToggled(false);
|
|
}
|
|
|
|
// we grab with the left button, pan with the right.
|
|
if (whichButton == Qt::LeftButton)
|
|
{
|
|
m_draggingAnything = true;
|
|
|
|
if (abs(frame - m_playbackLoopBegin) <= range)
|
|
{
|
|
m_draggingPlaybackLoopBegin = true;
|
|
m_draggingPlaybackLoopEnd = false;
|
|
}
|
|
else if (abs(frame - m_playbackLoopEnd) <= range)
|
|
{
|
|
m_draggingPlaybackLoopBegin = false;
|
|
m_draggingPlaybackLoopEnd = true;
|
|
}
|
|
else
|
|
{
|
|
m_draggingPlaybackLoopBegin = false;
|
|
m_draggingPlaybackLoopEnd = false;
|
|
|
|
SetScrubberFrame(frame);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnChannelControlMouseMove(FrameNumberType frame, FrameNumberType range, int modifiers)
|
|
{
|
|
(void)range;
|
|
(void)modifiers;
|
|
|
|
//ShowDrillerChannelTip(frame);
|
|
|
|
if (m_draggingAnything)
|
|
{
|
|
if (m_draggingPlaybackLoopBegin)
|
|
{
|
|
SetPlaybackLoopBegin(frame);
|
|
}
|
|
else if (m_draggingPlaybackLoopEnd)
|
|
{
|
|
SetPlaybackLoopEnd(frame);
|
|
}
|
|
else
|
|
{
|
|
SetScrubberFrame(frame);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnChannelControlMouseUp(Qt::MouseButton whichButton, FrameNumberType frame, FrameNumberType range, int modifiers)
|
|
{
|
|
(void)range;
|
|
(void)modifiers;
|
|
(void)frame;
|
|
|
|
if (whichButton == Qt::LeftButton)
|
|
{
|
|
m_draggingAnything = false;
|
|
}
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnChannelControlMouseWheel(FrameNumberType frame, int wheelAmount, FrameNumberType range, int modifiers)
|
|
{
|
|
(void)range;
|
|
(void)modifiers;
|
|
|
|
FrameNumberType currentVisibleFrames = m_visibleFrames;
|
|
bool zoomingIn = wheelAmount > 0;
|
|
if (zoomingIn)
|
|
{
|
|
// zooming in:
|
|
// find the next step DOWN from where we are and set our quant zoom to that
|
|
// since its from zoomed all the way in to out. The last element is assumed the special one.
|
|
|
|
if (currentVisibleFrames == s_availableFrameQuantities[0])
|
|
{
|
|
return;
|
|
}
|
|
|
|
// before we zoom in, where is the given frame within our scroll area?
|
|
int leftSideOfScreen = m_gui->controlScrollBar->value();
|
|
float fraction = (float)(frame - leftSideOfScreen) / (float)m_visibleFrames;
|
|
|
|
int numQuantsAvailable = sizeof(s_availableFrameQuantities) / sizeof(int);
|
|
int quantChosen = -1;
|
|
for (int quantIndex = numQuantsAvailable - 2; quantIndex >= 0; --quantIndex)
|
|
{
|
|
if (currentVisibleFrames > s_availableFrameQuantities[quantIndex])
|
|
{
|
|
quantChosen = s_availableFrameQuantities[quantIndex];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (quantChosen != -1)
|
|
{
|
|
OnQuantMenuFinal(quantChosen);
|
|
|
|
// we want to focus the scrollbar at the same fraction as before
|
|
FocusScrollbar(frame - (int)((float)m_visibleFrames * fraction));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// zooming out:
|
|
// find the next step DOWN from where we are and set our quant zoom to that
|
|
// since its from zoomed all the way in to out. The last element is assumed the special one.
|
|
|
|
FrameNumberType fullRange = m_frameRangeEnd - m_frameRangeBegin + 1;
|
|
|
|
if (currentVisibleFrames == fullRange)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int leftSideOfScreen = m_gui->controlScrollBar->value();
|
|
float fraction = (float)(frame - leftSideOfScreen) / (float)m_visibleFrames;
|
|
|
|
int numQuantsAvailable = sizeof(s_availableFrameQuantities) / sizeof(int);
|
|
|
|
int quantChosen = -1;
|
|
for (int quantIndex = 0; quantIndex < numQuantsAvailable - 1; ++quantIndex)
|
|
{
|
|
if (currentVisibleFrames < s_availableFrameQuantities[quantIndex])
|
|
{
|
|
quantChosen = s_availableFrameQuantities[quantIndex];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (quantChosen != -1)
|
|
{
|
|
OnQuantMenuFinal(quantChosen);
|
|
FocusScrollbar(frame - (int)((float)m_visibleFrames * fraction));
|
|
}
|
|
}
|
|
}
|
|
|
|
void DrillerCaptureWindow::SetScrubberFrame(FrameNumberType frame)
|
|
{
|
|
if ((!m_bForceNextScrub) && (frame == m_scrubberCurrentFrame))
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_bForceNextScrub = false;
|
|
|
|
m_scrubberCurrentFrame = frame >= m_frameRangeBegin ? frame : m_frameRangeBegin;
|
|
m_scrubberCurrentFrame = m_scrubberCurrentFrame <= m_frameRangeEnd ? m_scrubberCurrentFrame : m_frameRangeEnd;
|
|
|
|
UpdateFrameScrubberbox();
|
|
|
|
ScrubberFrame(m_scrubberCurrentFrame);
|
|
|
|
EBUS_EVENT_ID(m_identity, Driller::DrillerMainWindowMessages::Bus, FrameChanged, m_scrubberCurrentFrame);
|
|
m_AnnotationProvider.Finalize();
|
|
}
|
|
|
|
void DrillerCaptureWindow::SetPlaybackLoopBegin(FrameNumberType frame)
|
|
{
|
|
m_playbackLoopBegin = frame >= m_frameRangeBegin ? frame : m_frameRangeBegin;
|
|
m_playbackLoopBegin = m_playbackLoopBegin <= m_frameRangeEnd ? m_playbackLoopBegin : m_frameRangeEnd;
|
|
|
|
m_playbackLoopEnd = m_playbackLoopEnd >= m_playbackLoopBegin ? m_playbackLoopEnd : m_playbackLoopBegin;
|
|
m_playbackLoopEnd = m_playbackLoopEnd <= m_frameRangeEnd ? m_playbackLoopEnd : m_frameRangeEnd;
|
|
|
|
EBUS_EVENT_ID(m_identity, Driller::DrillerMainWindowMessages::Bus, PlaybackLoopBeginChanged, m_playbackLoopBegin);
|
|
|
|
UpdatePlaybackLoopPoints();
|
|
}
|
|
|
|
void DrillerCaptureWindow::SetPlaybackLoopEnd(FrameNumberType frame)
|
|
{
|
|
m_playbackLoopEnd = frame >= m_frameRangeBegin ? frame : m_frameRangeBegin;
|
|
m_playbackLoopEnd = m_playbackLoopEnd <= m_frameRangeEnd ? m_playbackLoopEnd : m_frameRangeEnd;
|
|
|
|
m_playbackLoopBegin = m_playbackLoopBegin >= m_playbackLoopEnd ? m_playbackLoopEnd : m_playbackLoopBegin;
|
|
m_playbackLoopBegin = m_playbackLoopBegin >= m_frameRangeBegin ? m_playbackLoopBegin : m_frameRangeBegin;
|
|
|
|
EBUS_EVENT_ID(m_identity, Driller::DrillerMainWindowMessages::Bus, PlaybackLoopEndChanged, m_playbackLoopEnd);
|
|
|
|
UpdatePlaybackLoopPoints();
|
|
}
|
|
|
|
void DrillerCaptureWindow::UpdatePlaybackLoopPoints()
|
|
{
|
|
for (auto iter = m_channels.begin(); iter != m_channels.end(); ++iter)
|
|
{
|
|
(*iter)->SetLoopBegin(m_playbackLoopBegin);
|
|
(*iter)->SetLoopEnd(m_playbackLoopEnd);
|
|
}
|
|
}
|
|
|
|
void DrillerCaptureWindow::SetFrameRangeBegin(FrameNumberType frame)
|
|
{
|
|
m_frameRangeBegin = frame;
|
|
|
|
SetPlaybackLoopBegin(m_playbackLoopBegin);
|
|
SetPlaybackLoopEnd(m_playbackLoopEnd);
|
|
SetScrubberFrame(m_scrubberCurrentFrame);
|
|
UpdateFrameScrubberbox();
|
|
UpdateScrollbar();
|
|
}
|
|
|
|
void DrillerCaptureWindow::SetFrameRangeEnd(FrameNumberType frame)
|
|
{
|
|
// if the scrubber/loop is on the last frame we always advance it to the new end
|
|
bool setScrubberToo = m_scrubberCurrentFrame == m_frameRangeEnd;
|
|
bool setEndloopToo = m_playbackLoopEnd == m_frameRangeEnd;
|
|
|
|
FrameNumberType range = m_frameRangeEnd - m_visibleFrames + 1;
|
|
range = range >= m_frameRangeBegin ? range : m_frameRangeBegin;
|
|
|
|
FrameNumberType priorFrameRangeEnd = m_frameRangeEnd;
|
|
|
|
int diff = static_cast<int>(frame - m_frameRangeEnd);
|
|
m_frameRangeEnd = frame;
|
|
|
|
if (priorFrameRangeEnd < m_frameRangeEnd)
|
|
{
|
|
for (ChannelControl* channelControl : m_channels)
|
|
{
|
|
for (ChannelProfilerWidget* channelProfiler : channelControl->GetProfilers())
|
|
{
|
|
Aggregator* aggregator = channelProfiler->GetAggregator();
|
|
if (aggregator != nullptr)
|
|
{
|
|
aggregator->EmitAnnotationChannelsForFrameRange(priorFrameRangeEnd, m_frameRangeEnd, &m_AnnotationProvider);
|
|
aggregator->EmitAllAnnotationsForFrameRange(priorFrameRangeEnd, m_frameRangeEnd, &m_AnnotationProvider);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!m_isLoadingFile)
|
|
{
|
|
SetScrubberFrame(setScrubberToo ? m_frameRangeEnd : m_scrubberCurrentFrame);
|
|
|
|
SetPlaybackLoopBegin(m_playbackLoopBegin);
|
|
SetPlaybackLoopEnd(setEndloopToo ? m_frameRangeEnd : m_playbackLoopEnd);
|
|
UpdateFrameScrubberbox();
|
|
UpdateScrollbar(diff);
|
|
}
|
|
}
|
|
|
|
void DrillerCaptureWindow::UpdateFrameScrubberbox()
|
|
{
|
|
m_gui->frameScrubberBox->setRange(m_frameRangeBegin, m_frameRangeEnd);
|
|
m_gui->frameScrubberBox->setValue(m_scrubberCurrentFrame);
|
|
}
|
|
|
|
void DrillerCaptureWindow::UpdateScrollbar(int diff)
|
|
{
|
|
int curVal = m_gui->controlScrollBar->value();
|
|
|
|
// range of motion for the scrollbar covers the off-window area, not the total
|
|
FrameNumberType range = m_frameRangeEnd - m_visibleFrames + 1;
|
|
range = range >= m_frameRangeBegin ? range : m_frameRangeBegin;
|
|
|
|
m_gui->controlScrollBar->setRange(m_frameRangeBegin, range);
|
|
if (m_gui->controlScrollBar->value() >= range - 1)
|
|
{
|
|
m_gui->controlScrollBar->setValue(static_cast<int>(range));
|
|
}
|
|
else if (diff)
|
|
{
|
|
m_gui->controlScrollBar->setValue(static_cast<int>(curVal));
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// when the Editor Main window is requested to close, it is not destroyed.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Qt Events
|
|
void DrillerCaptureWindow::closeEvent(QCloseEvent* event)
|
|
{
|
|
OnCloseFile();
|
|
event->ignore();
|
|
}
|
|
|
|
void DrillerCaptureWindow::showEvent(QShowEvent* /*event*/)
|
|
{
|
|
emit ShowYourself();
|
|
}
|
|
void DrillerCaptureWindow::hideEvent(QHideEvent* /*event*/)
|
|
{
|
|
emit HideYourself();
|
|
}
|
|
|
|
bool DrillerCaptureWindow::OnGetPermissionToShutDown()
|
|
{
|
|
OnCaptureToggled(false);
|
|
|
|
bool willShutDown = true;
|
|
|
|
ClearChannelDisplay(true);
|
|
|
|
AZ_TracePrintf(drillerDebugName, " willShutDown == %d\n", (int)willShutDown);
|
|
return willShutDown;
|
|
}
|
|
|
|
void DrillerCaptureWindow::ScrubToFrameRequest(FrameNumberType frame)
|
|
{
|
|
if (m_playbackIsActive)
|
|
{
|
|
OnPlayToggled(false);
|
|
}
|
|
|
|
SetScrubberFrame(frame);
|
|
}
|
|
|
|
void DrillerCaptureWindow::SaveWindowState()
|
|
{
|
|
m_inactiveChannels.clear();
|
|
|
|
for (auto iter = m_channels.begin(); iter != m_channels.end(); ++iter)
|
|
{
|
|
const AZStd::list< ChannelProfilerWidget*>& profilers = (*iter)->GetProfilers();
|
|
|
|
for (ChannelProfilerWidget* profiler : profilers)
|
|
{
|
|
if (!profiler->IsActive())
|
|
{
|
|
m_inactiveChannels.insert(profiler->GetID());
|
|
}
|
|
}
|
|
}
|
|
|
|
// build state and store it.
|
|
auto newState = AZ::UserSettings::CreateFind<DrillerCaptureWindowSavedState>(m_windowStateCRC, AZ::UserSettings::CT_GLOBAL);
|
|
//newState->Init(saveState(), saveGeometry());
|
|
newState->m_ChannelIDs.clear();
|
|
for (AZStd::set<AZ::Uuid>::iterator iter = m_inactiveChannels.begin(); iter != m_inactiveChannels.end(); ++iter)
|
|
{
|
|
newState->m_ChannelIDs.push_back(*iter);
|
|
}
|
|
|
|
newState->m_fpsValue = m_gui->fpsBox->value();
|
|
|
|
newState->m_scrubberCurrentFrame = m_scrubberCurrentFrame;
|
|
newState->m_playbackLoopBegin = m_playbackLoopBegin;
|
|
newState->m_playbackLoopEnd = m_playbackLoopEnd;
|
|
newState->m_scrubberCurrentEvent = m_scrubberCurrentEvent;
|
|
}
|
|
|
|
void DrillerCaptureWindow::RestoreWindowState() // call this after you have rebuilt everything.
|
|
{
|
|
// load the state from our state block:
|
|
auto savedState = AZ::UserSettings::Find<DrillerCaptureWindowSavedState>(m_windowStateCRC, AZ::UserSettings::CT_GLOBAL);
|
|
if (savedState)
|
|
{
|
|
QByteArray geomData((const char*)savedState->m_windowGeometry.data(), (int)savedState->m_windowGeometry.size());
|
|
QByteArray stateData((const char*)savedState->GetWindowState().data(), (int)savedState->GetWindowState().size());
|
|
|
|
restoreGeometry(geomData);
|
|
if (this->isMaximized())
|
|
{
|
|
this->showNormal();
|
|
this->showMaximized();
|
|
}
|
|
//restoreState(stateData);
|
|
|
|
m_inactiveChannels.clear();
|
|
for (auto iter = savedState->m_ChannelIDs.begin(); iter != savedState->m_ChannelIDs.end(); ++iter)
|
|
{
|
|
m_inactiveChannels.insert(*iter);
|
|
}
|
|
|
|
m_gui->fpsBox->setValue(savedState->m_fpsValue);
|
|
|
|
SetScrubberFrame(savedState->m_scrubberCurrentFrame);
|
|
SetPlaybackLoopBegin(savedState->m_playbackLoopBegin);
|
|
SetPlaybackLoopEnd(savedState->m_playbackLoopEnd);
|
|
SetScrubberEvent(savedState->m_scrubberCurrentEvent);
|
|
}
|
|
else
|
|
{
|
|
// default state!
|
|
}
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnOpenDrillerFile()
|
|
{
|
|
auto paths = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation);
|
|
QString capturePath;
|
|
if (paths.isEmpty())
|
|
{
|
|
paths = QStandardPaths::standardLocations(QStandardPaths::TempLocation);
|
|
}
|
|
if (!paths.isEmpty())
|
|
{
|
|
capturePath = paths.first();
|
|
}
|
|
|
|
QString fileName = QFileDialog::getOpenFileName(this, "Open Driller File", capturePath, "Driller Files (*.drl)");
|
|
if (!fileName.isNull())
|
|
{
|
|
OnOpenDrillerFile(fileName);
|
|
}
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnOpenDrillerFile(QString fileName)
|
|
{
|
|
if (m_data)
|
|
{
|
|
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
|
m_AnnotationProvider.Clear();
|
|
|
|
SetCaptureDirty(false);
|
|
m_currentDataFilename = fileName;
|
|
|
|
m_isLoadingFile = true;
|
|
m_data->LoadCaptureData(fileName.toUtf8().data());
|
|
m_isLoadingFile = false;
|
|
|
|
SetCaptureMode(CaptureMode::Inspecting);
|
|
|
|
m_bForceNextScrub = true;
|
|
EndFrame(m_frameRangeEnd);
|
|
SetPlaybackLoopBegin(0);
|
|
SetPlaybackLoopEnd(m_frameRangeEnd);
|
|
|
|
OnQuantMenuFinal(m_visibleFrames);
|
|
|
|
UpdateLiveControls();
|
|
m_bForceNextScrub = true;
|
|
|
|
ScrubberToEnd();
|
|
QApplication::restoreOverrideCursor();
|
|
}
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnOpenDrillerFileForWorkspace(QString fileName, QString workspaceFileName)
|
|
{
|
|
if (m_data)
|
|
{
|
|
QString successFileName;
|
|
|
|
// does a file local to our given Workspace DRW exist? It gets preference on load.
|
|
QString localFileName(workspaceFileName.left(workspaceFileName.size() - 3) + "drl");
|
|
if (AZ::IO::SystemFile::Exists(localFileName.toUtf8().data()))
|
|
{
|
|
successFileName = localFileName;
|
|
}
|
|
// does the workspace's suggested file exist?
|
|
else if (AZ::IO::SystemFile::Exists(fileName.toUtf8().data()))
|
|
{
|
|
successFileName = fileName;
|
|
}
|
|
// fall through to prompting the user for a DRL to use
|
|
else
|
|
{
|
|
QString userFileName = QFileDialog::getOpenFileName(this, "Find Driller File", localFileName, "Driller Files (*.drl)");
|
|
if (!userFileName.isNull())
|
|
{
|
|
successFileName = userFileName;
|
|
}
|
|
}
|
|
|
|
if (!successFileName.isEmpty() && !successFileName.isNull())
|
|
{
|
|
SetCaptureDirty(false);
|
|
m_currentDataFilename = successFileName;
|
|
|
|
m_isLoadingFile = true;
|
|
m_data->LoadCaptureData(m_currentDataFilename.toUtf8().data());
|
|
m_isLoadingFile = false;
|
|
|
|
SetCaptureMode(CaptureMode::Inspecting);
|
|
|
|
m_bForceNextScrub = true;
|
|
EndFrame(m_frameRangeEnd);
|
|
|
|
OnQuantMenuFinal(m_visibleFrames);
|
|
m_bForceNextScrub = true;
|
|
ScrubberToEnd();
|
|
UpdateLiveControls();
|
|
}
|
|
}
|
|
}
|
|
|
|
void DrillerCaptureWindow::RepopulateAnnotations()
|
|
{
|
|
// re-query all the annotations now that you have your settings.
|
|
m_AnnotationProvider.Clear();
|
|
|
|
if (m_frameRangeEnd != 0)
|
|
{
|
|
for (ChannelControl* channelControl : m_channels)
|
|
{
|
|
for (ChannelProfilerWidget* profiler : channelControl->GetProfilers())
|
|
{
|
|
Aggregator* aggregator = profiler->GetAggregator();
|
|
|
|
if (aggregator != nullptr)
|
|
{
|
|
aggregator->EmitAnnotationChannelsForFrameRange(0, m_frameRangeEnd, &m_AnnotationProvider);
|
|
aggregator->EmitAllAnnotationsForFrameRange(0, m_frameRangeEnd, &m_AnnotationProvider);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
m_AnnotationProvider.Finalize();
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnOpenWorkspaceFile(QString workspaceFileName, bool openDrillerFileAlso)
|
|
{
|
|
OnCaptureToggled(false);
|
|
|
|
if (m_data)
|
|
{
|
|
m_AnnotationProvider.Clear();
|
|
// 1: spawn a new local settings object using the DRW
|
|
if (!AZ::IO::SystemFile::Exists(workspaceFileName.toUtf8().data()))
|
|
{
|
|
QMessageBox::warning(this, tr("File not found"), tr("Unable to find the specified file '%1'").arg(workspaceFileName), QMessageBox::Ok, QMessageBox::Ok);
|
|
return;
|
|
}
|
|
|
|
WorkspaceSettingsProvider* provider = WorkspaceSettingsProvider::CreateFromFile(workspaceFileName.toUtf8().data());
|
|
if (!provider)
|
|
{
|
|
QMessageBox::warning(this, tr("Corrupted file?"), tr("Unable to parse the specified file '%1'").arg(workspaceFileName), QMessageBox::Ok, QMessageBox::Ok);
|
|
return;
|
|
}
|
|
|
|
// 2: extract therefrom the associated DRL file
|
|
AZStd::string windowStateStr = AZStd::string::format("DRILLER CAPTURE WINDOW WORKSPACE");
|
|
AZ::u32 workspaceCRC = AZ::Crc32(windowStateStr.c_str());
|
|
|
|
DrillerCaptureWindowWorkspace* workspace = provider->FindSetting<DrillerCaptureWindowWorkspace>(workspaceCRC);
|
|
if (!workspace)
|
|
{
|
|
QMessageBox::warning(this, tr("Corrupted file?"), tr("Specified file '%1' does not appear to contain a workspace.").arg(workspaceFileName), QMessageBox::Ok, QMessageBox::Ok);
|
|
return;
|
|
}
|
|
|
|
m_inactiveChannels.clear();
|
|
for (auto iter = workspace->m_ChannelIDs.begin(); iter != workspace->m_ChannelIDs.end(); ++iter)
|
|
{
|
|
m_inactiveChannels.insert(*iter);
|
|
}
|
|
|
|
// 3: load that data, which in turn clears and re-instantiates all needed aggregators
|
|
// other side effects include changing the current filename and replacing any current data loaded
|
|
if (openDrillerFileAlso)
|
|
{
|
|
m_isLoadingFile = true;
|
|
OnOpenDrillerFileForWorkspace(QString(workspace->m_matchingDataFileName.c_str()), workspaceFileName);
|
|
m_isLoadingFile = false;
|
|
}
|
|
|
|
SetCaptureMode(CaptureMode::Inspecting);
|
|
|
|
// 4: extract from the DRW any settings that I have saved there
|
|
// 5: synchronous EBUS message that informs all the aggregators that new settings are available
|
|
EBUS_EVENT_ID(m_identity, Driller::DrillerWorkspaceWindowMessages::Bus, ApplySettingsFromWorkspace, provider);
|
|
m_AnnotationProvider.LoadSettingsFromWorkspace(provider);
|
|
|
|
// 6: aggregators are responsible for checking if any of their data dialogs are required, and open them
|
|
|
|
EBUS_EVENT_ID(m_identity, Driller::DrillerWorkspaceWindowMessages::Bus, ActivateWorkspaceSettings, provider);
|
|
|
|
// 7: main window itself should load its settings, which will include the current scrubber frame
|
|
m_scrubberCurrentFrame = 0;
|
|
m_scrubberCurrentEvent = 0;
|
|
m_playbackLoopBegin = 0;
|
|
m_playbackLoopEnd = 0;
|
|
|
|
SetFrameRangeBegin(workspace->m_frameRangeBegin);
|
|
SetFrameRangeEnd(workspace->m_frameRangeEnd);
|
|
m_bForceNextScrub = true;
|
|
SetScrubberFrame(workspace->m_scrubberCurrentFrame);
|
|
SetPlaybackLoopBegin(workspace->m_playbackLoopBegin);
|
|
SetPlaybackLoopEnd(workspace->m_playbackLoopEnd);
|
|
OnQuantMenuFinal(workspace->m_visibleFrames);
|
|
m_gui->controlScrollBar->setSliderPosition(workspace->m_sliderPosition);
|
|
|
|
SetScrubberEvent(workspace->m_scrubberCurrentEvent);
|
|
|
|
// 8: close the local settings DRW
|
|
delete provider;
|
|
|
|
RepopulateAnnotations();
|
|
}
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnApplyWorkspaceFile(QString fileName)
|
|
{
|
|
if (!fileName.isNull())
|
|
{
|
|
if (m_data)
|
|
{
|
|
OnOpenWorkspaceFile(fileName, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnSaveWorkspaceFile(QString fileName, bool automated)
|
|
{
|
|
if (!fileName.isNull())
|
|
{
|
|
if (m_data)
|
|
{
|
|
// 1: spawn a new local settings object using the DRW
|
|
WorkspaceSettingsProvider provider;
|
|
|
|
// 2: push my own settings into the DRW
|
|
// plus logic to copy/rename tmp DRL files
|
|
AZStd::string windowStateStr = AZStd::string::format("DRILLER CAPTURE WINDOW WORKSPACE");
|
|
AZ::u32 workspaceCRC = AZ::Crc32(windowStateStr.c_str());
|
|
|
|
DrillerCaptureWindowWorkspace* workspace = provider.CreateSetting<DrillerCaptureWindowWorkspace>(workspaceCRC);
|
|
if (!automated)
|
|
{
|
|
m_currentDataFilename = PrepDataFileForSaving(m_currentDataFilename, fileName);
|
|
}
|
|
workspace->m_matchingDataFileName = m_currentDataFilename.toUtf8().data();
|
|
|
|
m_inactiveChannels.clear();
|
|
for (ChannelControl* channelControl : m_channels)
|
|
{
|
|
for (ChannelProfilerWidget* profilerWidget : channelControl->GetProfilers())
|
|
{
|
|
if (!profilerWidget->IsActive())
|
|
{
|
|
m_inactiveChannels.insert(profilerWidget->GetID());
|
|
}
|
|
}
|
|
}
|
|
|
|
workspace->m_ChannelIDs.clear();
|
|
for (AZStd::set<AZ::Uuid>::iterator iter = m_inactiveChannels.begin(); iter != m_inactiveChannels.end(); ++iter)
|
|
{
|
|
workspace->m_ChannelIDs.push_back(*iter);
|
|
}
|
|
workspace->m_scrubberCurrentFrame = m_scrubberCurrentFrame;
|
|
workspace->m_frameRangeBegin = m_frameRangeBegin;
|
|
workspace->m_frameRangeEnd = m_frameRangeEnd;
|
|
workspace->m_visibleFrames = m_visibleFrames;
|
|
workspace->m_scrubberCurrentEvent = m_scrubberCurrentEvent;
|
|
|
|
workspace->m_playbackLoopBegin = m_playbackLoopBegin;
|
|
workspace->m_playbackLoopEnd = m_playbackLoopEnd;
|
|
workspace->m_sliderPosition = m_gui->controlScrollBar->sliderPosition();
|
|
|
|
// 3: synchronous EBUS message that informs all the aggregators to push their own settings into the DRW
|
|
// 4: aggregators are responsible for dealing with their display view dialogs internally
|
|
EBUS_EVENT_ID(m_identity, Driller::DrillerWorkspaceWindowMessages::Bus, SaveSettingsToWorkspace, &provider);
|
|
m_AnnotationProvider.SaveSettingsToWorkspace(&provider);
|
|
|
|
if (!provider.WriteToFile(fileName.toUtf8().data()))
|
|
{
|
|
SetCaptureDirty(true);
|
|
QMessageBox::warning(this, tr("Could not save workspace"), tr("Unable to write data to the specified file '%1'").arg(fileName), QMessageBox::Ok, QMessageBox::Ok);
|
|
}
|
|
else
|
|
{
|
|
SetCaptureDirty(false);
|
|
}
|
|
UpdateLiveControls();
|
|
}
|
|
}
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnSaveDrillerFile()
|
|
{
|
|
if (m_frameRangeEnd <= 0)
|
|
{
|
|
if (m_identity == 0)
|
|
{
|
|
ResetCaptureControls();
|
|
}
|
|
return;
|
|
}
|
|
|
|
QString saveCapturePath;
|
|
QString tempWorkspaceName;
|
|
|
|
auto newState = AZ::UserSettings::CreateFind<DrillerCaptureWindowSavedState>(m_windowStateCRC, AZ::UserSettings::CT_GLOBAL);
|
|
if (!newState->m_priorSaveFolder.empty())
|
|
{
|
|
saveCapturePath = newState->m_priorSaveFolder.data();
|
|
}
|
|
else
|
|
{
|
|
auto paths = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation);
|
|
|
|
if (paths.isEmpty())
|
|
{
|
|
paths = QStandardPaths::standardLocations(QStandardPaths::TempLocation);
|
|
}
|
|
|
|
if (!paths.isEmpty())
|
|
{
|
|
saveCapturePath = paths.first();
|
|
}
|
|
}
|
|
|
|
bool success = false;
|
|
|
|
while (!success)
|
|
{
|
|
QString sourcename = m_tmpCaptureFilename;
|
|
|
|
if (!m_currentDataFilename.isEmpty())
|
|
{
|
|
sourcename = m_currentDataFilename;
|
|
}
|
|
|
|
QString fileName = QFileDialog::getSaveFileName(this, "Save Driller File As...", saveCapturePath, "Driller Files (*.drl)");
|
|
if (!fileName.isNull())
|
|
{
|
|
SetCaptureDirty(false);
|
|
if (sourcename == fileName)
|
|
{
|
|
QMessageBox::warning(this, tr("Unable to save"), tr("You can't save a data file over itself ( '%1' to '%2' )").arg(sourcename).arg(fileName));
|
|
}
|
|
else
|
|
{
|
|
(void)QFile::remove(fileName);
|
|
success = QFile::copy(sourcename, fileName);
|
|
if (success)
|
|
{
|
|
m_currentDataFilename = fileName;
|
|
|
|
{
|
|
QTemporaryFile f;
|
|
f.setAutoRemove(false);
|
|
if (f.open())
|
|
{
|
|
tempWorkspaceName = f.fileName();
|
|
}
|
|
}
|
|
if (!tempWorkspaceName.isEmpty())
|
|
{
|
|
OnSaveWorkspaceFile(tempWorkspaceName, true);
|
|
}
|
|
|
|
ResetCaptureControls();
|
|
|
|
EBUS_EVENT(Driller::DrillerDataViewMessages::Bus, EventRequestOpenWorkspace, tempWorkspaceName.toUtf8().data());
|
|
auto deleteResult = QFile::remove(tempWorkspaceName);
|
|
if (!deleteResult)
|
|
{
|
|
QMessageBox::warning(this, tr("Can't delete temp file"), tr("File = ( %1 )").arg(tempWorkspaceName));
|
|
}
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
QMessageBox::warning(this, tr("Unable to save"), tr("Could not copy '%1' to '%2'").arg(sourcename).arg(fileName));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fileName.isNull() || m_identity == 0) // close this window if no file named OR this is a LIVE channel
|
|
{
|
|
ResetCaptureControls();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
QString DrillerCaptureWindow::PrepDataFileForSaving(QString filename, QString workspaceName)
|
|
{
|
|
// is this a TMP file?
|
|
QString tempPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
|
|
if (filename.contains(tempPath, Qt::CaseInsensitive))
|
|
{
|
|
// yes := rename to match workspace
|
|
QString newFilename(workspaceName.left(workspaceName.size() - 3) + "drl");
|
|
// and then copy
|
|
QFile::copy(filename, newFilename);
|
|
m_currentDataFilename = newFilename;
|
|
UpdateLiveControls();
|
|
return newFilename;
|
|
}
|
|
|
|
return filename;
|
|
}
|
|
|
|
QString DrillerCaptureWindow::PrepTempFile(QString filename)
|
|
{
|
|
QString tmpCapturePath = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
|
|
tmpCapturePath = QDir(tmpCapturePath).absoluteFilePath(filename);
|
|
m_tmpCaptureFilename = tmpCapturePath;
|
|
m_currentDataFilename = m_tmpCaptureFilename;
|
|
return tmpCapturePath;
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnAnnotationOptionsClick()
|
|
{
|
|
// show the annotations configure window:
|
|
if (m_ptrConfigureAnnotationsWindow)
|
|
{
|
|
m_ptrConfigureAnnotationsWindow->raise();
|
|
}
|
|
else
|
|
{
|
|
m_ptrConfigureAnnotationsWindow = aznew ConfigureAnnotationsWindow(this);
|
|
m_ptrConfigureAnnotationsWindow->Initialize(&m_AnnotationProvider);
|
|
connect(m_ptrConfigureAnnotationsWindow, SIGNAL(destroyed(QObject*)), this, SLOT(OnAnnotationsDialogDestroyed()));
|
|
m_ptrConfigureAnnotationsWindow->show();
|
|
}
|
|
}
|
|
|
|
void DrillerCaptureWindow::OnSelectedAnnotationChannelsChanged()
|
|
{
|
|
// rebuild the annotations.
|
|
RepopulateAnnotations();
|
|
// update the views.
|
|
}
|
|
|
|
|
|
void DrillerCaptureWindow::OnAnnotationsDialogDestroyed()
|
|
{
|
|
m_ptrConfigureAnnotationsWindow = NULL;
|
|
}
|
|
|
|
void DrillerCaptureWindow::InformOfMouseOverAnnotation(const Annotation& annotation)
|
|
{
|
|
if (m_collectedAnnotations.empty())
|
|
{
|
|
QTimer::singleShot(0, this, SLOT(CommitAnnotationsCollected()));
|
|
}
|
|
m_collectedAnnotations.push_back(annotation);
|
|
}
|
|
|
|
void DrillerCaptureWindow::CommitAnnotationsCollected()
|
|
{
|
|
FrameNumberType frameCounter = -1;
|
|
QString finalText;
|
|
AZ::u32 priorCRC = 0;
|
|
|
|
AZStd::sort(m_collectedAnnotations.begin(), m_collectedAnnotations.end(),
|
|
[](const Annotation& first, const Annotation& second)
|
|
{
|
|
return first.GetEventIndex() < second.GetEventIndex();
|
|
}
|
|
);
|
|
|
|
int numConcated = 0;
|
|
for (auto iter = m_collectedAnnotations.begin(); iter != m_collectedAnnotations.end(); ++iter)
|
|
{
|
|
if (numConcated > 10)
|
|
{
|
|
int numRemaining = (int)m_collectedAnnotations.size() - numConcated;
|
|
finalText += QString("... and %1 other annotations").arg(numRemaining);
|
|
break;
|
|
}
|
|
++numConcated;
|
|
|
|
const Annotation& annot = *iter;
|
|
if ((annot.GetFrameIndex() == frameCounter) && (priorCRC == annot.GetChannelCRC()))
|
|
{
|
|
finalText += QString("Event %1: '%2'<BR>").arg(annot.GetEventIndex()).arg(annot.GetText().c_str());
|
|
}
|
|
else if (annot.GetFrameIndex() == frameCounter)
|
|
{
|
|
finalText += QString("<I>%2</I><BR>Event %3: '%4'<BR>").arg(annot.GetChannel().c_str()).arg(annot.GetEventIndex()).arg(annot.GetText().c_str());
|
|
}
|
|
else
|
|
{
|
|
finalText += QString("<B>Frame %1</B><BR><I>%2</I><BR>Event %3: '%4'<BR>").arg(annot.GetFrameIndex()).arg(annot.GetChannel().c_str()).arg(annot.GetEventIndex()).arg(annot.GetText().c_str());
|
|
}
|
|
|
|
frameCounter = annot.GetFrameIndex();
|
|
priorCRC = annot.GetChannelCRC();
|
|
}
|
|
|
|
QToolTip::showText(QCursor::pos(), finalText);
|
|
m_collectedAnnotations.clear();
|
|
}
|
|
|
|
void DrillerCaptureWindow::InformOfClickAnnotation(const Annotation& annotation)
|
|
{
|
|
(void)annotation;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Target Manager Messages
|
|
void DrillerCaptureWindow::DesiredTargetConnected(bool connected)
|
|
{
|
|
m_TargetConnected = connected;
|
|
|
|
if (IsInCaptureMode(CaptureMode::Inspecting))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// - have an existing capture?
|
|
// - - ask to save it
|
|
if (IsInCaptureMode(CaptureMode::Capturing))
|
|
{
|
|
OnSaveDrillerFile();
|
|
}
|
|
|
|
QString tmpCapturePath;
|
|
|
|
if (connected)
|
|
{
|
|
SetScrubberFrame(0);
|
|
SetFrameRangeBegin(0);
|
|
SetFrameRangeEnd(0);
|
|
SetCaptureDirty(false);
|
|
|
|
tmpCapturePath = PrepTempFile(baseTempFileName);
|
|
}
|
|
else
|
|
{
|
|
SetScrubberFrame(0);
|
|
SetFrameRangeBegin(0);
|
|
SetFrameRangeEnd(0);
|
|
SetCaptureDirty(false);
|
|
|
|
m_gui->captureButton->setEnabled(false);
|
|
m_gui->captureButton->setText(tr("Capture"));
|
|
m_gui->captureButton->setToolTip(tr("Begin Capturing Driller Data"));
|
|
|
|
tmpCapturePath.clear();
|
|
}
|
|
|
|
UpdateLiveControls();
|
|
}
|
|
|
|
void DrillerCaptureWindow::Reflect(AZ::ReflectContext* context)
|
|
{
|
|
// data container is the one place that knows about all the aggregators
|
|
// and indeed is responsible for creating them
|
|
DrillerDataContainer::Reflect(context);
|
|
DrillerCaptureWindowWorkspace::Reflect(context);
|
|
DrillerCaptureWindowSavedState::Reflect(context);
|
|
AnnotationsProvider::Reflect(context);
|
|
|
|
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
|
|
if (behaviorContext)
|
|
{
|
|
behaviorContext->Class<DrillerCaptureWindow>("DrillerCaptureWindow")->
|
|
Method("ShowWindow", &DrillerCaptureWindow::OnOpen)->
|
|
Method("HideWindow", &DrillerCaptureWindow::OnClose);
|
|
}
|
|
}
|
|
}//namespace Driller
|