Skip to content
This repository was archived by the owner on Apr 30, 2020. It is now read-only.

Added possibility to add time markers to the timeline with the mouse. #1

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion Include/Timeline/acTimeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -311,10 +311,14 @@ class AC_API acTimeline : public QWidget
/// Set should v scroll to end flag
void ShouldScrollToEnd(bool scroll) { m_shouldVScrollToEnd = scroll; }

/// returns pixel coord of a time value
/// returns x pixel coord of a time value
/// \param time value
int TimeToPixel(double timeValue, bool checkBounds = true);

/// returns time value of an x pixel coord
/// \param time value
double PixelToTime(const int pixelValue);

protected:
/// Overridden QWidget method used to display tooltip hints.
/// \param event the event parameters.
Expand Down Expand Up @@ -444,6 +448,8 @@ private slots:
quint64 m_nTimeStamp; ///< The timestamp of the marker.
QColor m_color; ///< The color of the marker.
};
/// Used for sorting markers
static bool markerLessThan(const TimelineMarker* m1, const TimelineMarker* m2) { return m1->m_nTimeStamp < m2->m_nTimeStamp; }

/// Resets the row index for all branches.
void resetRowIndex();
Expand Down
18 changes: 17 additions & 1 deletion Include/Timeline/acTimelineGrid.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,20 @@ class AC_API acTimelineGrid : public QWidget
/// \return the timestamp corresponding to the end of a selection
quint64 endSelectedTime() const { return m_nEndSelectedTime; }

/// Clear all markers from the grid
void clearMarkers();

/// Inserts a marker into the timeline. Used to display times and delta times between markers. Works like the
/// selected time, but the markers are permanent.
/// \param time The timestamp of the marker to add.
void addMarker(const quint64 time);

/// Removes a marker from the timeline at the specified timestamp. Only one marker is removed if several have
/// the same timestamp.
/// \param time The timestamp of the marker to remove
/// \return Whether a marker was found and removed at the specified timestamp
bool removeMarker(const quint64 time);

/// Sets the format string to used when displaying the duration of the selection in
/// the duration hint.
/// \param newDurationHintLabel the format string to used when displaying the duration of
Expand Down Expand Up @@ -242,7 +256,7 @@ class AC_API acTimelineGrid : public QWidget

/// Method called by paintEvent to draw the hints along the grid
/// \param painter the QPainter instance to use for painting
void drawTimeHints(QPainter& painter);
void drawTimeHints(QPainter& painter, quint64 nStartTime, quint64 nEndTime, bool clearBackground = false);

/// Adds the unicode-left-arrow or unicode-right-arrow character to the given string, if
/// the given timestamp is not within the visible range of the time grid
Expand All @@ -266,6 +280,8 @@ class AC_API acTimelineGrid : public QWidget
quint64 m_nSelectedTime; ///< The selected timestamp. Used to display a hint in the time grid.
quint64 m_nEndSelectedTime; ///< The timestamp corresponding to the end of a selection. Used to display a hint in the time grid. If different than "selectedTime", then three hints are shown (start of selection, end of selection, and duration of selection).

QList<quint64> m_markers; ///< A list of extra marker times to draw

bool m_bShowTimeHint; ///< A flag indicating whether or not hints should be shown in the time grid for the selected time (either a single timestamp or a range of time). Defaults to true.

QString m_strDurationHintLabel; ///< The format string to used when displaying the duration of the selection in the duration hint. Defaults to "%1 units".
Expand Down
53 changes: 52 additions & 1 deletion src/acTimeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,7 @@ void acTimeline::paintEvent(QPaintEvent* /* event */)

void acTimeline::mousePressEvent(QMouseEvent* event)
{
bool doUpdateGrid = false;
if (event->button() == Qt::LeftButton)
{
int mouseX = event->x();
Expand All @@ -743,9 +744,39 @@ void acTimeline::mousePressEvent(QMouseEvent* event)
m_bStartDrag = true;
m_nStartDragX = mouseX;
m_dStartSelectionPivot = (mouseX - m_nTitleWidth) / (double)rowWidth();
updateGrid();
doUpdateGrid = true;
}

if ((event->modifiers() & Qt::AltModifier) || (m_pGrid->rect().contains(event->x(), event->y())))
{
auto mouseTime = PixelToTime(mouseX);

// Remove a marker if we are within 5 pixels
bool removedItem = false;
for (auto marker : m_markers)
{
int pixelValue = TimeToPixel(marker->m_nTimeStamp - m_nStartTime);
if (abs(pixelValue - mouseX) < 5)
{
removeMarker(marker->m_nTimeStamp);
removedItem = true;
break; // We only remove one item at a time
}
}

if (!removedItem)
{
addMarker(mouseTime + m_nStartTime, QColor(255, 0, 0, 255));
}

doUpdateGrid = true;
}
}

if (doUpdateGrid)
{
updateGrid();
}
}

void acTimeline::mouseReleaseEvent(QMouseEvent* event)
Expand Down Expand Up @@ -1625,6 +1656,13 @@ void acTimeline::updateGrid()
time = adjustedStartTime + (quint64)(endPivot * m_nVisibleRange);
m_pGrid->setEndSelectedTime(time);

m_pGrid->clearMarkers();
for (const TimelineMarker* marker : m_markers)
{
const auto time = (TimeToPixel(marker->m_nTimeStamp - m_nStartTime) - m_nTitleWidth) / (double)rowWidth();
m_pGrid->addMarker(adjustedStartTime + (quint64)(time*m_nVisibleRange));
}

m_pGrid->update();
}
}
Expand Down Expand Up @@ -1782,6 +1820,19 @@ int acTimeline::TimeToPixel(double timeValue, bool checkBounds)
return retPixel;
}

double acTimeline::PixelToTime(const int pixelValue)
{
const int drawingWidth = rowWidth();
const double drawingPixel = visibleRange() / (drawingWidth * 1.0);

if (m_pGrid != nullptr)
{
return (pixelValue - titleWidth())*drawingPixel + m_pGrid->visibleStartTime();
}

return 0.0;
}

acTimeline::TimelineMarker::TimelineMarker(quint64 timeStamp, QColor color) :
m_nTimeStamp(timeStamp), m_color(color)
{
Expand Down
91 changes: 73 additions & 18 deletions src/acTimelineGrid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,21 @@ void acTimelineGrid::setEndSelectedTime(const quint64 newEndSelectedTime)
ensureValidVisibleRange();
}

void acTimelineGrid::clearMarkers()
{
m_markers.clear();
}

void acTimelineGrid::addMarker(const quint64 time)
{
m_markers.append(time);
}

bool acTimelineGrid::removeMarker(const quint64 time)
{
return m_markers.removeOne(time);
}

void acTimelineGrid::setDurationHintLabel(const QString newDurationHintLabel)
{
m_strDurationHintLabel = newDurationHintLabel;
Expand Down Expand Up @@ -288,7 +303,33 @@ void acTimelineGrid::paintEvent(QPaintEvent* /* event */)
}
}

drawTimeHints(painter);
// Draw markers first
QList<quint64> markersToDraw;
for (const auto marker : m_markers)
{
if ((marker > m_nVisibleStartTime) && (marker < m_nVisibleStartTime + m_nVisibleRange))
markersToDraw.append(marker);
}

if (markersToDraw.size() > 0)
{
if (markersToDraw.size() == 1)
{
drawTimeHints(painter, markersToDraw[0], markersToDraw[0]);
}
else
{
quint64 prevMarker = markersToDraw[0];
for (auto marker = markersToDraw.cbegin() + 1; marker != markersToDraw.cend(); marker++)
{
drawTimeHints(painter, prevMarker, *marker);
prevMarker = *marker;
}
}
}

// Draw the selected times after markers as we want selected time to take precedence over markers
drawTimeHints(painter, m_nSelectedTime, m_nEndSelectedTime, true);

// draw top line last, using the pre-calculated right coordinate
if (m_nGridRightXPosition > 0)
Expand Down Expand Up @@ -316,42 +357,51 @@ void acTimelineGrid::resizeEvent(QResizeEvent* event)
QWidget::resizeEvent(event);
}

void acTimelineGrid::drawTimeHints(QPainter& painter)
void drawDoubleArrowLine(QPainter& painter, const int x1, const int y1, const int x2, const int y2, const int arrowSize)
{
painter.drawLine(x1, y1, x2, y2);
painter.drawLine(x1, y1, x1 + arrowSize, y1 - arrowSize);
painter.drawLine(x1, y1, x1 + arrowSize, y1 + arrowSize);
painter.drawLine(x2, y2, x2 - arrowSize, y2 - arrowSize);
painter.drawLine(x2, y2, x2 - arrowSize, y2 + arrowSize);

}

void acTimelineGrid::drawTimeHints(QPainter& painter, const quint64 nStartTime, quint64 nEndTime, bool clearBackground)
{
if (m_bShowTimeHint)
{
QString startStrNum;

startStrNum.setNum(m_nSelectedTime * m_dInverseScalingFactor, 'f', m_precision);
startStrNum.setNum(nStartTime * m_dInverseScalingFactor, 'f', m_precision);

addOutOfRangeCharacterToHintString(startStrNum, m_nSelectedTime);
addOutOfRangeCharacterToHintString(startStrNum, nStartTime);

int startTextWidth = fontMetrics().width(startStrNum);
QRect startHintRect = calcHintRect(startTextWidth, m_nSelectedTime);
QRect startHintRect = calcHintRect(startTextWidth, nStartTime);
QColor hintColor = palette().color(QPalette::ToolTipBase);
hintColor.setAlpha(192);

if (m_nSelectedTime != m_nEndSelectedTime)
if (nStartTime != nEndTime)
{
QString endStrNum;
endStrNum.setNum(m_nEndSelectedTime * m_dInverseScalingFactor, 'f', m_precision);
endStrNum.setNum(nEndTime * m_dInverseScalingFactor, 'f', m_precision);

addOutOfRangeCharacterToHintString(endStrNum, m_nEndSelectedTime);
addOutOfRangeCharacterToHintString(endStrNum, nEndTime);
int endTextWidth = fontMetrics().width(endStrNum);
QRect endHintRect = calcHintRect(endTextWidth, m_nEndSelectedTime);
QRect endHintRect = calcHintRect(endTextWidth, nEndTime);

quint64 diffTime;
quint64 absDiffTime;

if (m_nEndSelectedTime > m_nSelectedTime)
if (nEndTime > nStartTime)
{
diffTime = m_nEndSelectedTime - m_nSelectedTime;
absDiffTime = m_nSelectedTime + (diffTime / 2);
diffTime = nEndTime - nStartTime;
absDiffTime = nStartTime + (diffTime / 2);
}
else
{
diffTime = m_nSelectedTime - m_nEndSelectedTime;
absDiffTime = m_nEndSelectedTime + (diffTime / 2);
diffTime = nStartTime - nEndTime;
absDiffTime = nEndTime + (diffTime / 2);
}

if ((startHintRect.left() == m_nGridLabelSpace && endHintRect.right() == m_nGridLabelSpace + m_nGridSpace - 1) ||
Expand All @@ -370,20 +420,24 @@ void acTimelineGrid::drawTimeHints(QPainter& painter)
if (startHintRect.intersects(endHintRect) || startHintRect.intersects(diffHintRect)
|| endHintRect.intersects(diffHintRect))
{
if (m_nEndSelectedTime > m_nSelectedTime)
if (nEndTime > nStartTime)
{
startStrNum = startStrNum + " - " + endStrNum + " (" + diffStrNum + ")" ;
startStrNum = startStrNum + " - " + endStrNum + " (" + diffStrNum + ")";
}
else
{
startStrNum = endStrNum + " - " + startStrNum + " (" + diffStrNum + ")";
}

startTextWidth = fontMetrics().width(startStrNum);
startHintRect = calcHintRect(startTextWidth, m_nSelectedTime);
startHintRect = calcHintRect(startTextWidth, nStartTime);
}
else
{
const int middle = startHintRect.top() + (startHintRect.bottom() - startHintRect.top()) / 2;
if (clearBackground)
painter.fillRect(QRect(startHintRect.topLeft(), endHintRect.bottomRight()), palette().color(QWidget::backgroundRole()));
drawDoubleArrowLine(painter, startHintRect.right() + 1, middle, endHintRect.left() - 1, middle, 3);
painter.fillRect(endHintRect, hintColor);
painter.drawText(endHintRect, Qt::AlignCenter, endStrNum);

Expand All @@ -398,6 +452,7 @@ void acTimelineGrid::drawTimeHints(QPainter& painter)
}
}


void acTimelineGrid::addOutOfRangeCharacterToHintString(QString& hintString, quint64 timeStamp)
{
if (timeStamp < m_nVisibleStartTime)
Expand Down