#pragma once #include class QResizeEvent; class TimelineWidget final : public QWidget { Q_OBJECT public: explicit TimelineWidget(QWidget* parent = nullptr); // 兼容旧接口:NLA/片段系统下时间轴始终固定为 0..600(local frame)。 void setFrameRange(int start, int end); void setCurrentFrame(int frame); /// 由主窗口同步工程帧时调用:不发射 frameScrubbed,避免与拖动/刷新打架造成数字闪烁 void setCurrentFrameProgrammatic(int frame); int currentFrame() const { return m_currentFrame; } void setSelectionRange(int start, int end); // -1,-1 清除 int selectionStart() const { return m_selStart; } int selectionEnd() const { return m_selEnd; } // 轨道数据直接由上层提供(通常来自当前条带引用的 clip)。 void setKeyframeTracks(const QVector& locFrames, const QVector& scaleFrames, const QVector& imgFrames, const QVector& visFrames); void setToolKeyframeTracks(const QVector& locFrames, const QVector& visFrames); enum class KeyKind { None, Location, UserScale, Image, Visibility }; KeyKind selectedKeyKind() const { return m_selKeyKind; } int selectedKeyFrame() const { return m_selKeyFrame; } bool hasSelectedKeyframe() const { return m_selKeyKind != KeyKind::None && m_selKeyFrame >= 0; } signals: void frameScrubbed(int frame); void frameCommitted(int frame); void contextMenuRequested(const QPoint& globalPos, int frame); void keyframeSelectionChanged(KeyKind kind, int frame); void intervalSelectionChanged(int start, int end); protected: void paintEvent(QPaintEvent*) override; void mousePressEvent(QMouseEvent*) override; void mouseMoveEvent(QMouseEvent*) override; void mouseReleaseEvent(QMouseEvent*) override; void wheelEvent(QWheelEvent*) override; void resizeEvent(QResizeEvent* e) override; private: int contentLeft() const { return 6; } int contentWidth() const { return std::max(1, width() - 12); } QRect contentRect() const; double frameToXf(double frame) const; int frameToX(int frame) const; double xToFramef(int x) const; int xToFrame(int x) const; QRect rulerRect() const; QRect keyAreaRect() const; void setFrameInternal(int frame, bool commit); static constexpr int kStart = 0; static constexpr int kEnd = 600; // exclusive for mapping, inclusive for UI labels int m_currentFrame = 0; // local frame: 0..599 int m_selStart = -1; int m_selEnd = -1; bool m_dragging = false; QPoint m_pressPos; bool m_moved = false; static constexpr int kRulerHeight = 14; QVector m_locFrames; QVector m_scaleFrames; QVector m_imgFrames; QVector m_visFrames; KeyKind m_selKeyKind = KeyKind::None; int m_selKeyFrame = -1; };