This commit is contained in:
2026-05-14 13:30:06 +08:00
parent 974946cee4
commit e43171521d
91 changed files with 10485 additions and 3254 deletions
+61 -15
View File
@@ -1,5 +1,7 @@
#include "timeline/TimelineWidget.h"
#include "timeline/TimelineEditorModel.h"
#include <algorithm>
#include <cmath>
@@ -38,7 +40,11 @@ TimelineWidget::TimelineWidget(QWidget* parent)
// 单行紧凑:标尺 + 轨道(帧号画在播放头处,随坐标轴滚动)
setMinimumHeight(kRulerHeight + 18 + 6);
setFocusPolicy(Qt::StrongFocus);
setToolTip(QStringLiteral("片段时间轴(固定 0-600):左键拖动播放头;滚轮:逐帧"));
setToolTip({});
}
void TimelineWidget::setModel(TimelineEditorModel* model) {
m_model = model;
}
void TimelineWidget::resizeEvent(QResizeEvent* e) {
@@ -47,8 +53,10 @@ void TimelineWidget::resizeEvent(QResizeEvent* e) {
}
void TimelineWidget::setFrameRange(int start, int end) {
(void)start;
(void)end;
m_start = std::max(0, start);
m_end = std::max(m_start + 1, end);
m_currentFrame = std::clamp(m_currentFrame, m_start, m_end - 1);
setSelectionRange(m_selStart, m_selEnd);
update();
}
@@ -57,7 +65,7 @@ void TimelineWidget::setCurrentFrame(int frame) {
}
void TimelineWidget::setCurrentFrameProgrammatic(int frame) {
const int f = std::clamp(frame, kStart, kEnd - 1);
const int f = std::clamp(frame, m_start, m_end - 1);
if (m_currentFrame == f) {
return;
}
@@ -74,8 +82,8 @@ void TimelineWidget::setSelectionRange(int start, int end) {
}
const int lo = std::min(start, end);
const int hi = std::max(start, end);
m_selStart = std::clamp(lo, kStart, kEnd - 1);
m_selEnd = std::clamp(hi, m_selStart, kEnd - 1);
m_selStart = std::clamp(lo, m_start, m_end - 1);
m_selEnd = std::clamp(hi, m_selStart, m_end - 1);
update();
}
@@ -111,6 +119,29 @@ void TimelineWidget::setKeyframeTracks(const QVector<int>& locFrames,
m_selKeyFrame = -1;
emit keyframeSelectionChanged(m_selKeyKind, m_selKeyFrame);
}
if (m_model) {
QVector<TimelineEditorModel::TrackView> tracks;
tracks.reserve(4);
tracks.push_back({TimelineEditorModel::TrackKind::Image, QStringLiteral("图像"), QColor(70, 130, 240), m_imgFrames});
tracks.push_back({TimelineEditorModel::TrackKind::Location, QStringLiteral("位置"), QColor(240, 110, 40), m_locFrames});
tracks.push_back({TimelineEditorModel::TrackKind::UserScale, QStringLiteral("缩放"), QColor(80, 190, 90), m_scaleFrames});
tracks.push_back({TimelineEditorModel::TrackKind::Visibility, QStringLiteral("显隐"), QColor(160, 100, 230), m_visFrames});
m_model->setTracks(std::move(tracks));
if (m_selKeyKind == KeyKind::None) {
m_model->clearSelection();
} else {
TimelineEditorModel::TrackKind kind = TimelineEditorModel::TrackKind::Location;
switch (m_selKeyKind) {
case KeyKind::Location: kind = TimelineEditorModel::TrackKind::Location; break;
case KeyKind::UserScale: kind = TimelineEditorModel::TrackKind::UserScale; break;
case KeyKind::Image: kind = TimelineEditorModel::TrackKind::Image; break;
case KeyKind::Visibility: kind = TimelineEditorModel::TrackKind::Visibility; break;
default: break;
}
m_model->setSelectedKey({kind, m_selKeyFrame});
}
m_model->setInterval(m_selStart, m_selEnd);
}
update();
}
@@ -131,6 +162,21 @@ void TimelineWidget::setToolKeyframeTracks(const QVector<int>& locFrames,
m_selKeyFrame = -1;
emit keyframeSelectionChanged(m_selKeyKind, m_selKeyFrame);
}
if (m_model) {
QVector<TimelineEditorModel::TrackView> tracks;
tracks.reserve(2);
tracks.push_back({TimelineEditorModel::TrackKind::Location, QStringLiteral("位置"), QColor(240, 110, 40), m_locFrames});
tracks.push_back({TimelineEditorModel::TrackKind::Visibility, QStringLiteral("显隐"), QColor(160, 100, 230), m_visFrames});
m_model->setTracks(std::move(tracks));
if (m_selKeyKind == KeyKind::None) {
m_model->clearSelection();
} else {
TimelineEditorModel::TrackKind kind = TimelineEditorModel::TrackKind::Location;
if (m_selKeyKind == KeyKind::Visibility) kind = TimelineEditorModel::TrackKind::Visibility;
m_model->setSelectedKey({kind, m_selKeyFrame});
}
m_model->setInterval(m_selStart, m_selEnd);
}
update();
}
@@ -151,8 +197,8 @@ QRect TimelineWidget::keyAreaRect() const {
}
double TimelineWidget::frameToXf(double frame) const {
const double pxf = double(contentWidth()) / double(std::max(1, kEnd - kStart));
return double(contentLeft()) + (frame - double(kStart)) * pxf;
const double pxf = double(contentWidth()) / double(std::max(1, m_end - m_start));
return double(contentLeft()) + (frame - double(m_start)) * pxf;
}
int TimelineWidget::frameToX(int frame) const {
@@ -160,8 +206,8 @@ int TimelineWidget::frameToX(int frame) const {
}
double TimelineWidget::xToFramef(int x) const {
const double pxf = double(contentWidth()) / double(std::max(1, kEnd - kStart));
return double(kStart) + double(x - contentLeft()) / std::max(pxf, 1e-9);
const double pxf = double(contentWidth()) / double(std::max(1, m_end - m_start));
return double(m_start) + double(x - contentLeft()) / std::max(pxf, 1e-9);
}
int TimelineWidget::xToFrame(int x) const {
@@ -169,7 +215,7 @@ int TimelineWidget::xToFrame(int x) const {
}
void TimelineWidget::setFrameInternal(int frame, bool commit) {
const int f = std::clamp(frame, kStart, kEnd - 1);
const int f = std::clamp(frame, m_start, m_end - 1);
// 松手时若帧未变:只发 committed,禁止再发 scrubbed,否则主窗口会双次求值/刷新导致帧号与红线闪烁
if (m_currentFrame == f) {
if (commit) {
@@ -194,9 +240,9 @@ void TimelineWidget::paintEvent(QPaintEvent*) {
const QRect cr = contentRect();
const QRect kr = keyAreaRect();
const QRect rr = rulerRect();
const double fLeft = double(kStart);
const int visMin = kStart;
const int visMax = kEnd;
const double fLeft = double(m_start);
const int visMin = m_start;
const int visMax = m_end;
auto frameVisible = [&](int fr) { return fr >= visMin && fr <= visMax; };
@@ -292,7 +338,7 @@ void TimelineWidget::paintEvent(QPaintEvent*) {
p.setBrush(palette().alternateBase());
p.drawRoundedRect(rr, 3, 3);
const double pxf = double(contentWidth()) / double(std::max(1, kEnd - kStart));
const double pxf = double(contentWidth()) / double(std::max(1, m_end - m_start));
const int major = pickMajorStep(pxf);
const int minor = pickMinorStep(major);
QPen minorPen(QColor(60, 60, 60, 100));