glvdebug: Timeline now supports tooltips.
authorPeter Lohrmann <peterl@valvesofware.com>
Wed, 4 Feb 2015 03:05:45 +0000 (19:05 -0800)
committerJon Ashburn <jon@lunarg.com>
Thu, 12 Feb 2015 15:08:27 +0000 (08:08 -0700)
* Hovering the mouse cursor over a timeline item now displays a tool tip that shows the call index, and entrypoint name & parameters.
* Currently the tooltip has a black background and looks like a window that failed to render, but as far as I can tell that is the default support for tooltips. We can probably spice it up a bit in the future.
* This change also implements several virtual methods of QAbstractItemView; I'm not convinced that they all work properly, but I'm sure additional testing and usage will help solidify things.

tools/glave/src/glvdebug/glvdebug_qtimelineview.cpp
tools/glave/src/glvdebug/glvdebug_qtimelineview.h

index 0b6c08b..00e4712 100755 (executable)
@@ -25,6 +25,7 @@
 \r
 #include <QPainter>\r
 #include <QPaintEvent>\r
+#include <QToolTip>\r
 #include "glvdebug_qtimelineview.h"\r
 #include "glvdebug_QTraceFileModel.h"\r
 \r
@@ -167,10 +168,74 @@ void glvdebug_QTimelineView::setModel(QAbstractItemModel* pModel)
     }\r
 }\r
 \r
+QRectF glvdebug_QTimelineView::itemRect(const QModelIndex &item) const\r
+{\r
+    QRectF rect;\r
+    if (!item.isValid())\r
+    {\r
+        return rect;\r
+    }\r
+\r
+    glv_trace_packet_header* pHeader = (glv_trace_packet_header*)item.internalPointer();\r
+\r
+    // make sure item is valid size\r
+    if (pHeader->entrypoint_end_time <= pHeader->entrypoint_begin_time)\r
+    {\r
+        return rect;\r
+    }\r
+\r
+    int threadIndex = m_threadIdList.indexOf(pHeader->thread_id);\r
+    int topOffset = (m_threadHeight * threadIndex) + (m_threadHeight * 0.5);\r
+\r
+    uint64_t duration = pHeader->entrypoint_end_time - pHeader->entrypoint_begin_time;\r
+\r
+    float leftOffset = scalePositionHorizontally(pHeader->entrypoint_begin_time);\r
+    float scaledWidth = scaleDurationHorizontally(duration);\r
+\r
+    // Clamp the item so that it is 1 pixel wide.\r
+    // This is intentionally being done before updating the minimum offset\r
+    // so that small items after the current item will not be drawn\r
+    if (scaledWidth < 1)\r
+    {\r
+        scaledWidth = 2;\r
+    }\r
+\r
+    // draw the colored box that represents this item\r
+    int itemHeight = m_threadHeight/2;\r
+\r
+    rect.setLeft(leftOffset);\r
+    rect.setTop(topOffset - (itemHeight/2));\r
+    rect.setWidth(scaledWidth);\r
+    rect.setHeight(itemHeight);\r
+\r
+    return rect;\r
+}\r
+\r
+bool glvdebug_QTimelineView::event(QEvent * e)\r
+{\r
+    if (e->type() == QEvent::ToolTip)\r
+    {\r
+        QHelpEvent* pHelp = static_cast<QHelpEvent*>(e);\r
+        QModelIndex index = indexAt(pHelp->pos());\r
+        if (index.isValid())\r
+        {\r
+            glv_trace_packet_header* pHeader = (glv_trace_packet_header*)index.internalPointer();\r
+            QToolTip::showText(pHelp->globalPos(), QString("Call %1:\n%2").arg(pHeader->global_packet_index).arg(index.data().toString()));\r
+            return true;\r
+        }\r
+        else\r
+        {\r
+            QToolTip::hideText();\r
+        }\r
+    }\r
+\r
+    return QAbstractItemView::event(e);\r
+}\r
 \r
 QRect glvdebug_QTimelineView::visualRect(const QModelIndex &index) const\r
 {\r
-    return QRect();\r
+    QRectF rectf = itemRect(index);\r
+    return rectf.toRect();\r
 }\r
 \r
 void glvdebug_QTimelineView::scrollTo(const QModelIndex &index, ScrollHint hint/* = EnsureVisible*/)\r
@@ -182,28 +247,32 @@ QModelIndex glvdebug_QTimelineView::indexAt(const QPoint &point) const
     if (model() == NULL)\r
         return QModelIndex();\r
 \r
-//    // Transform the view coordinates into contents widget coordinates.\r
-//    int wx = point.x() + horizontalScrollBar()->value();\r
-//    int wy = point.y() + verticalScrollBar()->value();\r
-\r
-    return model()->index(0, 0);\r
-}\r
+    // Transform the view coordinates into contents widget coordinates.\r
+    int wx = point.x() + horizontalScrollBar()->value();\r
+    int wy = point.y() + verticalScrollBar()->value();\r
 \r
-//QRect glvdebug_QTimelineView::itemRect(const QModelIndex &item) const\r
-//{\r
-//    if (!item.isValid())\r
-//        return QRect();\r
+    for (int r = 0; r < model()->rowCount(); r++)\r
+    {\r
+        QModelIndex index = model()->index(r, glvdebug_QTraceFileModel::Column_EntrypointName);\r
+        QRectF rectf = itemRect(index);\r
+        QRect rect = rectf.toRect();\r
+        int gap = 10;\r
+        if (rect.contains(wx-gap, wy))\r
+        {\r
+            return index;\r
+        }\r
+    }\r
 \r
-//    return viewport()->rect();\r
-//}\r
+    return QModelIndex();\r
+}\r
 \r
-//QRegion glvdebug_QTimelineView::itemRegion(const QModelIndex &index) const\r
-//{\r
-//    if (!index.isValid())\r
-//        return QRegion();\r
+QRegion glvdebug_QTimelineView::itemRegion(const QModelIndex &index) const\r
+{\r
+    if (!index.isValid())\r
+        return QRegion();\r
 \r
-//    return QRegion();\r
-//}\r
+    return QRegion(itemRect(index).toRect());\r
+}\r
 \r
 //int glvdebug_QTimelineView::rows(const QModelIndex &index = QModelIndex()) const\r
 //{\r
@@ -399,7 +468,7 @@ void glvdebug_QTimelineView::drawCurrentApiCallMarker(QPainter* painter,
     painter->restore();\r
 }\r
 \r
-float glvdebug_QTimelineView::scaleDurationHorizontally(uint64_t value)\r
+float glvdebug_QTimelineView::scaleDurationHorizontally(uint64_t value) const\r
 {\r
     float scaled = value * m_horizontalScale;\r
     if (scaled <= m_horizontalScale)\r
@@ -410,7 +479,7 @@ float glvdebug_QTimelineView::scaleDurationHorizontally(uint64_t value)
     return scaled;\r
 }\r
 \r
-float glvdebug_QTimelineView::scalePositionHorizontally(uint64_t value)\r
+float glvdebug_QTimelineView::scalePositionHorizontally(uint64_t value) const\r
 {\r
     uint64_t shiftedValue = value - m_rawStartTime;\r
     uint64_t duration = m_rawEndTime - m_rawStartTime;\r
@@ -423,9 +492,6 @@ void glvdebug_QTimelineView::drawTimelineItem(QPainter* painter, const QModelInd
 {\r
     glv_trace_packet_header* pHeader = (glv_trace_packet_header*)index.internalPointer();\r
 \r
-    int threadIndex = m_threadIdList.indexOf(pHeader->thread_id);\r
-    int topOffset = (m_threadHeight * threadIndex) + (m_threadHeight * 0.5);\r
-\r
     float duration = u64ToFloat(pHeader->entrypoint_end_time - pHeader->entrypoint_begin_time);\r
     if (duration < 0)\r
     {\r
@@ -434,35 +500,28 @@ void glvdebug_QTimelineView::drawTimelineItem(QPainter* painter, const QModelInd
 \r
     painter->save();\r
     {\r
+        int threadIndex = m_threadIdList.indexOf(pHeader->thread_id);\r
+\r
         // only draw if the item will extend beyond the minimum offset\r
-        float leftOffset = scalePositionHorizontally(pHeader->entrypoint_begin_time);\r
-        float scaledWidth = scaleDurationHorizontally(duration);\r
-        if (m_threadIdMinOffset[threadIndex] < leftOffset + scaledWidth)\r
+//        float leftOffset = scalePositionHorizontally(pHeader->entrypoint_begin_time);\r
+//        float scaledWidth = scaleDurationHorizontally(duration);\r
+//        if (m_threadIdMinOffset[threadIndex] < leftOffset + scaledWidth)\r
         {\r
-            float durationRatio = duration / m_maxItemDuration;\r
-            int intensity = std::min(255, (int)(durationRatio * 255.0f));\r
-            QColor color(intensity, 255-intensity, 0);\r
-            painter->setBrush(QBrush(color));\r
-            painter->setPen(color);\r
-\r
-            // Clamp the item so that it is 1 pixel wide.\r
-            // This is intentionally being done before updating the minimum offset\r
-            // so that small items after the current item will not be drawn\r
-            if (scaledWidth < 1)\r
+            QRectF rect = itemRect(index);\r
+\r
+            if (rect.isValid())\r
             {\r
-                scaledWidth = 1;\r
-            }\r
+                float durationRatio = duration / m_maxItemDuration;\r
+                int intensity = std::min(255, (int)(durationRatio * 255.0f));\r
+                QColor color(intensity, 255-intensity, 0);\r
+                painter->setBrush(QBrush(color));\r
+                painter->setPen(color);\r
 \r
-            // update minimum offset\r
-            m_threadIdMinOffset[threadIndex] = leftOffset + scaledWidth;\r
+                // update minimum offset\r
+                m_threadIdMinOffset[threadIndex] = rect.left() + rect.width();\r
 \r
-            // draw the colored box that represents this item\r
-            QRectF rect;\r
-            rect.setLeft(leftOffset);\r
-            rect.setTop(topOffset - (height/2));\r
-            rect.setWidth(scaledWidth);\r
-            rect.setHeight(height);\r
-            painter->drawRect(rect);\r
+                painter->drawRect(rect);\r
+            }\r
         }\r
     }\r
 \r
index 3dcb328..ac49dbf 100755 (executable)
@@ -111,12 +111,12 @@ private:
     void drawTimelineItem(QPainter* painter, const QModelIndex &index, int height);\r
     void drawCurrentApiCallMarker(QPainter *painter, QPolygon &triangle, uint64_t rawTime);\r
 \r
-    float scaleDurationHorizontally(uint64_t value);\r
-    float scalePositionHorizontally(uint64_t value);\r
+    float scaleDurationHorizontally(uint64_t value) const;\r
+    float scalePositionHorizontally(uint64_t value) const;\r
 \r
+    QRectF itemRect(const QModelIndex &item) const;\r
     // Begin Private...\r
-//    virtual QRect itemRect(const QModelIndex &item) const;\r
-//    virtual QRegion itemRegion(const QModelIndex &index) const;\r
+    virtual QRegion itemRegion(const QModelIndex &index) const;\r
 //    virtual int rows(const QModelIndex &index = QModelIndex()) const;\r
     // End private...\r
 \r
@@ -124,6 +124,8 @@ protected:
     void paintEvent(QPaintEvent *event);\r
     void paint(QPainter *painter, QPaintEvent *event);\r
 \r
+    virtual bool event(QEvent * e);\r
+\r
     // Begin protected virtual functions of QAbstractItemView\r
     virtual QModelIndex moveCursor(CursorAction cursorAction,\r
                                    Qt::KeyboardModifiers modifiers)\r