various: extended marker and timeline functionality
This commit is contained in:
@@ -50,6 +50,7 @@ void ResizableTimelineScrollBar::ConnectTimelinePoints(TimelinePoints *points)
|
||||
disconnect(points_->workarea(), &TimelineWorkArea::EnabledChanged, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
|
||||
disconnect(points_->markers(), &TimelineMarkerList::MarkerAdded, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
|
||||
disconnect(points_->markers(), &TimelineMarkerList::MarkerRemoved, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
|
||||
disconnect(points_->markers(), &TimelineMarkerList::MarkerModified, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
|
||||
}
|
||||
|
||||
points_ = points;
|
||||
@@ -59,6 +60,7 @@ void ResizableTimelineScrollBar::ConnectTimelinePoints(TimelinePoints *points)
|
||||
connect(points_->workarea(), &TimelineWorkArea::EnabledChanged, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
|
||||
connect(points_->markers(), &TimelineMarkerList::MarkerAdded, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
|
||||
connect(points_->markers(), &TimelineMarkerList::MarkerRemoved, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
|
||||
connect(points_->markers(), &TimelineMarkerList::MarkerModified, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
|
||||
}
|
||||
|
||||
update();
|
||||
@@ -77,7 +79,7 @@ void ResizableTimelineScrollBar::paintEvent(QPaintEvent *event)
|
||||
|
||||
if (points_
|
||||
&& !timebase().isNull()
|
||||
&& (points_->workarea()->enabled() || !points_->markers()->list().empty())) {
|
||||
&& (points_->workarea()->enabled() || !points_->markers()->empty())) {
|
||||
QStyleOptionSlider opt;
|
||||
initStyleOption(&opt);
|
||||
|
||||
@@ -110,11 +112,13 @@ void ResizableTimelineScrollBar::paintEvent(QPaintEvent *event)
|
||||
workarea_color);
|
||||
}
|
||||
|
||||
if (!points_->markers()->list().empty()) {
|
||||
foreach (TimelineMarker* marker, points_->markers()->list()) {
|
||||
if (!points_->markers()->empty()) {
|
||||
for (auto it=points_->markers()->cbegin(); it!=points_->markers()->cend(); it++) {
|
||||
TimelineMarker* marker = *it;
|
||||
|
||||
QColor marker_color = ColorCoding::GetColor(marker->color()).toQColor();
|
||||
int64_t in = qRound64(ratio * TimeToScene(marker->time().in()));
|
||||
int64_t out = qRound64(ratio * TimeToScene(marker->time().out()));
|
||||
int64_t in = qRound64(ratio * TimeToScene(marker->time_range().in()));
|
||||
int64_t out = qRound64(ratio * TimeToScene(marker->time_range().out()));
|
||||
int64_t length = qMax(int64_t(1), out-in);
|
||||
|
||||
p.fillRect(gr.x() + in,
|
||||
|
||||
@@ -153,36 +153,54 @@ public:
|
||||
for (int i=0; i<selected_.size(); i++) {
|
||||
T *obj = selected_.at(i);
|
||||
|
||||
dragging_[i] = {obj->time(), view_->TimeToScene(obj->time())};
|
||||
dragging_[i] = obj->time();
|
||||
}
|
||||
|
||||
drag_mouse_start_ = view_->mapToScene(event->pos());
|
||||
}
|
||||
|
||||
void DragMove(QMouseEvent *event, const QString &tip_format)
|
||||
void DragMove(QMouseEvent *event, const QString &tip_format = QString())
|
||||
{
|
||||
QPointF diff = view_->mapToScene(event->pos()) - drag_mouse_start_;
|
||||
rational time_diff = view_->SceneToTimeNoGrid(view_->mapToScene(event->pos()).x() - drag_mouse_start_.x());
|
||||
|
||||
// Validate movement
|
||||
for (int i=0; i<selected_.size(); i++) {
|
||||
rational proposed_time = view_->SceneToTimeNoGrid(dragging_.at(i).x + diff.x());
|
||||
rational proposed_time = dragging_.at(i) + time_diff;
|
||||
T *sel = selected_.at(i);
|
||||
|
||||
// Magic number: use interval of 1ms to avoid collisions
|
||||
rational adj(1, 1000);
|
||||
if (dragging_.at(i).time < proposed_time) {
|
||||
if (dragging_.at(i) < proposed_time) {
|
||||
// Negate adjustment value if origin is less than proposed time
|
||||
adj = -adj;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
NodeKeyframe *key_at_time = sel->parent()->GetKeyframeAtTimeOnTrack(sel->input(), proposed_time, sel->track(), sel->element());
|
||||
if (!key_at_time || key_at_time == sel) {
|
||||
break;
|
||||
bool loop;
|
||||
do {
|
||||
loop = false;
|
||||
while (sel->has_sibling_at_time(proposed_time)) {
|
||||
proposed_time += adj;
|
||||
}
|
||||
|
||||
proposed_time += adj;
|
||||
}
|
||||
if (proposed_time < 0) {
|
||||
// Prevent any object from going below zero
|
||||
proposed_time = 0;
|
||||
|
||||
sel->set_time(proposed_time);
|
||||
// Setting our proposed time to zero may (re)introduce a conflict that we just avoided
|
||||
// with the sibling check above, so we request it to happen again. To avoid a negative
|
||||
// adj bringing us back below zero, we force adj to positive so it'll only nudge higher
|
||||
adj = qAbs(adj);
|
||||
|
||||
loop = true;
|
||||
}
|
||||
} while (loop);
|
||||
|
||||
time_diff = proposed_time - dragging_.at(i);
|
||||
}
|
||||
|
||||
// Apply movement
|
||||
for (int i=0; i<selected_.size(); i++) {
|
||||
selected_.at(i)->set_time(dragging_.at(i) + time_diff);
|
||||
}
|
||||
|
||||
// Show information about this keyframe
|
||||
@@ -202,7 +220,7 @@ public:
|
||||
QToolTip::hideText();
|
||||
|
||||
for (int i=0; i<selected_.size(); i++) {
|
||||
command->add_child(new SetTimeCommand(selected_.at(i), selected_.at(i)->time(), dragging_.at(i).time));
|
||||
command->add_child(new SetTimeCommand(selected_.at(i), selected_.at(i)->time(), dragging_.at(i)));
|
||||
}
|
||||
|
||||
dragging_.clear();
|
||||
@@ -271,7 +289,7 @@ private:
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return key_->parent()->project();
|
||||
return Project::GetProjectFromObject(key_);
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -300,13 +318,7 @@ private:
|
||||
|
||||
QVector<T*> selected_;
|
||||
|
||||
struct DragObject
|
||||
{
|
||||
rational time;
|
||||
double x;
|
||||
};
|
||||
|
||||
QVector<DragObject> dragging_;
|
||||
QVector<rational> dragging_;
|
||||
|
||||
T *initial_drag_item_;
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "common/timecodefunctions.h"
|
||||
#include "config/config.h"
|
||||
#include "core.h"
|
||||
#include "dialog/markerproperties/markerpropertiesdialog.h"
|
||||
#include "node/project/sequence/sequence.h"
|
||||
#include "widget/timelinewidget/undo/timelineundoworkarea.h"
|
||||
|
||||
@@ -588,29 +589,36 @@ void TimeBasedWidget::SetMarker()
|
||||
return;
|
||||
}
|
||||
|
||||
bool ok;
|
||||
QString marker_name;
|
||||
TimelineMarkerList *markers = GetConnectedNode()->GetTimelinePoints()->markers();
|
||||
|
||||
if (Config::Current()[QStringLiteral("SetNameWithMarker")].toBool()) {
|
||||
marker_name = QInputDialog::getText(this, tr("Add Marker"), tr("Name:"), QLineEdit::Normal, QString(), &ok);
|
||||
if (TimelineMarker *existing = markers->GetMarkerAtTime(GetTime())) {
|
||||
// We already have a marker here, so pop open the edit dialog
|
||||
MarkerPropertiesDialog mpd({existing}, timebase(), this);
|
||||
mpd.exec();
|
||||
} else {
|
||||
ok = true;
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
// Create a new marker and place it here
|
||||
int color;
|
||||
|
||||
TimelineMarkerList *markers = GetConnectedNode()->GetTimelinePoints()->markers();
|
||||
|
||||
if (!markers->list().empty()) {
|
||||
// Use last invoked color if applicable
|
||||
color = markers->list().back()->color();
|
||||
if (TimelineMarker *closest = markers->GetClosestMarkerToTime(GetTime())) {
|
||||
// Copy color of closest marker to this time
|
||||
color = closest->color();
|
||||
} else {
|
||||
// Fallback to default color in preferences
|
||||
color = Config::Current()[QStringLiteral("MarkerColor")].toInt();
|
||||
}
|
||||
|
||||
Core::instance()->undo_stack()->push(new MarkerAddCommand(markers, TimeRange(GetTime(), GetTime()), marker_name, color));
|
||||
TimelineMarker *marker = new TimelineMarker(color, TimeRange(GetTime(), GetTime()));
|
||||
|
||||
if (Config::Current()[QStringLiteral("SetNameWithMarker")].toBool()) {
|
||||
MarkerPropertiesDialog mpd({marker}, timebase(), this);
|
||||
if (mpd.exec() != QDialog::Accepted) {
|
||||
delete marker;
|
||||
marker = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (marker) {
|
||||
Core::instance()->undo_stack()->push(new MarkerAddCommand(markers, marker));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1798,13 +1798,15 @@ bool TimelineWidget::SnapPoint(QVector<rational> start_times, rational* movement
|
||||
}
|
||||
|
||||
if ((snap_points & kSnapToMarkers)) {
|
||||
foreach (TimelineMarker* m, GetConnectedNode()->GetTimelinePoints()->markers()->list()) {
|
||||
qreal marker_pos = TimeToScene(m->time().in());
|
||||
potential_snaps.append(AttemptSnap(screen_pt, marker_pos, start_times, m->time().in()));
|
||||
for (auto it=GetConnectedNode()->GetTimelinePoints()->markers()->cbegin(); it!=GetConnectedNode()->GetTimelinePoints()->markers()->cend(); it++) {
|
||||
TimelineMarker* m = *it;
|
||||
|
||||
if (m->time().in() != m->time().out()) {
|
||||
marker_pos = TimeToScene(m->time().out());
|
||||
potential_snaps.append(AttemptSnap(screen_pt, marker_pos, start_times, m->time().out()));
|
||||
qreal marker_pos = TimeToScene(m->time_range().in());
|
||||
potential_snaps.append(AttemptSnap(screen_pt, marker_pos, start_times, m->time_range().in()));
|
||||
|
||||
if (m->time_range().in() != m->time_range().out()) {
|
||||
marker_pos = TimeToScene(m->time_range().out());
|
||||
potential_snaps.append(AttemptSnap(screen_pt, marker_pos, start_times, m->time_range().out()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ void TimelineView::mousePressEvent(QMouseEvent *event)
|
||||
if (rect.contains(mapToScene(event->pos()))) {
|
||||
TimelinePanel *timeline = PanelManager::instance()->MostRecentlyFocused<TimelinePanel>();
|
||||
if (timeline) {
|
||||
timeline->timeline_widget()->SetTime(clip_marker_positions_.key(rect)->time().in());
|
||||
timeline->timeline_widget()->SetTime(clip_marker_positions_.key(rect)->time_range().in());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -510,58 +510,43 @@ void TimelineView::DrawBlock(QPainter *painter, bool foreground, Block *block, q
|
||||
SceneToTime(block_left - block_in, GetScale(), connected_track_list_->parent()->GetAudioParams().sample_rate_as_time_base()));
|
||||
}
|
||||
|
||||
// Draw zebra stripes
|
||||
if (clip->connected_viewer() && !clip->connected_viewer()->GetLength().isNull()) {
|
||||
if (clip->media_in() < 0) {
|
||||
// Draw stripes for sections of clip < 0
|
||||
qreal zebra_right = TimeToScene(-clip->media_in());
|
||||
if (zebra_right > GetTimelineLeftBound()) {
|
||||
DrawZebraStripes(painter, QRectF(block_left, block_top, zebra_right, block_height));
|
||||
// Draw zebra stripes and markers
|
||||
if (clip->connected_viewer()) {
|
||||
if (!clip->connected_viewer()->GetLength().isNull()) {
|
||||
if (clip->media_in() < 0) {
|
||||
// Draw stripes for sections of clip < 0
|
||||
qreal zebra_right = TimeToScene(-clip->media_in());
|
||||
if (zebra_right > GetTimelineLeftBound()) {
|
||||
DrawZebraStripes(painter, QRectF(block_left, block_top, zebra_right, block_height));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (clip->length() + clip->media_in() > clip->connected_viewer()->GetLength()) {
|
||||
// Draw stripes for sections for clip > clip length
|
||||
qreal zebra_left = TimeToScene(clip->out() - (clip->media_in() + clip->length() - clip->connected_viewer()->GetLength()));
|
||||
if (zebra_left < GetTimelineRightBound()) {
|
||||
DrawZebraStripes(painter, QRectF(zebra_left, block_top, block_right - zebra_left, block_height));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw markers
|
||||
qDebug() << "MARKERS ON CLIP STUB";
|
||||
/*if (clip->connected_viewer() && !clip->connected_viewer()->GetLength().isNull()) {
|
||||
if (clip->connected_viewer()->GetTimelinePoints()->markers()->list().size() > 0) {
|
||||
std::vector<TimelineMarker *> marker_list = clip->connected_viewer()->GetTimelinePoints()->markers()->list();
|
||||
|
||||
int marker_width = QtUtils::QFontMetricsWidth(fm, "H");
|
||||
clip_marker_positions_.clear();
|
||||
|
||||
// Only draw markers if the block UI is large enough to draw all the markers
|
||||
if (marker_list.size() * marker_width < block_right - block_left) {
|
||||
|
||||
for (auto it=marker_list.cbegin(); it!=marker_list.cend(); it++) {
|
||||
TimelineMarker *marker = *it;
|
||||
// Make sure marker is within In/Out points of the clip
|
||||
if (marker->time().in() >= clip->media_in() && marker->time().out() <= clip->media_in() + clip->length()) {
|
||||
// Only draw names that we have room for
|
||||
bool draw_name = true;
|
||||
if (!marker->name().isEmpty()) {
|
||||
int length = fm.horizontalAdvance(marker->name());
|
||||
if (iterator.hasNext()) {
|
||||
if (TimeToScene(iterator.peekNext()->time().in()) - TimeToScene(marker->time().out()) < (double)length) {
|
||||
draw_name = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
DrawClipMarker(painter, TimeToScene(clip->in() - clip->media_in() + marker->time().in()),
|
||||
block_top + block_height, marker, draw_name);
|
||||
}
|
||||
if (clip->length() + clip->media_in() > clip->connected_viewer()->GetLength()) {
|
||||
// Draw stripes for sections for clip > clip length
|
||||
qreal zebra_left = TimeToScene(clip->out() - (clip->media_in() + clip->length() - clip->connected_viewer()->GetLength()));
|
||||
if (zebra_left < GetTimelineRightBound()) {
|
||||
DrawZebraStripes(painter, QRectF(zebra_left, block_top, block_right - zebra_left, block_height));
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
TimelineMarkerList *marker_list = clip->connected_viewer()->GetTimelinePoints()->markers();
|
||||
if (!marker_list->empty()) {
|
||||
|
||||
clip_marker_positions_.clear();
|
||||
|
||||
for (auto it=marker_list->cbegin(); it!=marker_list->cend(); it++) {
|
||||
TimelineMarker *marker = *it;
|
||||
// Make sure marker is within In/Out points of the clip
|
||||
if (marker->time_range().in() >= clip->media_in() && marker->time_range().out() <= clip->media_in() + clip->length()) {
|
||||
QPoint marker_pt(TimeToScene(clip->in() - clip->media_in() + marker->time_range().in()), block_top + block_height);
|
||||
painter->setClipRect(r);
|
||||
marker->Draw(painter, marker_pt, GetScale(), false);
|
||||
painter->setClipping(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For transitions, show lines representing a transition
|
||||
@@ -631,46 +616,6 @@ void TimelineView::DrawZebraStripes(QPainter *painter, const QRectF &r)
|
||||
painter->setClipping(false);
|
||||
}
|
||||
|
||||
void TimelineView::DrawClipMarker(QPainter* painter, double marker_x, qreal marker_y, TimelineMarker* marker, bool draw_name)
|
||||
{
|
||||
QFontMetrics fm = fontMetrics();
|
||||
|
||||
int marker_height = fm.height();
|
||||
int marker_width = QtUtils::QFontMetricsWidth(fm, "H");
|
||||
|
||||
int y = marker_y - 1;
|
||||
|
||||
int half_width = marker_width / 2;
|
||||
|
||||
int x = marker_x + half_width;
|
||||
|
||||
painter->setPen(Qt::black);
|
||||
|
||||
painter->setBrush(ColorCoding::GetColor(marker->color()).toQColor());
|
||||
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
int half_marker_height = marker_height / 3;
|
||||
|
||||
QPoint points[] = {
|
||||
QPoint(x, y),
|
||||
QPoint(x - half_width, y - half_marker_height),
|
||||
QPoint(x - half_width, y - marker_height),
|
||||
QPoint(x + 1 + half_width, y - marker_height),
|
||||
QPoint(x + 1 + half_width, y - half_marker_height),
|
||||
QPoint(x + 1, y),
|
||||
};
|
||||
|
||||
painter->drawPolygon(points, 6);
|
||||
|
||||
if (!marker->name().isEmpty() && draw_name) {
|
||||
painter->drawText(x + marker_width, y - half_marker_height, marker->name());
|
||||
}
|
||||
|
||||
QPointF scenePos = QPoint(x - half_width, y);
|
||||
clip_marker_positions_.insert(marker, (QRectF(scenePos, QSize(marker_width, -marker_height))));
|
||||
}
|
||||
|
||||
int TimelineView::GetHeightOfAllTracks() const
|
||||
{
|
||||
if (connected_track_list_) {
|
||||
|
||||
@@ -132,8 +132,6 @@ private:
|
||||
|
||||
void DrawZebraStripes(QPainter *painter, const QRectF &r);
|
||||
|
||||
void DrawClipMarker(QPainter* painter, double marker_x, qreal marker_y, TimelineMarker* marker, bool draw_name);
|
||||
|
||||
int GetHeightOfAllTracks() const;
|
||||
|
||||
void UpdatePlayheadRect();
|
||||
|
||||
@@ -20,12 +20,16 @@
|
||||
|
||||
#include "seekablewidget.h"
|
||||
|
||||
#include <QInputDialog>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QtMath>
|
||||
|
||||
#include "common/qtutils.h"
|
||||
#include "core.h"
|
||||
#include "dialog/markerproperties/markerpropertiesdialog.h"
|
||||
#include "widget/colorlabelmenu/colorlabelmenu.h"
|
||||
#include "widget/menu/menushared.h"
|
||||
#include "widget/timebased/timebasedwidget.h"
|
||||
|
||||
namespace olive {
|
||||
@@ -34,8 +38,10 @@ namespace olive {
|
||||
|
||||
SeekableWidget::SeekableWidget(QWidget* parent) :
|
||||
super(parent),
|
||||
NodeCopyPasteService(QStringLiteral("markers")),
|
||||
timeline_points_(nullptr),
|
||||
dragging_(false),
|
||||
ignore_next_focus_out_(false),
|
||||
selection_manager_(this)
|
||||
{
|
||||
QFontMetrics fm = fontMetrics();
|
||||
@@ -54,19 +60,21 @@ void SeekableWidget::ConnectTimelinePoints(TimelinePoints *points)
|
||||
if (timeline_points_) {
|
||||
selection_manager_.ClearSelection();
|
||||
|
||||
disconnect(timeline_points_->workarea(), &TimelineWorkArea::RangeChanged, this, static_cast<void (SeekableWidget::*)()>(&SeekableWidget::update));
|
||||
disconnect(timeline_points_->workarea(), &TimelineWorkArea::EnabledChanged, this, static_cast<void (SeekableWidget::*)()>(&SeekableWidget::update));
|
||||
disconnect(timeline_points_->markers(), &TimelineMarkerList::MarkerAdded, this, static_cast<void (SeekableWidget::*)()>(&SeekableWidget::update));
|
||||
disconnect(timeline_points_->markers(), &TimelineMarkerList::MarkerRemoved, this, static_cast<void (SeekableWidget::*)()>(&SeekableWidget::update));
|
||||
disconnect(timeline_points_->workarea(), &TimelineWorkArea::RangeChanged, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
|
||||
disconnect(timeline_points_->workarea(), &TimelineWorkArea::EnabledChanged, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
|
||||
disconnect(timeline_points_->markers(), &TimelineMarkerList::MarkerAdded, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
|
||||
disconnect(timeline_points_->markers(), &TimelineMarkerList::MarkerRemoved, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
|
||||
disconnect(timeline_points_->markers(), &TimelineMarkerList::MarkerModified, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
|
||||
}
|
||||
|
||||
timeline_points_ = points;
|
||||
|
||||
if (timeline_points_) {
|
||||
connect(timeline_points_->workarea(), &TimelineWorkArea::RangeChanged, this, static_cast<void (SeekableWidget::*)()>(&SeekableWidget::update));
|
||||
connect(timeline_points_->workarea(), &TimelineWorkArea::EnabledChanged, this, static_cast<void (SeekableWidget::*)()>(&SeekableWidget::update));
|
||||
connect(timeline_points_->markers(), &TimelineMarkerList::MarkerAdded, this, static_cast<void (SeekableWidget::*)()>(&SeekableWidget::update));
|
||||
connect(timeline_points_->markers(), &TimelineMarkerList::MarkerRemoved, this, static_cast<void (SeekableWidget::*)()>(&SeekableWidget::update));
|
||||
connect(timeline_points_->workarea(), &TimelineWorkArea::RangeChanged, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
|
||||
connect(timeline_points_->workarea(), &TimelineWorkArea::EnabledChanged, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
|
||||
connect(timeline_points_->markers(), &TimelineMarkerList::MarkerAdded, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
|
||||
connect(timeline_points_->markers(), &TimelineMarkerList::MarkerRemoved, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
|
||||
connect(timeline_points_->markers(), &TimelineMarkerList::MarkerModified, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
|
||||
}
|
||||
|
||||
viewport()->update();
|
||||
@@ -102,7 +110,9 @@ void SeekableWidget::PasteMarkers(bool insert, rational insert_time)
|
||||
|
||||
void SeekableWidget::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
if (TimelineMarker *initial = selection_manager_.MousePress(event)) {
|
||||
selection_manager_.DragStart(initial, event);
|
||||
} else if (!selection_manager_.GetObjectAtPoint(event->pos()) && event->button() == Qt::LeftButton) {
|
||||
SeekToScenePoint(mapToScene(event->pos()).x());
|
||||
dragging_ = true;
|
||||
|
||||
@@ -112,14 +122,20 @@ void SeekableWidget::mousePressEvent(QMouseEvent *event)
|
||||
|
||||
void SeekableWidget::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->buttons() & Qt::LeftButton) {
|
||||
if (selection_manager_.IsDragging()) {
|
||||
selection_manager_.DragMove(event);
|
||||
} else if (dragging_) {
|
||||
SeekToScenePoint(mapToScene(event->pos()).x());
|
||||
}
|
||||
}
|
||||
|
||||
void SeekableWidget::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
if (selection_manager_.IsDragging()) {
|
||||
MultiUndoCommand *command = new MultiUndoCommand();
|
||||
selection_manager_.DragStop(command);
|
||||
Core::instance()->undo_stack()->pushIfHasChildren(command);
|
||||
}
|
||||
|
||||
if (GetSnapService()) {
|
||||
GetSnapService()->HideSnaps();
|
||||
@@ -128,12 +144,25 @@ void SeekableWidget::mouseReleaseEvent(QMouseEvent *event)
|
||||
dragging_ = false;
|
||||
}
|
||||
|
||||
void SeekableWidget::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
{
|
||||
super::mouseDoubleClickEvent(event);
|
||||
|
||||
if (selection_manager_.GetObjectAtPoint(event->pos()) && !selection_manager_.GetSelectedObjects().isEmpty()) {
|
||||
ShowMarkerProperties();
|
||||
}
|
||||
}
|
||||
|
||||
void SeekableWidget::focusOutEvent(QFocusEvent *event)
|
||||
{
|
||||
super::focusOutEvent(event);
|
||||
|
||||
// Deselect everything when we lose focus
|
||||
DeselectAllMarkers();
|
||||
if (ignore_next_focus_out_) {
|
||||
ignore_next_focus_out_ = false;
|
||||
} else {
|
||||
// Deselect everything when we lose focus
|
||||
DeselectAllMarkers();
|
||||
}
|
||||
}
|
||||
|
||||
TimelinePoints *SeekableWidget::timeline_points() const
|
||||
@@ -159,6 +188,20 @@ void SeekableWidget::SetMarkerColor(int c)
|
||||
Core::instance()->undo_stack()->pushIfHasChildren(command);
|
||||
}
|
||||
|
||||
void SeekableWidget::ShowMarkerProperties()
|
||||
{
|
||||
MarkerPropertiesDialog mpd(selection_manager_.GetSelectedObjects(), timebase(), this);
|
||||
ignore_next_focus_out_ = true;
|
||||
mpd.exec();
|
||||
}
|
||||
|
||||
void SeekableWidget::TimebaseChangedEvent(const rational &t)
|
||||
{
|
||||
super::TimebaseChangedEvent(t);
|
||||
|
||||
selection_manager_.SetTimebase(t);
|
||||
}
|
||||
|
||||
void SeekableWidget::SeekToScenePoint(qreal scene)
|
||||
{
|
||||
if (timebase().isNull()) {
|
||||
@@ -171,8 +214,8 @@ void SeekableWidget::SeekToScenePoint(qreal scene)
|
||||
rational movement;
|
||||
|
||||
GetSnapService()->SnapPoint({playhead_time},
|
||||
&movement,
|
||||
SnapService::kSnapAll & ~SnapService::kSnapToPlayhead);
|
||||
&movement,
|
||||
SnapService::kSnapAll & ~SnapService::kSnapToPlayhead);
|
||||
|
||||
playhead_time += movement;
|
||||
}
|
||||
@@ -184,56 +227,62 @@ void SeekableWidget::SeekToScenePoint(qreal scene)
|
||||
}
|
||||
}
|
||||
|
||||
void SeekableWidget::SelectionManagerSelectEvent(void *obj)
|
||||
{
|
||||
super::SelectionManagerSelectEvent(obj);
|
||||
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
void SeekableWidget::SelectionManagerDeselectEvent(void *obj)
|
||||
{
|
||||
super::SelectionManagerDeselectEvent(obj);
|
||||
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
void SeekableWidget::DrawTimelinePoints(QPainter* p, int marker_bottom)
|
||||
{
|
||||
if (!timeline_points()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int lim_left = GetScroll();
|
||||
int lim_right = lim_left + width();
|
||||
|
||||
selection_manager_.ClearDrawnObjects();
|
||||
|
||||
// Draw in/out workarea
|
||||
if (timeline_points()->workarea()->enabled()) {
|
||||
int workarea_left = qMax(0.0, TimeToScene(timeline_points()->workarea()->in()));
|
||||
int workarea_left = qMax(qreal(lim_left), TimeToScene(timeline_points()->workarea()->in()));
|
||||
int workarea_right;
|
||||
|
||||
if (timeline_points()->workarea()->out() == TimelineWorkArea::kResetOut) {
|
||||
workarea_right = width();
|
||||
workarea_right = lim_right;
|
||||
} else {
|
||||
workarea_right = qMin(qreal(width()), TimeToScene(timeline_points()->workarea()->out()));
|
||||
workarea_right = qMin(qreal(lim_right), TimeToScene(timeline_points()->workarea()->out()));
|
||||
}
|
||||
|
||||
p->fillRect(workarea_left, 0, workarea_right - workarea_left, height(), palette().highlight());
|
||||
}
|
||||
|
||||
// Draw markers
|
||||
if (marker_bottom > 0 && !timeline_points()->markers()->list().empty()) {
|
||||
if (marker_bottom > 0 && !timeline_points()->markers()->empty()) {
|
||||
for (auto it=timeline_points()->markers()->cbegin(); it!=timeline_points()->markers()->cend(); it++) {
|
||||
TimelineMarker* marker = *it;
|
||||
|
||||
int marker_top = marker_bottom - text_height_;
|
||||
|
||||
// FIXME: Hardcoded marker colors
|
||||
p->setPen(Qt::black);
|
||||
p->setBrush(Qt::green);
|
||||
|
||||
foreach (TimelineMarker* marker, timeline_points()->markers()->list()) {
|
||||
int marker_left = TimeToScene(marker->time().in());
|
||||
int marker_right = TimeToScene(marker->time().out());
|
||||
|
||||
if (marker_left >= width() || marker_right < 0) {
|
||||
int marker_right = TimeToScene(marker->time_range().out());
|
||||
if (marker_right < lim_left) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (marker->time().length() != 0) {
|
||||
// Marker range
|
||||
int rect_left = qMax(0, marker_left);
|
||||
int rect_right = qMin(width(), marker_right);
|
||||
|
||||
QRect marker_rect(rect_left, marker_top, rect_right - rect_left, marker_bottom - marker_top);
|
||||
|
||||
p->drawRect(marker_rect);
|
||||
|
||||
if (!marker->name().isEmpty()) {
|
||||
p->drawText(marker_rect, marker->name());
|
||||
}
|
||||
int marker_left = TimeToScene(marker->time_range().in());
|
||||
if (marker_left >= lim_right) {
|
||||
break;
|
||||
}
|
||||
|
||||
QRect marker_rect = marker->Draw(p, QPoint(marker_left, marker_bottom), GetScale(), selection_manager_.IsSelected(marker));
|
||||
selection_manager_.DeclareDrawnObject(marker, marker_rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -264,4 +313,31 @@ void SeekableWidget::DrawPlayhead(QPainter *p, int x, int y)
|
||||
p->setRenderHint(QPainter::Antialiasing, false);
|
||||
}
|
||||
|
||||
bool SeekableWidget::ShowContextMenu(const QPoint &p)
|
||||
{
|
||||
if (selection_manager_.GetObjectAtPoint(p) && !selection_manager_.GetSelectedObjects().isEmpty()) {
|
||||
// Show marker-specific menu
|
||||
Menu m;
|
||||
|
||||
ColorLabelMenu color_coding_menu;
|
||||
connect(&color_coding_menu, &ColorLabelMenu::ColorSelected, this, &SeekableWidget::SetMarkerColor);
|
||||
m.addMenu(&color_coding_menu);
|
||||
|
||||
m.addSeparator();
|
||||
|
||||
MenuShared::instance()->AddItemsForEditMenu(&m, false);
|
||||
|
||||
m.addSeparator();
|
||||
|
||||
QAction *properties_action = m.addAction(tr("Properties"));
|
||||
connect(properties_action, &QAction::triggered, this, &SeekableWidget::ShowMarkerProperties);
|
||||
|
||||
ignore_next_focus_out_ = true;
|
||||
m.exec(mapToGlobal(p));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,14 +25,15 @@
|
||||
#include <QScrollBar>
|
||||
|
||||
#include "common/rational.h"
|
||||
#include "node/nodecopypaste.h"
|
||||
#include "timeline/timelinepoints.h"
|
||||
#include "widget/menu/menu.h"
|
||||
#include "widget/snapservice/snapservice.h"
|
||||
#include "widget/timebased/timebasedviewselectionmanager.h"
|
||||
//#include "widget/marker/markercopypaste.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class SeekableWidget : public TimeBasedView//, public MarkerCopyPasteService
|
||||
class SeekableWidget : public TimeBasedView, public NodeCopyPasteService
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -60,22 +61,22 @@ public:
|
||||
|
||||
void SeekToScenePoint(qreal scene);
|
||||
|
||||
virtual void SelectionManagerSelectEvent(void *obj) override;
|
||||
virtual void SelectionManagerDeselectEvent(void *obj) override;
|
||||
|
||||
public slots:
|
||||
void SetScroll(int i)
|
||||
{
|
||||
horizontalScrollBar()->setValue(i);
|
||||
}
|
||||
|
||||
void SetMarkerColor(int c);
|
||||
|
||||
/*void SetMarkerTime();
|
||||
|
||||
void SetMarkerName();*/
|
||||
virtual void TimebaseChangedEvent(const rational &) override;
|
||||
|
||||
protected:
|
||||
virtual void mousePressEvent(QMouseEvent *event) override;
|
||||
virtual void mouseMoveEvent(QMouseEvent *event) override;
|
||||
virtual void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
virtual void mouseDoubleClickEvent(QMouseEvent *event) override;
|
||||
|
||||
virtual void focusOutEvent(QFocusEvent *event) override;
|
||||
|
||||
@@ -93,6 +94,9 @@ protected:
|
||||
return playhead_width_;
|
||||
}
|
||||
|
||||
protected slots:
|
||||
virtual bool ShowContextMenu(const QPoint &p);
|
||||
|
||||
private:
|
||||
TimelinePoints* timeline_points_;
|
||||
|
||||
@@ -102,8 +106,15 @@ private:
|
||||
|
||||
bool dragging_;
|
||||
|
||||
bool ignore_next_focus_out_;
|
||||
|
||||
TimeBasedViewSelectionManager<TimelineMarker> selection_manager_;
|
||||
|
||||
private slots:
|
||||
void SetMarkerColor(int c);
|
||||
|
||||
void ShowMarkerProperties();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -32,8 +32,10 @@
|
||||
|
||||
namespace olive {
|
||||
|
||||
#define super SeekableWidget
|
||||
|
||||
TimeRuler::TimeRuler(bool text_visible, bool cache_status_visible, QWidget* parent) :
|
||||
SeekableWidget(parent),
|
||||
super(parent),
|
||||
text_visible_(text_visible),
|
||||
centered_text_(true),
|
||||
show_cache_status_(cache_status_visible),
|
||||
@@ -102,18 +104,9 @@ void TimeRuler::drawForeground(QPainter *p, const QRectF &rect)
|
||||
}
|
||||
|
||||
// Draw timeline points if connected
|
||||
int marker_height = TimelineMarker::GetMarkerHeight(p->fontMetrics());
|
||||
if (timeline_points()) {
|
||||
int marker_bottom = height() - text_height();
|
||||
|
||||
if (show_cache_status_) {
|
||||
marker_bottom -= cache_status_height_;
|
||||
}
|
||||
|
||||
if (text_visible_) {
|
||||
marker_bottom -= cache_status_height_;
|
||||
}
|
||||
|
||||
DrawTimelinePoints(p, marker_bottom);
|
||||
DrawTimelinePoints(p, marker_height);
|
||||
}
|
||||
|
||||
double width_of_frame = timebase_dbl() * GetScale();
|
||||
@@ -222,11 +215,11 @@ void TimeRuler::drawForeground(QPainter *p, const QRectF &rect)
|
||||
int timecode_left;
|
||||
|
||||
if (centered_text_) {
|
||||
text_rect = QRect(i - kAverageTextWidth/2, 0, kAverageTextWidth, fm.height());
|
||||
text_rect = QRect(i - kAverageTextWidth/2, marker_height, kAverageTextWidth, fm.height());
|
||||
text_align = Qt::AlignCenter;
|
||||
timecode_left = i - timecode_width/2;
|
||||
} else {
|
||||
text_rect = QRect(i, 0, kAverageTextWidth, fm.height());
|
||||
text_rect = QRect(i, marker_height, kAverageTextWidth, fm.height());
|
||||
text_align = Qt::AlignLeft | Qt::AlignVCenter;
|
||||
timecode_left = i;
|
||||
|
||||
@@ -265,13 +258,15 @@ void TimeRuler::drawForeground(QPainter *p, const QRectF &rect)
|
||||
if (show_cache_status_ && playback_cache_) {
|
||||
// FIXME: Hardcoded to get video length, if we ever need audio length, this will have to change
|
||||
rational len = playback_cache_->viewer_parent()->GetVideoLength();
|
||||
int lim_left = GetScroll();
|
||||
int lim_right = lim_left + width();
|
||||
|
||||
int cache_screen_length = qMin(TimeToScene(len), qreal(width()));
|
||||
int cache_screen_length = TimeToScene(len);
|
||||
|
||||
if (cache_screen_length > 0) {
|
||||
int cache_y = height() - cache_status_height_;
|
||||
|
||||
p->fillRect(0, cache_y, cache_screen_length , cache_status_height_, Qt::green);
|
||||
p->fillRect(0, cache_y, cache_screen_length, cache_status_height_, Qt::green);
|
||||
|
||||
foreach (const TimeRange& range, playback_cache_->GetInvalidatedRanges(len)) {
|
||||
int range_left = TimeToScene(range.in());
|
||||
@@ -284,11 +279,11 @@ void TimeRuler::drawForeground(QPainter *p, const QRectF &rect)
|
||||
continue;
|
||||
}
|
||||
|
||||
int adjusted_left = qMax(0, range_left);
|
||||
int adjusted_left = qMax(lim_left, range_left);
|
||||
|
||||
p->fillRect(adjusted_left,
|
||||
cache_y,
|
||||
qMin(width(), range_right) - adjusted_left,
|
||||
qMin(lim_right, range_right) - adjusted_left,
|
||||
cache_status_height_,
|
||||
Qt::red);
|
||||
}
|
||||
@@ -304,6 +299,8 @@ void TimeRuler::drawForeground(QPainter *p, const QRectF &rect)
|
||||
|
||||
void TimeRuler::TimebaseChangedEvent(const rational &tb)
|
||||
{
|
||||
super::TimebaseChangedEvent(tb);
|
||||
|
||||
timebase_flipped_dbl_ = tb.flipped().toDouble();
|
||||
|
||||
update();
|
||||
@@ -314,14 +311,20 @@ int TimeRuler::CacheStatusHeight() const
|
||||
return fontMetrics().height() / 4;
|
||||
}
|
||||
|
||||
void TimeRuler::ShowContextMenu()
|
||||
bool TimeRuler::ShowContextMenu(const QPoint &p)
|
||||
{
|
||||
Menu m(this);
|
||||
if (super::ShowContextMenu(p)) {
|
||||
return true;
|
||||
} else {
|
||||
Menu m(this);
|
||||
|
||||
MenuShared::instance()->AddItemsForTimeRulerMenu(&m);
|
||||
MenuShared::instance()->AboutToShowTimeRulerActions(timebase());
|
||||
MenuShared::instance()->AddItemsForTimeRulerMenu(&m);
|
||||
MenuShared::instance()->AboutToShowTimeRulerActions(timebase());
|
||||
|
||||
m.exec(QCursor::pos());
|
||||
m.exec(mapToGlobal(p));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void TimeRuler::UpdateHeight()
|
||||
@@ -339,7 +342,7 @@ void TimeRuler::UpdateHeight()
|
||||
}
|
||||
|
||||
// Add marker height
|
||||
height += text_height();
|
||||
height += TimelineMarker::GetMarkerHeight(fontMetrics());
|
||||
|
||||
setFixedHeight(height);
|
||||
}
|
||||
|
||||
@@ -45,6 +45,9 @@ protected:
|
||||
|
||||
virtual void TimebaseChangedEvent(const rational& tb) override;
|
||||
|
||||
protected slots:
|
||||
virtual bool ShowContextMenu(const QPoint &p) override;
|
||||
|
||||
private:
|
||||
void UpdateHeight();
|
||||
|
||||
@@ -64,9 +67,6 @@ private:
|
||||
|
||||
PlaybackCache* playback_cache_;
|
||||
|
||||
private slots:
|
||||
void ShowContextMenu();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user