]> git.cworth.org Git - apitrace/blobdiff - gui/graphing/heatmapview.cpp
Rewrote profile graph drawing code.
[apitrace] / gui / graphing / heatmapview.cpp
diff --git a/gui/graphing/heatmapview.cpp b/gui/graphing/heatmapview.cpp
new file mode 100644 (file)
index 0000000..9bb485c
--- /dev/null
@@ -0,0 +1,276 @@
+#include "heatmapview.h"
+
+#include <qmath.h>
+#include <QToolTip>
+#include <QPainter>
+#include <QMouseEvent>
+
+HeatmapView::HeatmapView(QWidget* parent) :
+    GraphView(parent),
+    m_data(NULL)
+{
+    m_rowHeight = 20;
+    setMouseTracking(true);
+}
+
+
+void HeatmapView::setDataProvider(HeatmapDataProvider* data)
+{
+    delete m_data;
+    m_data = data;
+
+    if (m_data) {
+        m_data->setSelectionState(m_selectionState);
+
+        setDefaultView(m_data->start(), m_data->end());
+
+        m_viewWidthMin = 1000;
+
+        m_graphBottom = 0;
+        m_graphTop = (m_data->headerRows() + m_data->dataRows()) * m_rowHeight;
+    } else {
+        setDefaultView(0, 0);
+        m_graphBottom = m_graphTop = 0;
+    }
+
+    update();
+}
+
+
+void HeatmapView::setSelectionState(SelectionState* state)
+{
+    if (m_data) {
+        m_data->setSelectionState(state);
+    }
+
+    GraphView::setSelectionState(state);
+}
+
+
+void HeatmapView::mouseMoveEvent(QMouseEvent *e)
+{
+    GraphView::mouseMoveEvent(e);
+
+    if (e->buttons() || !m_data) {
+        QToolTip::hideText();
+        return;
+    }
+
+    qint64 index = itemAtPosition(e->pos());
+
+    if (index >= 0) {
+        QToolTip::showText(e->globalPos(), m_data->itemTooltip(index));
+    } else {
+        QToolTip::hideText();
+    }
+}
+
+
+void HeatmapView::mouseDoubleClickEvent(QMouseEvent *e)
+{
+    if (m_data && e->button() == Qt::LeftButton) {
+        qint64 index = itemAtPosition(e->pos());
+
+        if (index >= 0) {
+            m_data->itemDoubleClicked(index);
+            return;
+        }
+    }
+
+    GraphView::mouseDoubleClickEvent(e);
+}
+
+
+void HeatmapView::paintEvent(QPaintEvent *)
+{
+    if (!m_data) {
+        return;
+    }
+
+    QPainter painter(this);
+    painter.fillRect(0, m_data->headerRows() * m_rowHeight, width(), height(), Qt::white);
+
+    /* Draw data rows */
+    painter.translate(0, m_data->headerRows() * m_rowHeight - m_viewBottom % m_rowHeight);
+    int rowStart = m_viewBottom / m_rowHeight;
+    int rowEnd = qMin<int>(qCeil(m_viewTop / (double)m_rowHeight), m_data->dataRows());
+
+    for (unsigned i = rowStart; i < rowEnd; ++i) {
+        HeatmapRowIterator* itr = m_data->dataRowIterator(i, m_viewLeft, m_viewRight, width());
+        paintRow(painter, itr);
+        painter.translate(0, m_rowHeight);
+        delete itr;
+    }
+
+    /* Draw Header */
+    painter.resetTransform();
+    painter.fillRect(0, 0, width(), m_data->headerRows() * m_rowHeight, Qt::white);
+
+    for (unsigned i = 0; i < m_data->headerRows(); ++i) {
+        HeatmapRowIterator* itr = m_data->headerRowIterator(i, m_viewLeft, m_viewRight, width());
+        paintRow(painter, itr);
+        painter.translate(0, m_rowHeight);
+        delete itr;
+    }
+
+    /* Draw Axis Lines */
+    painter.resetTransform();
+    painter.setPen(Qt::black);
+    painter.drawLine(0, m_rowHeight, width(), m_rowHeight);
+    painter.drawLine(0, m_rowHeight * 2, width(), m_rowHeight * 2);
+
+    painter.setPen(QColor(240, 240, 240));
+    painter.translate(0, m_data->headerRows() * m_rowHeight - m_viewBottom % m_rowHeight);
+
+    for (unsigned i = rowStart; i < rowEnd; ++i) {
+        painter.drawLine(0, m_rowHeight, width(), m_rowHeight);
+        painter.translate(0, m_rowHeight);
+    }
+
+    /* Draw selection borders */
+    painter.resetTransform();
+    painter.setPen(Qt::green);
+
+    if (m_selectionState->type == SelectionState::Horizontal) {
+        double dxdt = width() / (double)m_viewWidth;
+        double scroll = m_viewLeft * dxdt;
+        double left = (m_selectionState->start * dxdt) - scroll;
+        double right = (m_selectionState->end * dxdt) - scroll;
+
+        /* Highlight time */
+        if (left >= 0 && left <= width()) {
+            painter.drawLine(left, 0, left, height());
+        }
+
+        if (right >= 0 && right <= width()) {
+            painter.drawLine(right, 0, right, height());
+        }
+    } else if (m_selectionState->type == SelectionState::Vertical) {
+        /* Highlight row */
+        int row = m_selectionState->start;
+
+        for (unsigned i = rowStart; i < rowEnd; ++i) {
+            if (m_data->dataRowAt(i) == row) {
+                row = i - rowStart;
+
+                painter.translate(0, m_data->headerRows() * m_rowHeight - m_viewBottom % m_rowHeight);
+                painter.drawLine(0, (row + 1) * m_rowHeight, width(), (row + 1) * m_rowHeight);
+
+                if (row > 0) {
+                    painter.drawLine(0, row * m_rowHeight, width(), row * m_rowHeight);
+                }
+
+                break;
+            }
+        }
+    }
+}
+
+
+void HeatmapView::paintRow(QPainter& painter, HeatmapRowIterator* itr)
+{
+    bool selection = m_selectionState ? m_selectionState->type != SelectionState::None : false;
+
+    while (itr->next())
+    {
+        double heat = itr->heat();
+        int width = itr->width();
+        int x = itr->step();
+
+        /* Gamma correction */
+        heat = qPow(heat, 1.0 / 2.0);
+
+        if (width == 1) {
+            /* Draw single line */
+            if (selection) {
+                double selectedHeat = itr->selectedHeat();
+
+                if (selectedHeat >= 0.999) {
+                    heat = 255.0 - qBound(0.0, heat * 255.0, 255.0);
+
+                    if (itr->isGpu()) {
+                        painter.setPen(QColor(255, heat, heat));
+                    } else {
+                        painter.setPen(QColor(heat, heat, 255));
+                    }
+
+                    painter.drawLine(x, 0, x, m_rowHeight - 1);
+                } else {
+                    heat = 255.0 - qBound(0.0, heat * 100.0, 100.0);
+                    painter.setPen(QColor(heat, heat, heat));
+                    painter.drawLine(x, 0, x, m_rowHeight - 1);
+
+                    if (selectedHeat > 0.001) {
+                        selectedHeat = qPow(selectedHeat, 1.0 / 2.0);
+                        selectedHeat = qBound(0.0, selectedHeat * 255.0, 255.0);
+
+                        if (itr->isGpu()) {
+                            painter.setPen(QColor(255, 0, 0, selectedHeat));
+                        } else {
+                            painter.setPen(QColor(0, 0, 255, selectedHeat));
+                        }
+
+                        painter.drawLine(x, 0, x, m_rowHeight - 1);
+                    }
+                }
+            } else {
+                heat = qBound(0.0, heat * 255.0, 255.0);
+
+                if (itr->isGpu()) {
+                    painter.setPen(QColor(255, 255 - heat, 255 - heat));
+                } else {
+                    painter.setPen(QColor(255 - heat, 255 - heat, 255));
+                }
+
+                painter.drawLine(x, 0, x, m_rowHeight - 1);
+            }
+        } else {
+            double selectedHeat = itr->selectedHeat();
+
+            if (selection && selectedHeat < 0.9) {
+                painter.fillRect(x, 0, width, m_rowHeight, QColor(255 - 100, 255 - 100, 255 - 100));
+            } else if (itr->isGpu()) {
+                painter.fillRect(x, 0, width, m_rowHeight, QColor(255, 0, 0));
+            } else {
+                painter.fillRect(x, 0, width, m_rowHeight, QColor(0, 0, 255));
+            }
+
+            if (width > 6) {
+                painter.setPen(Qt::white);
+                QString elided = painter.fontMetrics().elidedText(itr->label(), Qt::ElideRight, width - 1);
+
+                painter.drawText(x + 1, 0, width - 1, m_rowHeight - 1,
+                                 Qt::AlignLeft | Qt::AlignVCenter,
+                                 elided);
+            }
+        }
+    }
+}
+
+
+qint64 HeatmapView::itemAtPosition(QPoint pos)
+{
+    if (!m_data) {
+        return -1;
+    }
+
+    double t = m_viewWidth / (double)width();
+    t *= pos.x();
+    t += m_viewLeft;
+
+    qint64 time = (qint64)t;
+    qint64 index;
+
+    if (pos.y() < m_data->headerRows() * m_rowHeight) {
+        int row = pos.y() / m_rowHeight;
+        index = m_data->headerItemAt(row, time);
+    } else {
+        int row = pos.y();
+        row -= m_data->headerRows() * m_rowHeight;
+        row += m_viewBottom;
+        row /= m_rowHeight;
+        index = m_data->dataItemAt(row, time);
+    }
+
+    return index;
+}