#include "timeline_view_selection_handler.h" #include "item_delegate.h" #include #include #include #include #include #include namespace LtsTimeline { TimelineViewSelectHandler::TimelineViewSelectHandler(TimelineView *view) : m_view(view) { } TimelineViewSelectHandler::~TimelineViewSelectHandler() { m_view = nullptr; } void TimelineViewSelectHandler::mouseDoubleClickEvent(QMouseEvent *e) { if (e->button() != Qt::LeftButton) return; m_view->clearSelectedItems(); const QModelIndex index = m_view->indexAt(e->pos()); if (!index.isValid() || index.column() == Section::eActuator) return; try { Track &track = m_view->timelineModel()->track(index.data().toInt()); Item &item = track.itemAt(m_view->toTime(e->pos().x())); emit m_view->itemActivated(item.id()); } catch (const QString &str) { DEBUG_LOG(m_view->m_logger) << LOGFUNCTION << " " << str; } catch (...) { ERROR_LOG(m_view->m_logger) << LOGFUNCTION << " failed"; } } void TimelineViewSelectHandler::mouseMoveEvent(QMouseEvent *e) { if (m_isRubberBandActive) { m_view->setCursor(QCursor(Qt::CrossCursor)); if (!m_view->isCursorWithinRangeX(e->pos().x())) m_rubberBand.setHeight(e->pos().y() - m_rubberBand.top()); else m_rubberBand.setRect( m_rubberBand.left(), m_rubberBand.top(), e->pos().x() - m_rubberBand.left(), e->pos().y() - m_rubberBand.top() ); } else m_selectedItemId = -1; } void TimelineViewSelectHandler::mousePressEvent(QMouseEvent *e) { if (e->button() != Qt::LeftButton && e->button() != Qt::RightButton) return; const QModelIndex index = m_view->indexAt(e->pos()); if (index.isValid()) { if (index.column() == Section::eActuator) { qWarning() << "clicked on row with actuator" << index.data().toString(); return; } try { Track &track = m_view->timelineModel()->track(index.data().toInt()); Item &item = track.itemAt(m_view->toTime(e->pos().x())); if (e->button() == Qt::LeftButton) m_selectedItemId = item.id(); return; } catch (...) { if (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier)) return; if (e->button() == Qt::RightButton) { emit m_view->customContextMenuRequested(e->pos()); return; } m_view->clearSelectedItems(); m_rubberBand.setLeft(e->pos().x()); m_rubberBand.setTop(e->pos().y()); m_rubberBand.setSize(QSize(0, 0)); m_isRubberBandActive = true; return; } return; } else { qWarning() << "TimelineViewSelectHandler::mousePressEvent: index invalid"; } if (e->button() == Qt::RightButton) return; if (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier)) return; m_view->clearSelectedItems(); if (!m_view->isCursorWithinRangeX(e->pos().x())) return; m_rubberBand.setLeft(e->pos().x()); m_rubberBand.setTop(e->pos().y()); m_rubberBand.setSize(QSize(0, 0)); m_isRubberBandActive = true; } void TimelineViewSelectHandler::mouseReleaseEvent(QMouseEvent *e) { if (e->button() == Qt::RightButton) { return; } if (e->button() != Qt::LeftButton) return; if (m_isRubberBandActive) { m_view->selectItems(getItemsWithinRubberBand()); m_isRubberBandActive = false; m_rubberBand.setSize(QSize(0, 0)); m_view->setCursor(QCursor(Qt::ArrowCursor)); return; } else { const QModelIndex index = m_view->indexAt(e->pos()); if (!index.isValid() || index.column() == Section::eActuator) { m_selectedItemId = -1; return; } try { Track &track = m_view->timelineModel()->track(index.data().toInt()); Item &item = track.itemAt(m_view->toTime(e->pos().x())); if (item.id() == m_selectedItemId) { if (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier)) { if (m_view->selectedItemIds().contains(m_selectedItemId)) m_view->unselectItem(m_selectedItemId); else m_view->selectItem(m_selectedItemId, false); } else { if (m_view->m_selectedItemIds.size() > 1 || !m_view->m_selectedItemIds.contains(m_selectedItemId)) m_view->selectItem(m_selectedItemId); else m_view->unselectItem(m_selectedItemId); } } } catch (...) {} m_selectedItemId = -1; } } void TimelineViewSelectHandler::keyPressEvent(QKeyEvent *e) { if (e->key() == Qt::Key_Escape) { m_selectedItemId = -1; m_view->clearSelectedItems(); } else if (e->key() == Qt::Key_Delete) { if (!m_view->m_selectedItemIds.isEmpty()) { for (const int &itemId : qAsConst(m_view->m_selectedItemIds)) { try { m_view->timelineModel()->removeItem(itemId); } catch (const QString &str) { ERROR_LOG(m_view->m_logger) << LOGFUNCTION << " " << str; } catch (...) { ERROR_LOG(m_view->m_logger) << LOGFUNCTION << " failed"; } } m_view->clearSelectedItems(); m_selectedItemId = -1; } } else if (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier)) { try { switch (e->key()) { case Qt::Key_A: m_view->selectAllItems(); m_selectedItemId = -1; break; case Qt::Key_C: if (m_view->hasSelectedItems()) m_view->timelineModel()->copyToClipboard(m_view->selectedItemIds()); break; case Qt::Key_X: if (m_view->hasSelectedItems()) { m_view->timelineModel()->cutToClipboard(m_view->selectedItemIds()); m_view->clearSelectedItems(); } break; case Qt::Key_V: if (!m_view->timelineModel()->m_clipboard.empty()) { qint64 time = m_view->currentTime(); if (m_view->m_header->isIndicatorVisible() && m_view->m_header->indicatorTime() != -1) time = m_view->m_header->indicatorTime(); m_view->timelineModel()->pasteFromClipboard(time); } break; default: break; } } catch (const QString &str) { ERROR_LOG(m_view->m_logger) << LOGFUNCTION << " " << str; } catch (...) { ERROR_LOG(m_view->m_logger) << LOGFUNCTION << " failed"; } } } bool TimelineViewSelectHandler::isActive() const { if (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier)) return true; if (m_isRubberBandActive) return true; return m_selectedItemId != -1; } QVector TimelineViewSelectHandler::getItemsWithinRubberBand() const { const QPoint topLeft = { std::min(m_rubberBand.left(), m_rubberBand.right()), std::min(m_rubberBand.top(), m_rubberBand.bottom()) }; const QPoint bottomRight = { std::max(m_rubberBand.left(), m_rubberBand.right()), std::max(m_rubberBand.top(), m_rubberBand.bottom()) }; const qint64 start = m_view->toTime(topLeft.x()); const qint64 end = m_view->toTime(bottomRight.x()); if (start == end) return {}; QVector itemsWithinRubberBand; const int h = m_view->itemDelegate()->sizeHint({}, {}).height(); for (int y = topLeft.y(); y <= bottomRight.y(); y += h) { const QPoint point = { topLeft.x(), y }; const QModelIndex index = m_view->indexAt(point); if (!index.isValid()) continue; try { const Track &track = m_view->timelineModel()->track(index.data().toInt()); itemsWithinRubberBand += track.itemIdsBetween(start, end); } catch (const QString &str) { ERROR_LOG(m_view->m_logger) << str; } catch (...) {} } if (topLeft.y() + h > bottomRight.y()) { const QModelIndex index = m_view->indexAt(bottomRight); if (!index.isValid()) return itemsWithinRubberBand; try { const Track &track = m_view->timelineModel()->track(index.data().toInt()); itemsWithinRubberBand += track.itemIdsBetween(start, end); } catch (const QString &str) { ERROR_LOG(m_view->m_logger) << str; } catch (...) {} } return itemsWithinRubberBand; } }