#include "timeline_view_resize_handler.h" #include "timeline_view.h" #include "timeline_header_view.h" #include "item.h" #include "track.h" #include #include #include namespace LtsTimeline { TimelineViewResizeHandler::TimelineViewResizeHandler(TimelineView *view) : m_view(view) {} TimelineViewResizeHandler::~TimelineViewResizeHandler() { m_view = nullptr; } void TimelineViewResizeHandler::mouseMoveEvent(QMouseEvent *e) { if (!m_view->timelineModel()->isEditable()) return; if (m_currentTrackId == -1 || m_currentItemId == -1 || m_resizePos == ResizePosition::eNone) return; if (!m_view->timelineModel()->item(m_currentItemId).isEditable()) return; const QModelIndex index(m_view->indexAt(e->pos())); if (index.column() == Section::eActuator || !index.isValid()) return; Track &track = m_view->timelineModel()->track(index.data().toInt()); if (track.id() != m_currentTrackId) return; qint64 time = m_view->timelineModel()->isSnapEnabled() ? globalSnapTime(e->pos().x()) : localSnapTime(e->pos().x()); try { Item &item = m_view->timelineModel()->item(m_currentItemId); if (m_resizePos == ResizePosition::eStart) { if (item.startTime() == time) return; if (!m_view->timelineModel()->canResizeItem(item, time, item.startTime() + item.duration() - time)) return; m_view->timelineModel()->setItemDuration(track, item, item.startTime() + item.duration() - time); m_view->timelineModel()->setItemStartTime(track, item, time); } else { if (item.duration() == time - item.startTime()) return; if (!m_view->timelineModel()->canResizeItem(item, item.startTime(), time - item.startTime())) return; m_view->timelineModel()->setItemDuration(track, item, time - item.startTime()); } } catch (...) { mouseReleaseEvent(e); } } void TimelineViewResizeHandler::mousePressEvent(QMouseEvent *e) { if (!m_view->timelineModel()->isEditable()) return; if (e->button() != Qt::LeftButton) return; const QModelIndex index(m_view->indexAt(e->pos())); if (!index.isValid() || index.column() == Section::eActuator) return; try { const Track &track = m_view->timelineModel()->track(index.data().toInt()); const Item &item = track.itemAt(m_view->toTime(e->pos().x())); if (!item.isEditable()) return; const int startPos = m_view->toPixel(item.startTime()); const int endPos = m_view->toPixel(item.startTime() + item.duration()); if (endPos - startPos < 15 || (startPos + 5 < e->pos().x() && e->pos().x() < endPos - 5)) { m_resizePos = ResizePosition::eNone; return; } else if (startPos + 5 >= e->pos().x()) m_resizePos = ResizePosition::eStart; else m_resizePos = ResizePosition::eEnd; m_currentTrackId = track.id(); m_currentItemId = item.id(); } catch (const QString &str) { ERROR_LOG(m_view->m_logger) << str; } catch (...) {} } void TimelineViewResizeHandler::mouseReleaseEvent(QMouseEvent *e) { if (!m_view->timelineModel()->isEditable()) return; if (e->button() != Qt::LeftButton) return; emit m_view->currentItemTimeChanged(); m_view->setCursor(QCursor(Qt::ArrowCursor)); m_currentTrackId = -1; m_currentItemId = -1; m_resizePos = ResizePosition::eNone; } qint64 TimelineViewResizeHandler::localSnapTime(int pos) const { qint64 time = m_view->toTime(pos); if (m_currentItemId == -1 || m_resizePos == ResizePosition::eNone) return time; try { Track &track = m_view->timelineModel()->track(m_currentTrackId); const Item ¤tItem = m_view->timelineModel()->item(m_currentItemId); if (m_resizePos == ResizePosition::eStart) { if (time >= currentItem.startTime() + currentItem.duration()) time = currentItem.startTime() + currentItem.duration() - m_view->timelineModel()->minimumDuration(); else { try { const Item &previous = track.previous(m_currentItemId); const qint64 endTime = previous.startTime() + previous.duration(); if (time <= endTime) time = endTime; } catch (const QString &str) { ERROR_LOG(m_view->m_logger) << str; } catch (...) {} } } else { if (time <= currentItem.startTime()) time = currentItem.startTime() + m_view->timelineModel()->minimumDuration(); else { try { Item &next = track.next(m_currentItemId); if (time >= next.startTime()) time = next.startTime(); } catch (const QString &str) { ERROR_LOG(m_view->m_logger) << str; } catch (...) {} } } } catch (const QString &str) { ERROR_LOG(m_view->m_logger) << str; } catch (...) {} return time; } qint64 TimelineViewResizeHandler::globalSnapTime(int pos) const { qint64 tPos = (m_view->toTime(pos) / m_view->timelineModel()->snapStep()) * m_view->timelineModel()->snapStep(); if (m_currentItemId == -1 || m_resizePos == ResizePosition::eNone) return tPos; qint64 tMin = m_view->m_startTime; qint64 tMax = m_view->endTime(); try { const Item &previous = m_view->timelineModel()->track(m_currentTrackId).previous(m_currentItemId); tMin = previous.startTime() + previous.duration(); } catch (const QString &str) { DEBUG_LOG(m_view->m_logger) << str; } catch (...) {} try { const Item &next = m_view->timelineModel()->track(m_currentTrackId).next(m_currentItemId); tMax = next.startTime(); } catch (const QString &str) { DEBUG_LOG(m_view->m_logger) << str; } catch (...) {} qint64 time = tPos; try { const Item ¤tItem = m_view->timelineModel()->item(m_currentItemId); int minDist = 2 * m_view->timelineModel()->snapTolerance(); int eps = m_view->timelineModel()->snapTolerance(); for (int itemId : m_view->timelineModel()->itemIds()) { if (itemId == m_currentItemId) continue; try { const Item &item = m_view->timelineModel()->item(itemId); qint64 t; if (time - eps < item.startTime() && item.startTime() < time + eps) t = item.startTime(); else if (time - eps < item.startTime() + item.duration() && item.startTime() + item.duration() < time + eps) t = item.startTime() + item.duration(); else continue; if (std::abs(t - tPos) < minDist) { if ((m_resizePos == ResizePosition::eStart && t >= currentItem.startTime() + currentItem.duration()) || (m_resizePos == ResizePosition::eEnd && t <= currentItem.startTime())) continue; time = t; minDist = time - tPos; } } catch (const QString &str) { ERROR_LOG(m_view->m_logger) << str; } catch (...) {} } if (m_resizePos == ResizePosition::eStart && time >= currentItem.startTime() + currentItem.duration()) return currentItem.startTime() + currentItem.duration() - m_view->timelineModel()->minimumDuration(); else if (m_resizePos == ResizePosition::eEnd && time <= currentItem.startTime()) return currentItem.startTime() + m_view->timelineModel()->minimumDuration(); } catch (const QString &str) { ERROR_LOG(m_view->m_logger) << str; } catch (...) {} time = std::max(tMin, time); time = std::min(tMax, time); return time; } }