301 lines
8.8 KiB
C++
301 lines
8.8 KiB
C++
|
|
|
|
#pragma once
|
|
#include "item.h"
|
|
#include "ltstimeline_export.h"
|
|
#include "track.h"
|
|
|
|
#include <NGLLogger/INGLLogger.h>
|
|
#include <QAbstractItemModel>
|
|
#include <QObject>
|
|
#include <type_traits>
|
|
|
|
namespace LtsTimeline
|
|
{
|
|
|
|
class TimelineView;
|
|
|
|
class LTSTIMELINE_EXPORT TimelineModel : public QAbstractItemModel
|
|
{
|
|
Q_OBJECT
|
|
|
|
friend class TimelineViewSelectHandler;
|
|
|
|
public:
|
|
explicit TimelineModel(TimelineView* view, QObject* parent = nullptr);
|
|
virtual ~TimelineModel() = default;
|
|
|
|
void clear();
|
|
|
|
Track& rootTrack()
|
|
{
|
|
return m_rootTrack;
|
|
}
|
|
|
|
Track& track(int id) noexcept(false);
|
|
const Track& track(int id) const noexcept(false);
|
|
const Item& item(int id) const noexcept(false);
|
|
Item& item(int id) noexcept(false);
|
|
const QVector<int> itemIds() const;
|
|
const QVector<int> itemIdsBetween(qint64 start, qint64 end, bool strict = false, bool complete = false,
|
|
bool recursive = false, bool sorted = false) const;
|
|
const QVector<int> copyItemIdsBetween(qint64 start, qint64 end, bool strict, bool complete, bool sorted) const;
|
|
|
|
bool isItemsBetween(qint64 start, qint64 end, const QVector<int>& ignoreIds = {}, bool strict = false,
|
|
bool complete = false, bool recursive = false) const;
|
|
bool isItemsBetween(qint64 start, qint64 end, int ignoreId = -1, bool strict = false, bool complete = false,
|
|
bool recursive = false) const;
|
|
const Track& parentOfTrackId(int id) const noexcept(false);
|
|
|
|
virtual void setItemStartTime(Track& t, Item& i, qint64 newStart);
|
|
virtual void setItemStartTime(Item& i, qint64 newStart) noexcept(false);
|
|
virtual void setItemStartTime(int itemId, qint64 newStart) noexcept(false);
|
|
|
|
virtual void setItemDuration(Track& t, Item& i, int duration);
|
|
virtual void setItemDuration(Item& i, int duration) noexcept(false);
|
|
virtual void setItemDuration(int itemId, int duration) noexcept(false);
|
|
|
|
void print(bool withItems = false) const
|
|
{
|
|
m_rootTrack.printTrackIds(withItems);
|
|
}
|
|
|
|
template <typename TrackClass,
|
|
typename = typename std::enable_if<std::is_base_of<Track, TrackClass>::value, TrackClass>::type>
|
|
int addTrack(int parentTrackId, TrackClass&& newTrack) noexcept(false)
|
|
{
|
|
int id = nextFreeTrackId();
|
|
|
|
TrackClass _track(std::move(newTrack));
|
|
_track.m_id = id;
|
|
_track.m_parentId = parentTrackId;
|
|
|
|
auto* ptr = track(parentTrackId).addTrack(std::move(_track));
|
|
m_trackCache.insert(std::pair<int, Track*>(id, ptr));
|
|
|
|
return id;
|
|
}
|
|
|
|
template <typename ItemClass,
|
|
typename = typename std::enable_if<std::is_base_of<Item, ItemClass>::value, ItemClass>::type>
|
|
int addItem(int parentTrackId, ItemClass&& item) noexcept(false)
|
|
{
|
|
int id = nextFreeItemId();
|
|
|
|
ItemClass _item(std::move(item));
|
|
_item.m_id = id;
|
|
_item.m_parentTrackId = parentTrackId;
|
|
|
|
if (m_isSnapEnabled)
|
|
{
|
|
_item.m_startTime = _item.m_startTime - (_item.m_startTime % 1000);
|
|
_item.m_duration = _item.m_duration - (_item.m_duration % 1000);
|
|
}
|
|
|
|
Item* ptr = track(parentTrackId).addItem(std::move(_item));
|
|
m_itemCache.insert(std::pair<int, Item*>(id, ptr));
|
|
|
|
QModelIndex idx = indexOfTrack(parentTrackId);
|
|
emit dataChanged(idx, idx);
|
|
|
|
return id;
|
|
}
|
|
|
|
bool isEditable() const
|
|
{
|
|
return m_isEditable;
|
|
}
|
|
|
|
void setEditable(bool editable)
|
|
{
|
|
m_isEditable = editable;
|
|
}
|
|
|
|
bool isSnapEnabled() const
|
|
{
|
|
return m_isSnapEnabled;
|
|
}
|
|
|
|
void setSnapEnabled(bool enabled)
|
|
{
|
|
m_isSnapEnabled = enabled;
|
|
}
|
|
|
|
int snapStep() const
|
|
{
|
|
return m_snapStep;
|
|
}
|
|
|
|
void setSnapStep(int step)
|
|
{
|
|
m_snapStep = step;
|
|
}
|
|
|
|
int snapTolerance() const
|
|
{
|
|
return m_snapTol;
|
|
}
|
|
|
|
void setSnapTolerance(int tolerance)
|
|
{
|
|
m_snapTol = tolerance;
|
|
}
|
|
|
|
qint64 snapTime(qint64 time) const
|
|
{
|
|
return m_isSnapEnabled ? time / m_snapStep * m_snapStep : time;
|
|
}
|
|
|
|
int minimumDuration() const
|
|
{
|
|
return m_minItemDuration;
|
|
}
|
|
|
|
void setMinimumDuration(int duration);
|
|
|
|
QModelIndex indexOfTrack(int trackId) const;
|
|
QModelIndex indexOfTrackSafe(int trackId) const noexcept(false);
|
|
|
|
virtual void moveItemToTrack(int itemId, int trackId, qint64 time) noexcept(false);
|
|
virtual void removeItem(int itemId) noexcept(false);
|
|
virtual void removeTrack(int trackId) noexcept(false);
|
|
|
|
virtual bool canDropItem(const Item& item, int trackId, qint64 start) const;
|
|
virtual bool canMoveItem(const Item& item, qint64 start) const;
|
|
virtual bool canResizeItem(const Item& item, qint64 start, int duration) const;
|
|
|
|
virtual bool isItemDragged(int _itemId) const;
|
|
|
|
virtual void copyToClipboard(const QVector<int>& ids) noexcept(false);
|
|
virtual void cutToClipboard(const QVector<int>& ids) noexcept(false);
|
|
virtual void pasteFromClipboard(qint64 time) noexcept(false);
|
|
|
|
bool isClipboardEmpty() const
|
|
{
|
|
return m_clipboard.empty();
|
|
}
|
|
|
|
int rowCount(const QModelIndex& parent = {}) const override;
|
|
QVariant data(const QModelIndex& index, int role) const override;
|
|
QModelIndex index(int row, int column, const QModelIndex& parent) const override;
|
|
Qt::ItemFlags flags(const QModelIndex& index) const override;
|
|
QModelIndex parent(const QModelIndex& index) const override;
|
|
|
|
int columnCount(const QModelIndex&) const override
|
|
{
|
|
return 2;
|
|
}
|
|
|
|
protected:
|
|
|
|
ItemPtrNCVRef _itemNCV(Track& track, int id) noexcept(false)
|
|
{
|
|
return track._itemNCV(id);
|
|
}
|
|
|
|
ItemPtrNCVRef _itemNCV(const TrackPtr& trackPtr, int id) noexcept(false)
|
|
{
|
|
return trackPtr->_itemNCV(id);
|
|
}
|
|
|
|
const ItemPtrRefs _items(const TrackPtr& trackPtr, bool recursive) const
|
|
{
|
|
return trackPtr->_items(recursive);
|
|
}
|
|
|
|
ItemPtrNCVRefs _itemsNCV(const TrackPtr& trackPtr, bool recursive)
|
|
{
|
|
return trackPtr->_itemsNCV(recursive);
|
|
}
|
|
|
|
int addItem(int parentTrackId, ItemPtr&& itemPtr, bool forceTheCompilerToUseMe = false) noexcept(false)
|
|
{
|
|
(void)forceTheCompilerToUseMe;
|
|
|
|
int id = nextFreeItemId();
|
|
|
|
ItemPtr _itemPtr(std::move(itemPtr));
|
|
|
|
_itemPtr->m_id = id;
|
|
|
|
_itemPtr->m_parentTrackId = parentTrackId;
|
|
|
|
if (m_isSnapEnabled)
|
|
{
|
|
_itemPtr->m_startTime = _itemPtr->m_startTime - (_itemPtr->m_startTime % 1000);
|
|
_itemPtr->m_duration = _itemPtr->m_duration - (_itemPtr->m_duration % 1000);
|
|
}
|
|
Item* ptr = track(parentTrackId).addItem(std::move(_itemPtr));
|
|
|
|
m_itemCache.insert(std::pair<int, Item*>(id, ptr));
|
|
|
|
QModelIndex idx = indexOfTrack(parentTrackId);
|
|
emit dataChanged(idx, idx);
|
|
|
|
return id;
|
|
}
|
|
|
|
void clearItems();
|
|
int rowOfTrackId(int id) const noexcept(false);
|
|
|
|
const Track& trackOfIndex(const QModelIndex& index) const;
|
|
int indexOf(int id) const;
|
|
|
|
const QVector<int> _itemIdsBetween(Track& t, qint64 start, qint64 end, bool strict, bool complete, bool recursive,
|
|
bool sorted, qint64 minimumDuration) const;
|
|
const QVector<int> _copyItemIdsBetween(Track& t, qint64 start, qint64 end, bool strict, bool complete,
|
|
bool recursive, bool sorted, qint64 minimumDuration) const;
|
|
bool _isItemsBetween(const Track& t, qint64 start, qint64 end, const QVector<int>& ignoreIds, bool strict,
|
|
bool complete, bool recursive, qint64 minimumDuration) const;
|
|
bool _isItemsBetween(const Track& t, qint64 start, qint64 end, int ignoreId, bool strict, bool complete,
|
|
bool recursive, qint64 minimumDuration) const;
|
|
|
|
private:
|
|
int nextFreeTrackId()
|
|
{
|
|
return m_currentTrackId++;
|
|
}
|
|
|
|
int nextFreeItemId()
|
|
{
|
|
return m_currentItemId++;
|
|
}
|
|
|
|
QModelIndex indexOfTrackFromIndex(const QModelIndex& idx, int trackId) const;
|
|
QModelIndex indexOfTrackFromIndexSafe(const QModelIndex& idx, int trackId) const noexcept(false);
|
|
|
|
public slots:
|
|
|
|
virtual void onInsertTrack(const QModelIndex& index)
|
|
{
|
|
Q_UNUSED(index);
|
|
}
|
|
|
|
virtual void onRemoveTrack(const QModelIndex& index)
|
|
{
|
|
Q_UNUSED(index);
|
|
}
|
|
|
|
protected:
|
|
NGL::INGLLogger& m_logger;
|
|
TimelineView* m_view{nullptr};
|
|
|
|
Track m_rootTrack;
|
|
int m_currentTrackId{0};
|
|
int m_currentItemId{0};
|
|
bool m_isEditable{true};
|
|
bool m_isSnapEnabled{false};
|
|
int m_snapStep{500};
|
|
int m_snapTol{1000};
|
|
int m_minItemDuration{0};
|
|
|
|
bool m_itemCaching{true};
|
|
bool m_trackCaching{true};
|
|
std::map<int, Track*> m_trackCache;
|
|
|
|
std::map<int, Item*> m_itemCache;
|
|
Items m_clipboard;
|
|
};
|
|
|
|
} // namespace LtsTimeline
|