diff --git a/qrenderdoc/Code/Core.h b/qrenderdoc/Code/Core.h index d01e59b2a..0b60097be 100644 --- a/qrenderdoc/Code/Core.h +++ b/qrenderdoc/Code/Core.h @@ -219,4 +219,19 @@ class LambdaThread : public QObject bool isRunning() { return m_Thread->isRunning(); } }; +// useful delegate for enforcing a given size +#include + +class SizeDelegate : public QItemDelegate +{ + private: + Q_OBJECT + + QSize m_Size; + public: + SizeDelegate(QSize size) : m_Size(size) {} + + QSize sizeHint(const QStyleOptionViewItem &option,const QModelIndex &index) const { return m_Size; } +}; + #endif // CORE_H diff --git a/qrenderdoc/Windows/EventBrowser.cpp b/qrenderdoc/Windows/EventBrowser.cpp index 8e6a22f21..ff7e940b0 100644 --- a/qrenderdoc/Windows/EventBrowser.cpp +++ b/qrenderdoc/Windows/EventBrowser.cpp @@ -1,29 +1,20 @@ #include "EventBrowser.h" #include "ui_EventBrowser.h" +#include + #include "Code/Core.h" enum { COL_NAME = 0, COL_EID = 1, COL_DURATION = 2, + + COL_CURRENT, + COL_FIND, + COL_BOOKMARK, }; -uint AddDrawcalls(QTreeWidgetItem *parent, const rdctype::array &draws) -{ - uint lastEID = 0; - - for(int32_t i = 0; i < draws.count; i++) - { - QTreeWidgetItem *child = new QTreeWidgetItem(parent, QStringList{ QString(draws[i].name.elems), QString("%1").arg(draws[i].eventID), "0.0" }); - lastEID = AddDrawcalls(child, draws[i].children); - if(lastEID == 0) lastEID = draws[i].eventID; - child->setData(COL_EID, Qt::UserRole, QVariant(lastEID)); - } - - return lastEID; -} - EventBrowser::EventBrowser(Core *core, QWidget *parent) : QFrame(parent), ui(new Ui::EventBrowser), @@ -47,19 +38,32 @@ m_Core(core) // becomes quickly infuriating to rearrange, just disable until that can be fixed. ui->events->header()->setSectionsMovable(false); - QObject::connect(ui->closeFind, &QToolButton::clicked, this, &EventBrowser::hideFindJump); - QObject::connect(ui->closeJump, &QToolButton::clicked, this, &EventBrowser::hideFindJump); - QObject::connect(ui->jumpToEID, &LineEditFocusWidget::leave, this, &EventBrowser::hideFindJump); - QObject::connect(ui->findEvent, &LineEditFocusWidget::leave, this, &EventBrowser::hideFindJump); + m_SizeDelegate = new SizeDelegate(QSize(0, 16)); + ui->events->setItemDelegate(m_SizeDelegate); + + m_FindHighlight = new QTimer(this); + m_FindHighlight->setInterval(400); + m_FindHighlight->setSingleShot(true); + connect(m_FindHighlight, SIGNAL(timeout()), this, SLOT(on_findHighlight_timeout())); + + QObject::connect(ui->closeFind, &QToolButton::clicked, this, &EventBrowser::on_HideFindJump); + QObject::connect(ui->closeJump, &QToolButton::clicked, this, &EventBrowser::on_HideFindJump); + QObject::connect(ui->jumpToEID, &LineEditFocusWidget::leave, this, &EventBrowser::on_HideFindJump); + QObject::connect(ui->findEvent, &LineEditFocusWidget::leave, this, &EventBrowser::on_HideFindJump); ui->jumpStrip->hide(); ui->findStrip->hide(); ui->bookmarkStrip->hide(); + + m_CurrentIcon.addFile(QStringLiteral(":/Resources/flag_green.png"), QSize(), QIcon::Normal, QIcon::Off); + m_FindIcon.addFile(QStringLiteral(":/Resources/find.png"), QSize(), QIcon::Normal, QIcon::Off); + m_BookmarkIcon.addFile(QStringLiteral(":/Resources/asterisk_orange.png"), QSize(), QIcon::Normal, QIcon::Off); } EventBrowser::~EventBrowser() { m_Core->RemoveLogViewer(this); delete ui; + delete m_SizeDelegate; } void EventBrowser::OnLogfileLoaded() @@ -68,6 +72,9 @@ void EventBrowser::OnLogfileLoaded() QTreeWidgetItem *framestart = new QTreeWidgetItem(frame, QStringList{ "Frame Start", "0", "" }); framestart->setData(COL_EID, Qt::UserRole, QVariant(0)); + framestart->setData(COL_CURRENT, Qt::UserRole, QVariant(false)); + framestart->setData(COL_FIND, Qt::UserRole, QVariant(false)); + framestart->setData(COL_BOOKMARK, Qt::UserRole, QVariant(false)); uint lastEID = AddDrawcalls(frame, m_Core->CurDrawcalls(0)); frame->setData(COL_EID, Qt::UserRole, QVariant(lastEID)); @@ -84,33 +91,28 @@ void EventBrowser::OnLogfileClosed() void EventBrowser::OnEventSelected(uint32_t frameID, uint32_t eventID) { - + SelectEvent(frameID, eventID); } -void EventBrowser::on_find_clicked() +uint EventBrowser::AddDrawcalls(QTreeWidgetItem *parent, const rdctype::array &draws) { - ui->jumpStrip->hide(); - ui->findStrip->show(); - ui->bookmarkStrip->hide(); - ui->findEvent->setFocus(); + uint lastEID = 0; + + for(int32_t i = 0; i < draws.count; i++) + { + QTreeWidgetItem *child = new QTreeWidgetItem(parent, QStringList{ QString(draws[i].name.elems), QString("%1").arg(draws[i].eventID), "0.0" }); + lastEID = AddDrawcalls(child, draws[i].children); + if(lastEID == 0) lastEID = draws[i].eventID; + child->setData(COL_EID, Qt::UserRole, QVariant(lastEID)); + child->setData(COL_CURRENT, Qt::UserRole, QVariant(false)); + child->setData(COL_FIND, Qt::UserRole, QVariant(false)); + child->setData(COL_BOOKMARK, Qt::UserRole, QVariant(false)); + } + + return lastEID; } -void EventBrowser::on_gotoEID_clicked() -{ - ui->jumpStrip->show(); - ui->findStrip->hide(); - ui->bookmarkStrip->hide(); - ui->jumpToEID->setFocus(); -} - -void EventBrowser::on_toolButton_clicked() -{ - ui->jumpStrip->hide(); - ui->findStrip->hide(); - ui->bookmarkStrip->show(); -} - -static void SetDrawcallTimes(QTreeWidgetItem *node, const rdctype::array &results) +void EventBrowser::SetDrawcallTimes(QTreeWidgetItem *node, const rdctype::array &results) { if(node == NULL) return; @@ -150,6 +152,29 @@ static void SetDrawcallTimes(QTreeWidgetItem *node, const rdctype::arraysetData(COL_DURATION, Qt::UserRole, QVariant(duration)); } +void EventBrowser::on_find_clicked() +{ + ui->jumpStrip->hide(); + ui->findStrip->show(); + ui->bookmarkStrip->hide(); + ui->findEvent->setFocus(); +} + +void EventBrowser::on_gotoEID_clicked() +{ + ui->jumpStrip->show(); + ui->findStrip->hide(); + ui->bookmarkStrip->hide(); + ui->jumpToEID->setFocus(); +} + +void EventBrowser::on_toolButton_clicked() +{ + ui->jumpStrip->hide(); + ui->findStrip->hide(); + ui->bookmarkStrip->show(); +} + void EventBrowser::on_timeDraws_clicked() { m_Core->Renderer()->AsyncInvoke([this](IReplayRenderer *r) { @@ -166,32 +191,311 @@ void EventBrowser::on_timeDraws_clicked() }); } -void EventBrowser::on_events_itemSelectionChanged() +void EventBrowser::on_events_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous) { - if(ui->events->selectedItems().empty()) return; + if(previous) + { + previous->setData(COL_CURRENT, Qt::UserRole, QVariant(false)); + RefreshIcon(previous); + } - uint EID = ui->events->selectedItems()[0]->data(COL_EID, Qt::UserRole).toUInt(); + if(!current) return; + + current->setData(COL_CURRENT, Qt::UserRole, QVariant(true)); + RefreshIcon(current); + + uint EID = current->data(COL_EID, Qt::UserRole).toUInt(); m_Core->SetEventID(this, 0, EID); } -void EventBrowser::hideFindJump() +void EventBrowser::on_HideFindJump() { ui->jumpStrip->hide(); ui->findStrip->hide(); + + ui->jumpToEID->setText(""); + + ClearFindIcons(); + ui->findEvent->setText(""); + ui->findEvent->setStyleSheet(""); } void EventBrowser::on_jumpToEID_returnPressed() { bool ok = false; - uint eid = ui->findEvent->text().toUInt(&ok); + uint eid = ui->jumpToEID->text().toUInt(&ok); if(ok) { - //SelectEvent(0, eid); + SelectEvent(m_Core->CurFrame(), eid); } } +void EventBrowser::on_findHighlight_timeout() +{ + ClearFindIcons(); + + int results = SetFindIcons(ui->findEvent->text()); + + if(results > 0) + ui->findEvent->setStyleSheet(""); + else + ui->findEvent->setStyleSheet("QLineEdit{background-color:#ff0000;}"); +} + +void EventBrowser::on_findEvent_textEdited(const QString &arg1) +{ + if(arg1.isEmpty()) + { + m_FindHighlight->stop(); + + ui->findEvent->setStyleSheet(""); + ClearFindIcons(); + } + else + { + m_FindHighlight->start(); // restart + } +} + + void EventBrowser::on_findEvent_returnPressed() { + if(m_FindHighlight->isActive()) + { + // manually fire it instantly + m_FindHighlight->stop(); + on_findHighlight_timeout(); + } + if(!ui->findEvent->text().isEmpty()) + { + Find(true); + } +} + +void EventBrowser::on_findNext_clicked() +{ + Find(true); +} + +void EventBrowser::on_findPrev_clicked() +{ + Find(false); +} + +void EventBrowser::RefreshIcon(QTreeWidgetItem *item) +{ + if(item->data(COL_CURRENT, Qt::UserRole).toBool()) + item->setIcon(COL_NAME, m_CurrentIcon); + else if(item->data(COL_FIND, Qt::UserRole).toBool()) + item->setIcon(COL_NAME, m_FindIcon); + else if(item->data(COL_BOOKMARK, Qt::UserRole).toBool()) + item->setIcon(COL_NAME, m_BookmarkIcon); + else + item->setIcon(COL_NAME, QIcon()); +} + +bool EventBrowser::FindEventNode(QTreeWidgetItem *&found, QTreeWidgetItem *parent, uint32_t frameID, uint32_t eventID) +{ + for(int i=0; i < parent->childCount(); i++) + { + QTreeWidgetItem *n = parent->child(i); + + uint nEID = n->data(COL_EID, Qt::UserRole).toUInt(); + uint fEID = found ? found->data(COL_EID, Qt::UserRole).toUInt() : 0; + + if(nEID >= eventID && (found == NULL || nEID <= fEID)) + found = n; + + if(nEID == eventID && n->childCount() == 0) + return true; + + if(n->childCount() > 0) + { + bool exact = FindEventNode(found, n, frameID, eventID); + if(exact) return true; + } + } + + return false; +} + +void EventBrowser::ExpandNode(QTreeWidgetItem *node) +{ + QTreeWidgetItem *n = node; + while(node != NULL) + { + node->setExpanded(true); + node = node->parent(); + } + + if(n) + ui->events->scrollToItem(n); +} + +bool EventBrowser::SelectEvent(uint32_t frameID, uint32_t eventID) +{ + if(!m_Core->LogLoaded()) + return false; + + QTreeWidgetItem *found = NULL; + FindEventNode(found, ui->events->topLevelItem(0), frameID, eventID); + if(found != NULL) + { + ui->events->clearSelection(); + ui->events->setItemSelected(found, true); + ui->events->setCurrentItem(found); + + ExpandNode(found); + return true; + } + + return false; +} + +void EventBrowser::ClearFindIcons(QTreeWidgetItem *parent) +{ + for(int i=0; i < parent->childCount(); i++) + { + QTreeWidgetItem *n = parent->child(i); + + n->setData(COL_FIND, Qt::UserRole, QVariant(false)); + RefreshIcon(n); + + if(n->childCount() > 0) + ClearFindIcons(n); + } +} + +void EventBrowser::ClearFindIcons() +{ + if(m_Core->LogLoaded()) + ClearFindIcons(ui->events->topLevelItem(0)); +} + +int EventBrowser::SetFindIcons(QTreeWidgetItem *parent, QString filter) +{ + int results = 0; + + for(int i=0; i < parent->childCount(); i++) + { + QTreeWidgetItem *n = parent->child(i); + + if(n->text(COL_NAME).contains(filter, Qt::CaseInsensitive)) + { + n->setData(COL_FIND, Qt::UserRole, QVariant(true)); + RefreshIcon(n); + results++; + } + + if(n->childCount() > 0) + { + results += SetFindIcons(n, filter); + } + } + + return results; +} + +int EventBrowser::SetFindIcons(QString filter) +{ + if(filter.isEmpty()) + return 0; + + return SetFindIcons(ui->events->topLevelItem(0), filter); +} + +QTreeWidgetItem *EventBrowser::FindNode(QTreeWidgetItem *parent, QString filter, uint32_t after) +{ + for(int i=0; i < parent->childCount(); i++) + { + QTreeWidgetItem *n = parent->child(i); + + uint eid = n->data(COL_EID, Qt::UserRole).toUInt(); + + if(eid > after && n->text(COL_NAME).contains(filter, Qt::CaseInsensitive)) + return n; + + if(n->childCount() > 0) + { + QTreeWidgetItem *found = FindNode(n, filter, after); + + if(found != NULL) + return found; + } + } + + return NULL; +} + +int EventBrowser::FindEvent(QTreeWidgetItem *parent, QString filter, uint32_t after, bool forward) +{ + if(parent == NULL) return -1; + + for(int i = forward ? 0 : parent->childCount() - 1; + i >= 0 && i < parent->childCount(); + i += forward ? 1 : -1) + { + auto n = parent->child(i); + + uint eid = n->data(COL_EID, Qt::UserRole).toUInt(); + + bool matchesAfter = (forward && eid > after) || (!forward && eid < after); + + if(matchesAfter) + { + QString name = n->text(COL_NAME); + if(name.contains(filter, Qt::CaseInsensitive)) + return (int)eid; + } + + if(n->childCount() > 0) + { + int found = FindEvent(n, filter, after, forward); + + if(found > 0) + return found; + } + } + + return -1; +} + +int EventBrowser::FindEvent(QString filter, uint32_t after, bool forward) +{ + if(!m_Core->LogLoaded()) + return 0; + + return FindEvent(ui->events->topLevelItem(0), filter, after, forward); +} + +void EventBrowser::Find(bool forward) +{ + if(ui->findEvent->text().isEmpty()) + return; + + uint32_t curEID = m_Core->CurEvent(); + if(!ui->events->selectedItems().isEmpty()) + curEID = ui->events->selectedItems()[0]->data(COL_EID, Qt::UserRole).toUInt(); + + int eid = FindEvent(ui->findEvent->text(), curEID, forward); + if(eid >= 0) + { + SelectEvent(0, (uint32_t)eid); + ui->findEvent->setStyleSheet(""); + } + else // if(WrapSearch) + { + eid = FindEvent(ui->findEvent->text(), forward ? 0 : ~0U, forward); + if(eid >= 0) + { + SelectEvent(0, (uint32_t)eid); + ui->findEvent->setStyleSheet(""); + } + else + { + ui->findEvent->setStyleSheet("QLineEdit{background-color:#ff0000;}"); + } + } } diff --git a/qrenderdoc/Windows/EventBrowser.h b/qrenderdoc/Windows/EventBrowser.h index ec5b31461..748c3f6e7 100644 --- a/qrenderdoc/Windows/EventBrowser.h +++ b/qrenderdoc/Windows/EventBrowser.h @@ -2,6 +2,7 @@ #define EVENTBROWSER_H #include +#include #include "Code/Core.h" @@ -9,6 +10,9 @@ namespace Ui { class EventBrowser; } +class QTreeWidgetItem; +class QTimer; + class EventBrowser : public QFrame, public ILogViewerForm { private: @@ -27,19 +31,55 @@ class EventBrowser : public QFrame, public ILogViewerForm void on_gotoEID_clicked(); - void on_events_itemSelectionChanged(); - void on_timeDraws_clicked(); void on_toolButton_clicked(); - void hideFindJump(); + void on_HideFindJump(); void on_jumpToEID_returnPressed(); void on_findEvent_returnPressed(); + void on_findEvent_textEdited(const QString &arg1); + + void on_events_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); + + void on_findNext_clicked(); + + void on_findPrev_clicked(); + + void on_findHighlight_timeout(); + private: + uint AddDrawcalls(QTreeWidgetItem *parent, const rdctype::array &draws); + void SetDrawcallTimes(QTreeWidgetItem *node, const rdctype::array &results); + + void ExpandNode(QTreeWidgetItem *node); + + bool FindEventNode(QTreeWidgetItem *&found, QTreeWidgetItem *parent, uint32_t frameID, uint32_t eventID); + bool SelectEvent(uint32_t frameID, uint32_t eventID); + + void ClearFindIcons(QTreeWidgetItem *parent); + void ClearFindIcons(); + + int SetFindIcons(QTreeWidgetItem *parent, QString filter); + int SetFindIcons(QString filter); + + QTreeWidgetItem *FindNode(QTreeWidgetItem *parent, QString filter, uint32_t after); + int FindEvent(QTreeWidgetItem *parent, QString filter, uint32_t after, bool forward); + int FindEvent(QString filter, uint32_t after, bool forward); + void Find(bool forward); + + QIcon m_CurrentIcon; + QIcon m_FindIcon; + QIcon m_BookmarkIcon; + + SizeDelegate *m_SizeDelegate; + QTimer *m_FindHighlight; + + void RefreshIcon(QTreeWidgetItem *item); + Ui::EventBrowser *ui; Core *m_Core; }; diff --git a/qrenderdoc/Windows/EventBrowser.ui b/qrenderdoc/Windows/EventBrowser.ui index cb68cde43..85b987f87 100644 --- a/qrenderdoc/Windows/EventBrowser.ui +++ b/qrenderdoc/Windows/EventBrowser.ui @@ -363,7 +363,7 @@ false - + Search String false