]> git.cworth.org Git - apitrace/blob - gui/graphing/graphwidget.cpp
Merge remote-tracking branch 'github/master' into d2d
[apitrace] / gui / graphing / graphwidget.cpp
1 #include "graphwidget.h"
2
3 #include <QScrollBar>
4
5 GraphWidget::GraphWidget(QWidget* parent) :
6     QWidget(parent),
7     m_view(NULL),
8     m_label(NULL),
9     m_axisTop(NULL),
10     m_axisLeft(NULL),
11     m_axisRight(NULL),
12     m_axisBottom(NULL),
13     m_horizontalScrollbar(NULL),
14     m_horizontalMin(0),
15     m_horizontalMax(0),
16     m_horizontalStart(0),
17     m_horizontalEnd(0),
18     m_horizontalScrollbarPolicy(Qt::ScrollBarAlwaysOff),
19     m_verticalScrollbar(NULL),
20     m_verticalMin(0),
21     m_verticalMax(0),
22     m_verticalStart(0),
23     m_verticalEnd(0),
24     m_verticalScrollbarPolicy(Qt::ScrollBarAlwaysOff)
25 {
26     m_selection.type = SelectionState::None;
27
28     m_verticalScrollbar = new QScrollBar(this);
29     m_verticalScrollbar->setOrientation(Qt::Vertical);
30     m_verticalScrollbar->hide();
31     m_verticalScrollbar->resize(m_verticalScrollbar->sizeHint());
32
33     m_horizontalScrollbar = new QScrollBar(this);
34     m_horizontalScrollbar->setOrientation(Qt::Horizontal);
35     m_horizontalScrollbar->hide();
36     m_horizontalScrollbar->resize(m_horizontalScrollbar->sizeHint());
37
38     updateLayout();
39     setAutoFillBackground(true);
40 }
41
42
43 GraphView* GraphWidget::view()
44 {
45     return m_view;
46 }
47
48
49 GraphLabelWidget* GraphWidget::label()
50 {
51     return m_label;
52 }
53
54
55 GraphAxisWidget* GraphWidget::axis(AxisPosition pos)
56 {
57     switch(pos) {
58         case AxisTop:
59             return m_axisTop;
60
61         case AxisLeft:
62             return m_axisLeft;
63
64         case AxisRight:
65             return m_axisRight;
66
67         case AxisBottom:
68             return m_axisBottom;
69
70         default:
71             return NULL;
72     }
73 }
74
75
76 void GraphWidget::setView(GraphView* view)
77 {
78     delete m_view;
79     m_view = view;
80
81     updateConnections();
82
83     m_view->setSelectionState(&m_selection);
84     m_view->show();
85     m_view->update();
86 }
87
88
89 void GraphWidget::setLabel(GraphLabelWidget* label)
90 {
91     delete m_label;
92     m_label = label;
93 }
94
95
96 void GraphWidget::setAxis(AxisPosition pos, GraphAxisWidget* axis)
97 {
98     switch(pos) {
99         case AxisTop:
100             delete m_axisTop;
101             m_axisTop = axis;
102             m_axisTop->setOrientation(GraphAxisWidget::Horizontal);
103             m_axisTop->setSelectionState(&m_selection);
104             break;
105
106         case AxisLeft:
107             delete m_axisLeft;
108             m_axisLeft = axis;
109             m_axisLeft->setOrientation(GraphAxisWidget::Vertical);
110             m_axisLeft->setSelectionState(&m_selection);
111             break;
112
113         case AxisRight:
114             delete m_axisRight;
115             m_axisRight = axis;
116             m_axisRight->setOrientation(GraphAxisWidget::Vertical);
117             m_axisRight->setSelectionState(&m_selection);
118             break;
119
120         case AxisBottom:
121             delete m_axisBottom;
122             m_axisBottom = axis;
123             m_axisBottom->setOrientation(GraphAxisWidget::Horizontal);
124             m_axisBottom->setSelectionState(&m_selection);
125             break;
126     }
127
128     updateConnections();
129     updateSelection();
130     axis->show();
131 }
132
133
134 void GraphWidget::setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy policy)
135 {
136     m_horizontalScrollbarPolicy = policy;
137     updateScrollbars();
138 }
139
140
141 void GraphWidget::setVerticalScrollBarPolicy(Qt::ScrollBarPolicy policy)
142 {
143     m_verticalScrollbarPolicy = policy;
144     updateScrollbars();
145 }
146
147
148 void GraphWidget::resizeEvent(QResizeEvent *e)
149 {
150     updateLayout();
151     update();
152 }
153
154
155 /* Used if a selection would be shared between graphs with different axis */
156 SelectionState GraphWidget::transformSelectionIn(SelectionState state)
157 {
158     return state;
159 }
160
161
162 /* Used if a selection would be shared between graphs with different axis */
163 SelectionState GraphWidget::transformSelectionOut(SelectionState state)
164 {
165     return state;
166 }
167
168
169 /* Update the scrollbars based on current view */
170 void GraphWidget::updateScrollbars()
171 {
172     /* Vertical scroll bar */
173     qint64 size = (m_verticalMax - m_verticalMin) - (m_verticalEnd - m_verticalStart);
174
175     if (size <= INT_MAX) {
176         m_verticalScrollbar->setValue(m_verticalStart - m_verticalMin);
177         m_verticalScrollbar->setPageStep(m_verticalEnd - m_verticalStart);
178         m_verticalScrollbar->setRange(0, size);
179     } else {
180         /* QScrollBar only supports up to INT_MAX values,
181          * here we must scale our values to match this */
182         double curSize = m_verticalEnd - m_verticalStart;
183         double pages = (m_verticalMax - m_verticalMin) / curSize;
184         double value = (m_verticalStart - m_verticalMin) / curSize;
185
186         m_verticalScrollbar->setValue(value);
187         m_verticalScrollbar->setPageStep(1);
188         m_verticalScrollbar->setRange(0, pages);
189     }
190
191     /* Adhere to scrollbar policy */
192     bool visible = false;
193
194     if (m_verticalScrollbarPolicy == Qt::ScrollBarAlwaysOn) {
195         visible = true;
196     } else if (m_verticalScrollbarPolicy == Qt::ScrollBarAlwaysOff) {
197         visible = false;
198     } else if (m_verticalScrollbarPolicy == Qt::ScrollBarAsNeeded) {
199         visible = m_verticalMin != m_verticalStart || m_verticalMax != m_verticalEnd;
200     }
201
202     if (visible != m_verticalScrollbar->isVisible()) {
203         m_verticalScrollbar->setVisible(visible);
204         updateLayout();
205     }
206
207     /* Horizontal scroll bar */
208     size = (m_horizontalMax - m_horizontalMin) - (m_horizontalEnd - m_horizontalStart);
209
210     if (size <= INT_MAX) {
211         m_horizontalScrollbar->setValue(m_horizontalStart - m_horizontalMin);
212         m_horizontalScrollbar->setPageStep(m_horizontalEnd - m_horizontalStart);
213         m_horizontalScrollbar->setRange(0, size);
214     } else {
215         /* QScrollBar only supports up to INT_MAX values,
216          * here we must scale our values to match this */
217         double dxdv = INT_MAX / (double)size;
218         double value = (m_horizontalStart - m_horizontalMin) * dxdv;
219         double pageStep = (m_horizontalEnd - m_horizontalStart) * dxdv;
220
221         m_horizontalScrollbar->setValue((int)value);
222         m_horizontalScrollbar->setPageStep((int)pageStep);
223         m_horizontalScrollbar->setRange(0, INT_MAX);
224     }
225
226     /* Adhere to scrollbar policy */
227     visible = false;
228
229     if (m_horizontalScrollbarPolicy == Qt::ScrollBarAlwaysOn) {
230         visible = true;
231     } else if (m_horizontalScrollbarPolicy == Qt::ScrollBarAlwaysOff) {
232         visible = false;
233     } else if (m_horizontalScrollbarPolicy == Qt::ScrollBarAsNeeded) {
234         visible =  m_horizontalMin != m_horizontalStart || m_horizontalMax != m_horizontalEnd;
235     }
236
237     if (visible != m_horizontalScrollbar->isVisible()) {
238         m_horizontalScrollbar->setVisible(visible);
239         updateLayout();
240     }
241 }
242
243
244 /* Update all signal / slot connections */
245 void GraphWidget::updateConnections()
246 {
247     if (m_view) {
248         connect(m_view, SIGNAL(selectionChanged()), this, SLOT(updateSelection()), Qt::UniqueConnection);
249
250         connect(m_view, SIGNAL(horizontalViewChanged(qint64,qint64)), this, SLOT(horizontalViewChange(qint64,qint64)), Qt::UniqueConnection);
251         connect(m_view, SIGNAL(horizontalRangeChanged(qint64,qint64)), this, SLOT(horizontalRangeChange(qint64,qint64)), Qt::UniqueConnection);
252
253         connect(m_view, SIGNAL(verticalViewChanged(qint64,qint64)), this, SLOT(verticalViewChange(qint64,qint64)), Qt::UniqueConnection);
254         connect(m_view, SIGNAL(verticalRangeChanged(qint64,qint64)), this, SLOT(verticalRangeChange(qint64,qint64)), Qt::UniqueConnection);
255     }
256
257     if (m_axisTop) {
258         if (m_view) {
259             connect(m_view, SIGNAL(horizontalViewChanged(qint64,qint64)), m_axisTop, SLOT(setView(qint64,qint64)), Qt::UniqueConnection);
260             connect(m_view, SIGNAL(horizontalRangeChanged(qint64,qint64)), m_axisTop, SLOT(setRange(qint64,qint64)), Qt::UniqueConnection);
261         }
262
263         connect(m_axisTop, SIGNAL(selectionChanged()), this, SLOT(updateSelection()), Qt::UniqueConnection);
264     }
265
266     if (m_axisLeft) {
267         if (m_view) {
268             connect(m_view, SIGNAL(verticalViewChanged(qint64,qint64)), m_axisLeft, SLOT(setView(qint64,qint64)), Qt::UniqueConnection);
269             connect(m_view, SIGNAL(verticalRangeChanged(qint64,qint64)), m_axisLeft, SLOT(setRange(qint64,qint64)), Qt::UniqueConnection);
270         }
271
272         connect(m_axisLeft, SIGNAL(selectionChanged()), this, SLOT(updateSelection()), Qt::UniqueConnection);
273     }
274
275     if (m_axisRight) {
276         if (m_view) {
277             connect(m_view, SIGNAL(verticalViewChanged(qint64,qint64)), m_axisRight, SLOT(setView(qint64,qint64)), Qt::UniqueConnection);
278             connect(m_view, SIGNAL(verticalRangeChanged(qint64,qint64)), m_axisRight, SLOT(setRange(qint64,qint64)), Qt::UniqueConnection);
279         }
280
281         connect(m_axisRight, SIGNAL(selectionChanged()), this, SLOT(updateSelection()), Qt::UniqueConnection);
282     }
283
284     if (m_axisBottom) {
285         if (m_view) {
286             connect(m_view, SIGNAL(horizontalViewChanged(qint64,qint64)), m_axisBottom, SLOT(setView(qint64,qint64)), Qt::UniqueConnection);
287             connect(m_view, SIGNAL(horizontalRangeChanged(qint64,qint64)), m_axisBottom, SLOT(setRange(qint64,qint64)), Qt::UniqueConnection);
288         }
289
290         connect(m_axisBottom, SIGNAL(selectionChanged()), this, SLOT(updateSelection()), Qt::UniqueConnection);
291     }
292
293     if (m_horizontalScrollbar) {
294         connect(m_horizontalScrollbar, SIGNAL(actionTriggered(int)), this, SLOT(horizontalScrollAction(int)));
295     }
296
297     if (m_verticalScrollbar) {
298         connect(m_verticalScrollbar, SIGNAL(actionTriggered(int)), this, SLOT(verticalScrollAction(int)));
299     }
300 }
301
302
303 /* Recalculate the layout */
304 void GraphWidget::updateLayout()
305 {
306     int x, y;
307     int padX = 0, padY = 0;
308
309     if (m_axisTop) {
310         padY += m_axisTop->height();
311     }
312
313     if (m_axisBottom) {
314         padY += m_axisBottom->height();
315     }
316
317     if (m_axisLeft) {
318         padX += m_axisLeft->width();
319     }
320
321     if (m_axisRight) {
322         padX += m_axisRight->width();
323     }
324
325     if (m_horizontalScrollbar->isVisible()) {
326         padY += m_horizontalScrollbar->height();
327     }
328
329     if (m_verticalScrollbar->isVisible()) {
330         padX += m_verticalScrollbar->width();
331     }
332
333     if (m_axisTop) {
334         x = m_axisLeft ? m_axisLeft->width() : 0;
335         y = 0;
336
337         m_axisTop->move(x, y);
338         m_axisTop->resize(width() - padX, m_axisTop->height());
339     }
340
341     if (m_axisBottom) {
342         x = m_axisLeft ? m_axisLeft->width() : 0;
343         y = height() - m_axisBottom->height();
344
345         if (m_horizontalScrollbar->isVisible())  {
346             y -= m_horizontalScrollbar->height();
347         }
348
349         m_axisBottom->move(x, y);
350         m_axisBottom->resize(width() - padX, m_axisBottom->height());
351     }
352
353     if (m_axisLeft) {
354         x = 0;
355         y = m_axisTop ? m_axisTop->height() : 0;
356
357         m_axisLeft->move(x, y);
358         m_axisLeft->resize(m_axisLeft->width(), height() - padY);
359     }
360
361     if (m_axisRight) {
362         x = width() - m_axisRight->width();
363         y = m_axisTop ? m_axisTop->height() : 0;
364
365         if (m_verticalScrollbar->isVisible())  {
366             x -= m_verticalScrollbar->width();
367         }
368
369         m_axisRight->move(x, y);
370         m_axisRight->resize(m_axisRight->width(), height() - padY);
371     }
372
373     if (m_view) {
374         x = m_axisLeft ? m_axisLeft->width() : 0;
375         y = m_axisTop ? m_axisTop->height() : 0;
376
377         m_view->move(x, y);
378         m_view->resize(width() - padX, height() - padY);
379     }
380
381     if (m_label) {
382         if (m_axisTop && m_axisLeft) {
383             m_label->move(0, 0);
384             m_label->resize(m_axisLeft->width(), m_axisTop->height());
385         }
386     }
387
388     if (m_verticalScrollbar) {
389         m_verticalScrollbar->move(width() - m_verticalScrollbar->width(), 0);
390
391         if (m_horizontalScrollbar) {
392             m_verticalScrollbar->resize(m_verticalScrollbar->width(), height() - m_horizontalScrollbar->height());
393         } else {
394             m_verticalScrollbar->resize(m_verticalScrollbar->width(), height());
395         }
396     }
397
398     if (m_horizontalScrollbar) {
399         m_horizontalScrollbar->move(0, height() - m_horizontalScrollbar->height());
400
401         if (m_verticalScrollbar) {
402             m_horizontalScrollbar->resize(width() - m_verticalScrollbar->width(), m_horizontalScrollbar->height());
403         } else {
404             m_horizontalScrollbar->resize(width(), m_horizontalScrollbar->height());
405         }
406     }
407 }
408
409
410 void GraphWidget::setSelection(SelectionState state)
411 {
412     m_selection = transformSelectionIn(state);
413     updateSelection(false);
414 }
415
416
417 void GraphWidget::setHorizontalView(qint64 start, qint64 end)
418 {
419     if (m_view) {
420         m_view->setHorizontalView(start, end);
421     }
422 }
423
424
425 void GraphWidget::setVerticalView(qint64 start, qint64 end)
426 {
427     if (m_view) {
428         m_view->setVerticalView(start, end);
429     }
430 }
431
432
433 /* Called when the view is translated / zoomed */
434 void GraphWidget::verticalViewChange(qint64 start, qint64 end)
435 {
436     m_verticalStart = start;
437     m_verticalEnd = end;
438     updateScrollbars();
439
440     emit verticalViewChanged(start, end);
441 }
442
443
444 void GraphWidget::verticalRangeChange(qint64 start, qint64 end)
445 {
446     m_verticalMin = start;
447     m_verticalMax = end;
448     updateScrollbars();
449
450     emit verticalRangeChanged(start, end);
451 }
452
453
454 void GraphWidget::horizontalViewChange(qint64 start, qint64 end)
455 {
456     m_horizontalStart = start;
457     m_horizontalEnd = end;
458     updateScrollbars();
459
460     emit horizontalViewChanged(start, end);
461 }
462
463
464 void GraphWidget::horizontalRangeChange(qint64 start, qint64 end)
465 {
466     m_horizontalMin = start;
467     m_horizontalMax = end;
468     updateScrollbars();
469
470     emit horizontalRangeChanged(start, end);
471 }
472
473
474 /* User interaction with horizontal scroll bar */
475 void GraphWidget::horizontalScrollAction(int /*action*/)
476 {
477     int value = m_horizontalScrollbar->sliderPosition();
478     qint64 size = (m_horizontalMax - m_horizontalMin) - (m_horizontalEnd - m_horizontalStart);
479
480     /* Calculate the new scroll values */
481     if (size <= INT_MAX) {
482         m_horizontalEnd -= m_horizontalStart;
483         m_horizontalStart = value + m_horizontalMin;
484         m_horizontalEnd += value;
485     } else {
486         /* QScrollBar only supports up to INT_MAX values, here we must scale
487          * our values to match this */
488         double dxdv = INT_MAX / (double)size;
489
490         size = m_horizontalEnd - m_horizontalStart;
491         m_horizontalStart = value / dxdv + m_horizontalMin;
492         m_horizontalEnd = m_horizontalStart + size;
493     }
494
495     /* Update view */
496     if (m_view) {
497         m_view->setHorizontalView(m_horizontalStart, m_horizontalEnd);
498     }
499
500     /* Update horizontal axes */
501     if (m_axisTop) {
502         m_axisTop->setView(m_horizontalStart, m_horizontalEnd);
503     }
504
505     if (m_axisBottom) {
506         m_axisBottom->setView(m_horizontalStart, m_horizontalEnd);
507     }
508
509     /* Inform the world of our changes! */
510     emit horizontalViewChanged(m_horizontalStart, m_horizontalEnd);
511 }
512
513
514 /* User interaction with vertical scroll bar */
515 void GraphWidget::verticalScrollAction(int /*action*/)
516 {
517     int value = m_verticalScrollbar->sliderPosition();
518     qint64 size = (m_verticalMax - m_verticalMin) - (m_verticalEnd - m_verticalStart);
519
520     /* Calculate the new scroll values */
521     if (size <= INT_MAX) {
522         m_verticalEnd -= m_verticalStart;
523         m_verticalStart = value + m_verticalMin;
524         m_verticalEnd += value;
525     } else {
526         /* QScrollBar only supports up to INT_MAX values, here we must scale
527          * our values to match this */
528         double dxdv = INT_MAX / (double)size;
529
530         size = m_verticalEnd - m_verticalStart;
531         m_verticalStart = value / dxdv + m_verticalMin;
532         m_verticalEnd = m_verticalStart + size;
533     }
534
535     /* Update view */
536     if (m_view) {
537         m_view->setVerticalView(m_verticalStart, m_verticalEnd);
538     }
539
540     /* Update vertical axes */
541     if (m_axisLeft) {
542         m_axisLeft->setView(m_verticalStart, m_verticalEnd);
543     }
544
545     if (m_axisRight) {
546         m_axisRight->setView(m_verticalStart, m_verticalEnd);
547     }
548
549     /* Inform the world of our changes! */
550     emit verticalViewChanged(m_verticalStart, m_verticalEnd);
551 }
552
553
554 /* Update child elements when selection changes */
555 void GraphWidget::updateSelection(bool emitSignal)
556 {
557     if (m_view) {
558         m_view->update();
559     }
560
561     if (m_axisTop) {
562         m_axisTop->update();
563     }
564
565     if (m_axisLeft) {
566         m_axisLeft->update();
567     }
568
569     if (m_axisRight) {
570         m_axisRight->update();
571     }
572
573     if (m_axisBottom) {
574         m_axisBottom->update();
575     }
576
577     if (emitSignal) {
578         emit selectionChanged(transformSelectionOut(m_selection));
579     }
580 }
581
582
583 #include "graphwidget.moc"