1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 **************************************************************************/
27 #include "vogleditor_qtimelineview.h"
28 #include "vogleditor_frameitem.h"
30 vogleditor_QTimelineView::vogleditor_QTimelineView(QWidget *parent) :
33 m_curApiCallNumber(0),
37 QLinearGradient gradient(QPointF(50, -20), QPointF(80, 20));
38 gradient.setColorAt(0.0, Qt::white);
39 gradient.setColorAt(1.0, QColor(0xa6, 0xce, 0x39));
41 m_background = QBrush(QColor(200,200,200));//QBrush(parent->palette().brush(parent->backgroundRole()));
42 m_triangleBrush = QBrush(gradient);
43 m_trianglePen = QPen(Qt::black);
44 m_trianglePen.setWidth(1);
45 m_textPen = QPen(Qt::white);
46 m_textFont.setPixelSize(50);
48 m_horizontalScale = 1;
52 vogleditor_QTimelineView::~vogleditor_QTimelineView()
57 void vogleditor_QTimelineView::paintEvent(QPaintEvent *event)
59 // Don't bother drawing if the rect is too small.
60 // For some reason this is happening at unexpected times.
61 int rectHeight = event->rect().height();
62 int rectWidth = event->rect().width();
63 if (rectHeight < 100 || rectWidth < 100)
70 paint(&painter, event);
74 void vogleditor_QTimelineView::drawBaseTimeline(QPainter* painter, const QRect& rect, int gap)
78 // fill entire background with background color
79 painter->fillRect(rect, m_background);
81 // translate drawing to vertical center of rect
82 painter->translate(0, rect.height()/2);
84 painter->setBrush(m_triangleBrush);
85 painter->setPen(m_trianglePen);
87 // everything will have a small gap on the left and right sides
88 painter->translate(gap, 0);
90 // draw the actual timeline
91 int lineLength = rect.width()-2*gap;
92 painter->drawLine(0,0, lineLength, 0);
97 void vogleditor_QTimelineView::paint(QPainter *painter, QPaintEvent *event)
100 int arrowHeight = 10;
101 int arrowTop = event->rect().height()/2-gap-arrowHeight;
102 int arrowHalfWidth = 3;
103 m_lineLength = event->rect().width()-2*gap;
105 QPolygon triangle(3);
106 triangle.setPoint(0, 0, arrowTop);
107 triangle.setPoint(1, -arrowHalfWidth, arrowTop+arrowHeight);
108 triangle.setPoint(2, arrowHalfWidth, arrowTop+arrowHeight);
110 drawBaseTimeline(painter, event->rect(), gap);
112 if (m_pModel == NULL)
117 if (m_pModel->get_root_item() == NULL)
122 if (m_pPixmap != NULL)
124 int rectHeight = event->rect().height();
125 int rectWidth = event->rect().width();
126 int pmHeight = m_pPixmap->height();
127 int pmWidth = m_pPixmap->width();
129 float widthPctDelta = (float)(rectWidth - pmWidth) / (float)pmWidth;
130 float heightPctDelta = (float)(rectHeight - pmHeight) / (float)pmHeight;
132 // If the resize is of a 'signficant' amount, then delete the pixmap so that it will be regenerated at the new size.
133 if (fabs(widthPctDelta) > 0.2 ||
134 fabs(heightPctDelta) > 0.2)
140 if (m_pPixmap == NULL)
142 m_pPixmap = new QPixmap(event->rect().width(), event->rect().height());
143 QPainter pixmapPainter(m_pPixmap);
144 drawBaseTimeline(&pixmapPainter, event->rect(), gap);
146 // translate drawing to vertical center of rect
147 // everything will have a small gap on the left and right sides
148 pixmapPainter.translate(gap, event->rect().height()/2);
150 if (m_pModel->get_root_item()->getBrush() == NULL)
152 m_pModel->get_root_item()->setBrush(&m_triangleBrush);
155 m_horizontalScale = (float)m_lineLength / (float)m_pModel->get_root_item()->getDuration();
157 // we don't want to draw the root item, but all of its children
158 int numChildren = m_pModel->get_root_item()->childCount();
159 int height = event->rect().height()/2-2*gap;
161 pixmapPainter.setBrush(m_triangleBrush);
162 pixmapPainter.setPen(m_trianglePen);
164 float minimumOffset = 0;
165 for (int c = 0; c < numChildren; c++)
167 vogleditor_timelineItem* pChild = m_pModel->get_root_item()->child(c);
168 drawTimelineItem(&pixmapPainter, pChild, height, minimumOffset);
172 painter->drawPixmap(event->rect(), *m_pPixmap, m_pPixmap->rect());
174 // translate drawing to vertical center of rect
175 // everything will have a small gap on the left and right sides
176 painter->translate(gap, event->rect().height()/2);
178 painter->setBrush(m_triangleBrush);
179 painter->setPen(m_trianglePen);
181 int numChildren = m_pModel->get_root_item()->childCount();
182 for (int c = 0; c < numChildren; c++)
184 vogleditor_timelineItem* pChild = m_pModel->get_root_item()->child(c);
186 // draw current frame marker
187 if (pChild->getFrameItem() != NULL && pChild->getFrameItem()->frameNumber() == m_curFrame)
190 painter->translate(scalePositionHorizontally(pChild->getBeginTime()), 0);
191 painter->drawPolygon(triangle);
195 // draw current api call marker
196 if (pChild->getApiCallItem() != NULL && pChild->getApiCallItem()->globalCallIndex() == m_curApiCallNumber)
199 painter->translate(scalePositionHorizontally(pChild->getBeginTime()), 0);
200 painter->drawPolygon(triangle);
206 float vogleditor_QTimelineView::scaleDurationHorizontally(float value)
208 float scaled = value * m_horizontalScale;
209 if (scaled <= m_horizontalScale)
211 scaled = m_horizontalScale;
217 float vogleditor_QTimelineView::scalePositionHorizontally(float value)
219 float horizontalShift = m_pModel->get_root_item()->getBeginTime();
220 float horizontalLength = m_pModel->get_root_item()->getDuration();
221 float offset = ((value - horizontalShift) / horizontalLength) * m_lineLength;
226 void vogleditor_QTimelineView::drawTimelineItem(QPainter* painter, vogleditor_timelineItem *pItem, int height, float& minimumOffset)
228 float duration = pItem->getDuration();
235 if (pItem->isMarker())
237 painter->setBrush(m_triangleBrush);
238 painter->setPen(m_trianglePen);
240 float offset = scalePositionHorizontally(pItem->getBeginTime());
241 painter->drawLine(QLineF(offset, -height, offset, height));
245 // only draw if the item will extend beyond the minimum offset
246 float leftOffset = scalePositionHorizontally(pItem->getBeginTime());
247 float scaledWidth = scaleDurationHorizontally(duration);
248 if (minimumOffset < leftOffset + scaledWidth)
250 float durationRatio = duration / m_maxItemDuration;
251 int intensity = std::min(255, (int)(durationRatio * 255.0f));
252 // painter->setBrush(*(pItem->getBrush()));
253 QColor color(intensity, 255-intensity, 0);
254 painter->setBrush(QBrush(color));
255 painter->setPen(color);
257 // Clamp the item so that it is 1 pixel wide.
258 // This is intentionally being done before updating the minimum offset
259 // so that small items after the current item will not be drawn
265 // update minimum offset
266 minimumOffset = leftOffset + scaledWidth;
268 // draw the colored box that represents this item
270 rect.setLeft(leftOffset);
271 rect.setTop(-height/2);
272 rect.setWidth(scaledWidth);
273 rect.setHeight(height);
274 painter->drawRect(rect);
276 // now draw all children
277 int numChildren = pItem->childCount();
278 for (int c = 0; c < numChildren; c++)
280 drawTimelineItem(painter, pItem->child(c), height-1, minimumOffset);