321 lines
8.0 KiB
C++
Executable File
321 lines
8.0 KiB
C++
Executable File
#include "timeline_view_selection_handler.h"
|
|
#include "item_delegate.h"
|
|
|
|
#include <QApplication>
|
|
#include <QKeyEvent>
|
|
#include <QMouseEvent>
|
|
#include <QSize>
|
|
#include <QModelIndex>
|
|
|
|
#include <QDebug>
|
|
|
|
|
|
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<int> 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<int> 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;
|
|
}
|
|
|
|
}
|