Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

@@ -0,0 +1,307 @@
#include "tln_timeline_select_handler.h"
#include "tln_abstract_event_item.h"
#include "tln_participant_track.h"
#include "tln_timeline_delegate.h"
#include "tln_timeline_model.h"
#include <QApplication>
#include <QDebug>
namespace Timeline
{
TimelineSelectHandler::TimelineSelectHandler(LtsTimeline::TimelineView *view)
: LtsTimeline::TimelineViewSelectHandler(view)
{
m_model = qobject_cast<TimelineModel *>(view->model());
if (m_model != nullptr)
return;
// okay, maybe it's a proxy model
auto proxyModel = qobject_cast<QAbstractProxyModel *>(view->model());
if (proxyModel != nullptr)
m_model = qobject_cast<TimelineModel *>(proxyModel->sourceModel());
if (m_model == nullptr)
qWarning() << "TimelineSelectHandler:c_tor: model is not a TimelineModel!";
Q_ASSERT(m_model != nullptr);
}
///////////////////////////////////////////////////////////////////////////////
// PUBLIC
void TimelineSelectHandler::mouseDoubleClickEvent(QMouseEvent *e)
{
if (m_model == nullptr)
return;
if (e->button() != Qt::LeftButton)
return;
m_view->clearSelectedItems();
const QModelIndex index(m_view->indexAt(e->pos()));
if (!index.isValid())
return;
if (index.column() == LtsTimeline::Section::eActuator)
{
int trackId;
try
{
bool k = true;
trackId = index.data(Qt::UserRole).toInt(&k); // ffs
if (!k)
{
qWarning() << "cannot find track by user role" << index;
return;
}
}
catch (...)
{
qWarning() << "cannot find track by index" << index;
return;
}
qWarning() << "TRACK ID 1 =" << trackId;
qWarning() << "clicked on actuator column with content (string):" << index.data().toString();
emit m_view->trackActivated(trackId);
return;
}
// at this point an ITEM was / might have been selected:
int itemId;
try
{
bool k = true;
int trackId = index.data().toInt(&k);
if (!k)
{
qWarning() << "cannot find track by data" << index;
return;
}
qWarning() << "TRACK ID 2 =" << trackId;
const Track &t = m_model->track(trackId);
itemId = itemIdAt(t, e->pos().x());
}
catch (const QString &msg)
{
qWarning() << Q_FUNC_INFO << "cannot get track from index internalId" << msg;
return;
}
if (itemId != -1)
{
emit m_view->itemActivated(itemId);
return;
}
qWarning() << Q_FUNC_INFO << "no item behind click";
m_view->clearSelectedItems();
m_rubberBand.setLeft(e->pos().x());
m_rubberBand.setTop(e->pos().y());
m_rubberBand.setSize(QSize(0, 0));
m_isRubberBandActive = true;
}
void TimelineSelectHandler::mousePressEvent(QMouseEvent *e)
{
if (m_model == nullptr)
return;
if (e->button() != Qt::LeftButton)
return;
const QModelIndex index(m_view->indexAt(e->pos()));
if (index.isValid())
{
if (index.column() == LtsTimeline::Section::eActuator)
{
qWarning() << "clicked on row with actuator" << index.data().toString();
return;
}
try
{
int itemId = itemIdAt(m_model->track(index.data().toInt()), e->pos().x());
if (itemId != -1)
{
m_selectedItemId = itemId;
return;
}
else
{
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;
}
}
catch (...) {}
return;
}
else
{
qWarning() << "TimelineSelectHandler::mousePressEvent: index invalid";
}
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 TimelineSelectHandler::mouseReleaseEvent(QMouseEvent *e)
{
if (m_model == nullptr)
return;
if (e->button() != Qt::LeftButton)
return;
if (m_isRubberBandActive)
{
if (m_rubberBand.width() > 1 && m_rubberBand.height() > 1) // threshold for rubberband
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() == LtsTimeline::Section::eActuator)
{
m_selectedItemId = -1;
return;
}
try
{
int itemId = itemIdAt(m_model->track(index.data().toInt()), e->pos().x());
if (itemId == -1)
{
m_view->clearSelectedItems();
}
else
{
if (itemId == m_selectedItemId)
{
if (m_view->selectedItemIds().size() > 1 || !m_view->selectedItemIds().contains(m_selectedItemId))
m_view->selectItem(m_selectedItemId);
else
m_view->unselectItem(m_selectedItemId);
}
}
m_selectedItemId = -1;
return;
}
catch (...)
{
m_selectedItemId = -1;
return;
}
}
}
///////////////////////////////////////////////////////////////////////////////
// PUBLIC
int TimelineSelectHandler::itemIdAt(const LtsTimeline::Track &track, int x) const // TODO: noexcept(false)
{
if (m_model == nullptr)
return -1;
qint64 time = m_view->toTime(x);
try
{
const LtsTimeline::Item &item = track.itemAt(time);
return item.id();
}
catch (...) {}
const TrackType trackType = m_model->trackType(track);
// check marker track
if (trackType == TrackType::Marker)
{
try
{
const qint64 offset = TimelineDelegate::s_zeroDurationItemWidth / 2;
const QVector<int> itemIds = track.itemIdsBetween(m_view->toTime(x - offset), m_view->toTime(x + offset));
if (itemIds.isEmpty())
return -1;
else if (itemIds.size() == 1)
return itemIds.first();
else
{
auto it = std::min_element(itemIds.begin(), itemIds.end(), [this, time](int leftId, int rightId)
{
return std::abs(m_model->item(leftId).startTime() - time) < std::abs(m_model->item(rightId).startTime() - time);
});
return *it;
}
}
catch (const QString &errMsg) { qCritical() << LOGFUNCTION << "failed:" << errMsg; }
catch (...) { qCritical() << LOGFUNCTION << "failed"; }
return -1;
}
// check zero duration track
if (trackType == TrackType::Party || trackType == TrackType::Participant || trackType == TrackType::BuildingHits)
{
try
{
for (const ItemPtr &itemPtr : qAsConst(track.items()))
{
const int xItem = m_view->toPixel(itemPtr->startTime());
if (xItem <= x && x <= xItem + TimelineDelegate::s_zeroDurationItemWidth)
return itemPtr->id();
}
}
catch (const QString &errMsg) { qCritical() << LOGFUNCTION << "failed:" << errMsg; }
catch (...) { qCritical() << LOGFUNCTION << "failed"; }
return -1;
}
// check duration track
try
{
const int minDuration = m_model->m_zeroDurationItemWidthTime;
for (const ItemPtr &itemPtr : qAsConst(track.items()))
{
if (itemPtr->duration() == -1 && itemPtr->startTime() >= time)
return itemPtr->id();
int duration = itemPtr->duration() < minDuration ? minDuration : itemPtr->duration();
if (itemPtr->startTime() <= time && time <= itemPtr->startTime() + duration)
return itemPtr->id();
}
}
catch (const QString &errMsg) { qCritical() << LOGFUNCTION << "failed:" << errMsg; }
catch (...) { qCritical() << LOGFUNCTION << "failed"; }
return -1;
}
} // namespace Timeline