]> git.cworth.org Git - apitrace/blobdiff - gui/graphing/histogramview.cpp
Rewrote profile graph drawing code.
[apitrace] / gui / graphing / histogramview.cpp
diff --git a/gui/graphing/histogramview.cpp b/gui/graphing/histogramview.cpp
new file mode 100644 (file)
index 0000000..0b94577
--- /dev/null
@@ -0,0 +1,258 @@
+#include "histogramview.h"
+
+#include <QPen>
+#include <QBrush>
+#include <qmath.h>
+#include <QPainter>
+#include <QToolTip>
+#include <QMouseEvent>
+
+HistogramView::HistogramView(QWidget* parent) :
+    GraphView(parent),
+    m_data(NULL)
+{
+    setMouseTracking(true);
+
+    m_gradientUnselected.setColorAt(0.9, QColor(200, 200, 200));
+    m_gradientUnselected.setColorAt(0.0, QColor(220, 220, 220));
+
+    m_gradientSelected.setColorAt(0.9, QColor(0, 0, 210));
+    m_gradientSelected.setColorAt(0.0, QColor(130, 130, 255));
+}
+
+
+void HistogramView::setDataProvider(GraphDataProvider* data)
+{
+    delete m_data;
+    m_data = data;
+
+    if (m_data) {
+        m_data->setSelectionState(m_selectionState);
+        setDefaultView(0, m_data->size());
+        m_viewWidthMin = 10;
+    } else {
+        setDefaultView(0, 0);
+    }
+}
+
+
+void HistogramView::setSelectionState(SelectionState* state)
+{
+    if (m_data) {
+        m_data->setSelectionState(state);
+    }
+
+    GraphView::setSelectionState(state);
+}
+
+
+void HistogramView::setSelectedGradient(const QLinearGradient& gradient)
+{
+    m_gradientSelected = gradient;
+}
+
+
+void HistogramView::setUnelectedGradient(const QLinearGradient& gradient)
+{
+    m_gradientUnselected = gradient;
+}
+
+
+void HistogramView::mouseMoveEvent(QMouseEvent *e)
+{
+    GraphView::mouseMoveEvent(e);
+
+    if (e->buttons() || !m_data) {
+        QToolTip::hideText();
+        return;
+    }
+
+    qint64 index = itemAtPosition(e->pos());
+    qint64 time = valueAtPosition(e->pos());
+
+    if (m_data->value(index) >= time) {
+        QToolTip::showText(e->globalPos(), m_data->itemTooltip(index));
+    } else {
+        QToolTip::hideText();
+    }
+}
+
+
+void HistogramView::mouseDoubleClickEvent(QMouseEvent *e)
+{
+    if (e->button() == Qt::LeftButton) {
+        qint64 index = itemAtPosition(e->pos());
+        qint64 time = valueAtPosition(e->pos());
+
+        if (m_data->value(index) >= time) {
+            m_data->itemDoubleClicked(index);
+            return;
+        }
+    }
+
+    GraphView::mouseDoubleClickEvent(e);
+}
+
+
+void HistogramView::update()
+{
+    m_graphBottom = 0;
+    m_graphTop = 0;
+
+    if (m_data) {
+        for (qint64 i = m_viewLeft; i < m_viewRight; ++i) {
+            qint64 value = m_data->value(i);
+
+            if (value > m_graphTop) {
+                m_graphTop = value;
+            }
+        }
+    }
+
+    GraphView::update();
+}
+
+
+void HistogramView::resizeEvent(QResizeEvent *)
+{
+    m_gradientSelected.setStart(0, height());
+    m_gradientUnselected.setStart(0, height());
+}
+
+
+/* Draw the histogram
+ *
+ * When the view is zoomed such that there is more than one item occupying a single pixel
+ * the one with the highest value will be displayed.
+ */
+void HistogramView::paintEvent(QPaintEvent *)
+{
+    if (!m_data) {
+        return;
+    }
+
+    QBrush selectedBrush = QBrush(m_gradientSelected);
+    QPen selectedPen = QPen(selectedBrush, 1);
+
+    QBrush unselectedBrush = QBrush(m_gradientUnselected);
+    QPen unselectedPen = QPen(unselectedBrush, 1);
+
+    QPainter painter(this);
+    painter.fillRect(0, 0, width(), height(), Qt::white);
+
+    double dydv = height() / (double)m_graphTop;
+    double dxdv = width() / (double)(m_viewRight - m_viewLeft);
+    bool selection = m_selectionState && m_selectionState->type != SelectionState::None;
+
+    if (dxdv < 1.0) {
+        /* Less than one pixel per item */
+        qint64 longestValue = m_graphBottom;
+        qint64 longestSelected = m_graphBottom;
+        int lastX = 0;
+        double x = 0;
+
+        if (selection) {
+            painter.setPen(unselectedPen);
+        } else {
+            painter.setPen(selectedPen);
+        }
+
+        for (qint64 i = m_viewLeft; i < m_viewRight; ++i) {
+            qint64 value = m_data->value(i);
+            int ix;
+
+            if (value > longestValue) {
+                longestValue = value;
+            }
+
+            if (selection && m_data->selected(i) && value > longestSelected) {
+                longestSelected = value;
+            }
+
+            x += dxdv;
+            ix = (int)x;
+
+            if (lastX != ix) {
+                painter.drawLine(lastX, height(), lastX, height() - (longestValue * dydv));
+
+                if (selection && longestSelected > m_graphBottom) {
+                    painter.setPen(selectedPen);
+                    painter.drawLine(lastX, height(), lastX, height() - (longestSelected * dydv));
+                    painter.setPen(unselectedPen);
+                    longestSelected = m_graphBottom;
+                }
+
+                longestValue = m_graphBottom;
+                lastX = ix;
+            }
+        }
+    } else {
+        /* Draw rectangles for graph */
+        double x = 0;
+
+        for (qint64 i = m_viewLeft; i < m_viewRight; ++i, x += dxdv) {
+            qint64 value = m_data->value(i);
+            int y = qMax<int>(1, value * dydv);
+
+            if (!selection || m_data->selected(i)) {
+                painter.fillRect(x, height() - y, dxdv, y, selectedBrush);
+            } else {
+                painter.fillRect(x, height() - y, dxdv, y, unselectedBrush);
+            }
+        }
+    }
+
+    /* Draw the borders for the selection */
+    if (m_selectionState && 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;
+
+        painter.setPen(Qt::green);
+
+        if (left >= 0 && left <= width()) {
+            painter.drawLine(left, 0, left, height());
+        }
+
+        if (right >= 0 && right <= width()) {
+            painter.drawLine(right, 0, right, height());
+        }
+    }
+}
+
+
+/* Find the item with the highest value at pos.x() +/- 1,
+ * the mouse must be within the bar height-wise.
+ */
+qint64 HistogramView::itemAtPosition(QPoint pos) {
+    double dvdx = m_viewWidth / (double)width();
+
+    qint64 left = qFloor(dvdx) * (pos.x() - 1) + m_viewLeft;
+    qint64 right = qCeil(dvdx) * (pos.x() + 1) + m_viewLeft;
+
+    qint64 longestIndex = 0;
+    qint64 longestValue = 0;
+
+    left = qBound<qint64>(0, left, m_data->size() - 1);
+    right = qBound<qint64>(0, right, m_data->size() - 1);
+
+    for (qint64 i = left; i <= right; ++i) {
+        if (m_data->value(i) > longestValue) {
+            longestValue = m_data->value(i);
+            longestIndex = i;
+        }
+    }
+
+    return longestIndex;
+}
+
+
+/* Return the value at position */
+qint64 HistogramView::valueAtPosition(QPoint pos) {
+    double value = m_graphTop / (double)height();
+    value *= height() - pos.y();
+    value += m_graphBottom;
+    return (qint64)value;
+}
+