]> git.cworth.org Git - apitrace/blob - gui/graphing/histogramview.cpp
0b945772b96916bbe470289865eedcfba9e96b33
[apitrace] / gui / graphing / histogramview.cpp
1 #include "histogramview.h"
2
3 #include <QPen>
4 #include <QBrush>
5 #include <qmath.h>
6 #include <QPainter>
7 #include <QToolTip>
8 #include <QMouseEvent>
9
10 HistogramView::HistogramView(QWidget* parent) :
11     GraphView(parent),
12     m_data(NULL)
13 {
14     setMouseTracking(true);
15
16     m_gradientUnselected.setColorAt(0.9, QColor(200, 200, 200));
17     m_gradientUnselected.setColorAt(0.0, QColor(220, 220, 220));
18
19     m_gradientSelected.setColorAt(0.9, QColor(0, 0, 210));
20     m_gradientSelected.setColorAt(0.0, QColor(130, 130, 255));
21 }
22
23
24 void HistogramView::setDataProvider(GraphDataProvider* data)
25 {
26     delete m_data;
27     m_data = data;
28
29     if (m_data) {
30         m_data->setSelectionState(m_selectionState);
31         setDefaultView(0, m_data->size());
32         m_viewWidthMin = 10;
33     } else {
34         setDefaultView(0, 0);
35     }
36 }
37
38
39 void HistogramView::setSelectionState(SelectionState* state)
40 {
41     if (m_data) {
42         m_data->setSelectionState(state);
43     }
44
45     GraphView::setSelectionState(state);
46 }
47
48
49 void HistogramView::setSelectedGradient(const QLinearGradient& gradient)
50 {
51     m_gradientSelected = gradient;
52 }
53
54
55 void HistogramView::setUnelectedGradient(const QLinearGradient& gradient)
56 {
57     m_gradientUnselected = gradient;
58 }
59
60
61 void HistogramView::mouseMoveEvent(QMouseEvent *e)
62 {
63     GraphView::mouseMoveEvent(e);
64
65     if (e->buttons() || !m_data) {
66         QToolTip::hideText();
67         return;
68     }
69
70     qint64 index = itemAtPosition(e->pos());
71     qint64 time = valueAtPosition(e->pos());
72
73     if (m_data->value(index) >= time) {
74         QToolTip::showText(e->globalPos(), m_data->itemTooltip(index));
75     } else {
76         QToolTip::hideText();
77     }
78 }
79
80
81 void HistogramView::mouseDoubleClickEvent(QMouseEvent *e)
82 {
83     if (e->button() == Qt::LeftButton) {
84         qint64 index = itemAtPosition(e->pos());
85         qint64 time = valueAtPosition(e->pos());
86
87         if (m_data->value(index) >= time) {
88             m_data->itemDoubleClicked(index);
89             return;
90         }
91     }
92
93     GraphView::mouseDoubleClickEvent(e);
94 }
95
96
97 void HistogramView::update()
98 {
99     m_graphBottom = 0;
100     m_graphTop = 0;
101
102     if (m_data) {
103         for (qint64 i = m_viewLeft; i < m_viewRight; ++i) {
104             qint64 value = m_data->value(i);
105
106             if (value > m_graphTop) {
107                 m_graphTop = value;
108             }
109         }
110     }
111
112     GraphView::update();
113 }
114
115
116 void HistogramView::resizeEvent(QResizeEvent *)
117 {
118     m_gradientSelected.setStart(0, height());
119     m_gradientUnselected.setStart(0, height());
120 }
121
122
123 /* Draw the histogram
124  *
125  * When the view is zoomed such that there is more than one item occupying a single pixel
126  * the one with the highest value will be displayed.
127  */
128 void HistogramView::paintEvent(QPaintEvent *)
129 {
130     if (!m_data) {
131         return;
132     }
133
134     QBrush selectedBrush = QBrush(m_gradientSelected);
135     QPen selectedPen = QPen(selectedBrush, 1);
136
137     QBrush unselectedBrush = QBrush(m_gradientUnselected);
138     QPen unselectedPen = QPen(unselectedBrush, 1);
139
140     QPainter painter(this);
141     painter.fillRect(0, 0, width(), height(), Qt::white);
142
143     double dydv = height() / (double)m_graphTop;
144     double dxdv = width() / (double)(m_viewRight - m_viewLeft);
145     bool selection = m_selectionState && m_selectionState->type != SelectionState::None;
146
147     if (dxdv < 1.0) {
148         /* Less than one pixel per item */
149         qint64 longestValue = m_graphBottom;
150         qint64 longestSelected = m_graphBottom;
151         int lastX = 0;
152         double x = 0;
153
154         if (selection) {
155             painter.setPen(unselectedPen);
156         } else {
157             painter.setPen(selectedPen);
158         }
159
160         for (qint64 i = m_viewLeft; i < m_viewRight; ++i) {
161             qint64 value = m_data->value(i);
162             int ix;
163
164             if (value > longestValue) {
165                 longestValue = value;
166             }
167
168             if (selection && m_data->selected(i) && value > longestSelected) {
169                 longestSelected = value;
170             }
171
172             x += dxdv;
173             ix = (int)x;
174
175             if (lastX != ix) {
176                 painter.drawLine(lastX, height(), lastX, height() - (longestValue * dydv));
177
178                 if (selection && longestSelected > m_graphBottom) {
179                     painter.setPen(selectedPen);
180                     painter.drawLine(lastX, height(), lastX, height() - (longestSelected * dydv));
181                     painter.setPen(unselectedPen);
182                     longestSelected = m_graphBottom;
183                 }
184
185                 longestValue = m_graphBottom;
186                 lastX = ix;
187             }
188         }
189     } else {
190         /* Draw rectangles for graph */
191         double x = 0;
192
193         for (qint64 i = m_viewLeft; i < m_viewRight; ++i, x += dxdv) {
194             qint64 value = m_data->value(i);
195             int y = qMax<int>(1, value * dydv);
196
197             if (!selection || m_data->selected(i)) {
198                 painter.fillRect(x, height() - y, dxdv, y, selectedBrush);
199             } else {
200                 painter.fillRect(x, height() - y, dxdv, y, unselectedBrush);
201             }
202         }
203     }
204
205     /* Draw the borders for the selection */
206     if (m_selectionState && m_selectionState->type == SelectionState::Horizontal) {
207         double dxdt = width() / (double)m_viewWidth;
208         double scroll = m_viewLeft * dxdt;
209         double left = (m_selectionState->start * dxdt) - scroll;
210         double right = (m_selectionState->end * dxdt) - scroll;
211
212         painter.setPen(Qt::green);
213
214         if (left >= 0 && left <= width()) {
215             painter.drawLine(left, 0, left, height());
216         }
217
218         if (right >= 0 && right <= width()) {
219             painter.drawLine(right, 0, right, height());
220         }
221     }
222 }
223
224
225 /* Find the item with the highest value at pos.x() +/- 1,
226  * the mouse must be within the bar height-wise.
227  */
228 qint64 HistogramView::itemAtPosition(QPoint pos) {
229     double dvdx = m_viewWidth / (double)width();
230
231     qint64 left = qFloor(dvdx) * (pos.x() - 1) + m_viewLeft;
232     qint64 right = qCeil(dvdx) * (pos.x() + 1) + m_viewLeft;
233
234     qint64 longestIndex = 0;
235     qint64 longestValue = 0;
236
237     left = qBound<qint64>(0, left, m_data->size() - 1);
238     right = qBound<qint64>(0, right, m_data->size() - 1);
239
240     for (qint64 i = left; i <= right; ++i) {
241         if (m_data->value(i) > longestValue) {
242             longestValue = m_data->value(i);
243             longestIndex = i;
244         }
245     }
246
247     return longestIndex;
248 }
249
250
251 /* Return the value at position */
252 qint64 HistogramView::valueAtPosition(QPoint pos) {
253     double value = m_graphTop / (double)height();
254     value *= height() - pos.y();
255     value += m_graphBottom;
256     return (qint64)value;
257 }
258