From ae13ccfbd1ec2fc2ad423d06123babea3242c8ac Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Tue, 3 Jul 2018 20:45:39 +0100 Subject: [PATCH] added some functionality for #97 --- effects/crossdissolvetransition.cpp | 4 ++ effects/transition.h | 4 ++ io/media.h | 6 +- io/previewgenerator.cpp | 2 +- mainwindow.cpp | 2 +- olive.pro.user | 2 +- panels/project.cpp | 23 ++++-- panels/project.h | 2 + panels/project.ui | 2 +- project/effect.cpp | 4 +- project/sequence.cpp | 15 ++++ ui/sourcetable.cpp | 34 +++++++-- ui/sourcetable.h | 8 +++ ui/timelinewidget.cpp | 107 +++++++++++++++++----------- ui/viewerwidget.cpp | 5 +- 15 files changed, 157 insertions(+), 63 deletions(-) diff --git a/effects/crossdissolvetransition.cpp b/effects/crossdissolvetransition.cpp index d1eb18835..98f1a2144 100644 --- a/effects/crossdissolvetransition.cpp +++ b/effects/crossdissolvetransition.cpp @@ -2,6 +2,10 @@ #include +CrossDissolveTransition::CrossDissolveTransition() { + name = "Cross Dissolve"; +} + void CrossDissolveTransition::process_transition(float progress) { float color[4]; glGetFloatv(GL_CURRENT_COLOR, color); diff --git a/effects/transition.h b/effects/transition.h index d77c5ae26..6c36e7cff 100644 --- a/effects/transition.h +++ b/effects/transition.h @@ -1,16 +1,20 @@ #ifndef TRANSITION_H #define TRANSITION_H +#include + class Transition { public: Transition(); int length; + QString name; virtual void process_transition(float); }; class CrossDissolveTransition : public Transition { public: + CrossDissolveTransition(); void process_transition(float); }; diff --git a/io/media.h b/io/media.h index 929bdee6b..458de3315 100644 --- a/io/media.h +++ b/io/media.h @@ -8,6 +8,10 @@ #include #include +#define MEDIA_TYPE_FOOTAGE 0 +#define MEDIA_TYPE_SEQUENCE 1 +#define MEDIA_TYPE_FOLDER 2 + struct Sequence; struct MediaStream { @@ -31,7 +35,7 @@ struct Media QString url; QString name; - bool is_sequence; + char type; int64_t length; QVector video_tracks; QVector audio_tracks; diff --git a/io/previewgenerator.cpp b/io/previewgenerator.cpp index 1a0011896..030e26fcc 100644 --- a/io/previewgenerator.cpp +++ b/io/previewgenerator.cpp @@ -29,7 +29,7 @@ void PreviewGenerator::run() { if (media == NULL) { qDebug() << "[ERROR] No media was set for preview generation"; } else { - if (media->is_sequence) { + if (media->type == MEDIA_TYPE_SEQUENCE) { qDebug() << "[ERROR] Cannot run preview generation on a sequence"; } else { SwsContext* sws_ctx; diff --git a/mainwindow.cpp b/mainwindow.cpp index 2aae07dd9..04f1f812a 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -73,7 +73,7 @@ MainWindow::MainWindow(QWidget *parent) : ui->setupUi(this); - setWindowTitle("Olive (June 2018 | Pre-Alpha)"); + setWindowTitle("Olive (July 2018 | Pre-Alpha)"); statusBar()->showMessage("Welcome to Olive"); ui->centralWidget->setMaximumSize(0, 0); diff --git a/olive.pro.user b/olive.pro.user index 3faa11855..0b8a18e47 100644 --- a/olive.pro.user +++ b/olive.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/panels/project.cpp b/panels/project.cpp index c5e0faf2b..9390032c5 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -37,6 +37,8 @@ Project::Project(QWidget *parent) : ui(new Ui::Project) { ui->setupUi(this); + + connect(ui->treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(rename_media(QTreeWidgetItem*,int))); } Project::~Project() @@ -66,13 +68,19 @@ QString Project::get_next_sequence_name() { return name; } +void Project::rename_media(QTreeWidgetItem* item, int column) { + Media* m = get_media_from_tree(item); + m->name = item->text(column); +} + void Project::new_sequence(Sequence *s) { Media* m = new Media(); - m->is_sequence = true; + m->type = MEDIA_TYPE_SEQUENCE; m->sequence = s; QTreeWidgetItem* item = new QTreeWidgetItem(); - item->setText(0, s->name); + item->setFlags(item->flags() | Qt::ItemIsEditable); + item->setText(0, s->name); set_media_of_tree(item, m); ui->treeWidget->addTopLevelItem(item); @@ -105,7 +113,7 @@ Media* Project::import_file(QString file) { av_dump_format(pFormatCtx, 0, filename, 0); m = new Media(); - m->is_sequence = false; + m->type = MEDIA_TYPE_FOOTAGE; m->url = file; // detect video/audio streams in file @@ -144,6 +152,7 @@ Media* Project::import_file(QString file) { m->length = pFormatCtx->duration; QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setFlags(item->flags() | Qt::ItemIsEditable); if (m->video_tracks.size() == 0) { item->setIcon(0, QIcon(":/icons/audiosource.png")); } else { @@ -181,7 +190,7 @@ void Project::delete_selected_media() { // check if media is in use for (int i=0;iis_sequence && sequence != NULL) { + if (m->type == MEDIA_TYPE_FOOTAGE && sequence != NULL) { for (int j=0;jclip_count();j++) { Clip* c = sequence->get_clip(j); if (c != NULL && c->media == m) { @@ -289,7 +298,7 @@ void Project::set_media_of_tree(QTreeWidgetItem* item, Media* media) { void Project::delete_media(QTreeWidgetItem* item) { Media* m = get_media_from_tree(item); - if (m->is_sequence) { + if (m->type == MEDIA_TYPE_SEQUENCE) { if (sequence == m->sequence) { set_sequence(NULL); } @@ -537,7 +546,7 @@ void Project::save_project() { stream.writeStartElement("media"); for (int i=0;itreeWidget->topLevelItem(i)); - if (!m->is_sequence) { + if (m->type == MEDIA_TYPE_FOOTAGE) { m->save_id = i; stream.writeStartElement("footage"); stream.writeAttribute("id", QString::number(m->save_id)); @@ -551,7 +560,7 @@ void Project::save_project() { stream.writeStartElement("timeline"); for (int i=0;itreeWidget->topLevelItem(i)); - if (m->is_sequence) { + if (m->type == MEDIA_TYPE_SEQUENCE) { Sequence* s = m->sequence; stream.writeStartElement("sequence"); stream.writeTextElement("name", s->name); diff --git a/panels/project.h b/panels/project.h index 39243c162..25e2716f2 100644 --- a/panels/project.h +++ b/panels/project.h @@ -45,6 +45,8 @@ public: SourceTable* source_table; private: Ui::Project *ui; +private slots: + void rename_media(QTreeWidgetItem* item, int column); }; #endif // PROJECT_H diff --git a/panels/project.ui b/panels/project.ui index f8fb1db10..5ab0c04f5 100644 --- a/panels/project.ui +++ b/panels/project.ui @@ -36,7 +36,7 @@ - QAbstractItemView::CurrentChanged|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked + QAbstractItemView::NoEditTriggers false diff --git a/project/effect.cpp b/project/effect.cpp index 13b07b191..a12ffe039 100644 --- a/project/effect.cpp +++ b/project/effect.cpp @@ -8,9 +8,7 @@ #include -Effect::Effect(Clip* c) : parent_clip(c) -{ - name = ""; +Effect::Effect(Clip* c) : parent_clip(c) { type = EFFECT_TYPE_INVALID; } diff --git a/project/sequence.cpp b/project/sequence.cpp index b1efd1abe..fb328ca66 100644 --- a/project/sequence.cpp +++ b/project/sequence.cpp @@ -1,6 +1,7 @@ #include "sequence.h" #include "project/clip.h" +#include "effects/transition.h" #include @@ -88,6 +89,20 @@ Clip* Sequence::split_clip(Clip* pre, long frame) { post->timeline_in = frame; post->clip_in = pre->clip_in + pre->getLength(); + long pre_length = pre->getLength(); + + if (pre->closing_transition != NULL) { + post->closing_transition = pre->closing_transition; + pre->closing_transition = NULL; + long post_length = post->getLength(); + if (post->closing_transition->length > post_length) { + post->closing_transition->length = post_length; + } + } + if (pre->opening_transition != NULL && pre->opening_transition->length > pre_length) { + pre->opening_transition->length = pre_length; + } + add_clip(post); return post; diff --git a/ui/sourcetable.cpp b/ui/sourcetable.cpp index c9154fc70..def96972d 100644 --- a/ui/sourcetable.cpp +++ b/ui/sourcetable.cpp @@ -14,17 +14,41 @@ SourceTable::SourceTable(QWidget* parent) : QTreeWidget(parent) { sortByColumn(0, Qt::AscendingOrder); setAcceptDrops(true); + editing_item = NULL; + rename_timer.setInterval(500); + connect(&rename_timer, SIGNAL(timeout()), this, SLOT(rename_interval())); + connect(this, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(item_click(QTreeWidgetItem*,int))); + +// connect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, ) } -void SourceTable::mouseDoubleClickEvent(QMouseEvent* ) -{ +void SourceTable::rename_interval() { + rename_timer.stop(); + if (hasFocus() && editing_item != NULL) { + editItem(editing_item, 0); + } +} +void SourceTable::item_click(QTreeWidgetItem* item, int column) { + if (column == 0) { + editing_item = item; + rename_timer.start(); + } +} + +void SourceTable::mousePressEvent(QMouseEvent* event) { + rename_timer.stop(); + QTreeWidget::mousePressEvent(event); +} + +void SourceTable::mouseDoubleClickEvent(QMouseEvent* ) { if (selectedItems().count() == 0) { panel_project->import_dialog(); } else if (selectedItems().count() == 1) { - Media* m = reinterpret_cast(selectedItems().at(0)->data(0, Qt::UserRole + 1).value()); - if (m->is_sequence) { + QTreeWidgetItem* item = selectedItems().at(0); + Media* m = reinterpret_cast(item->data(0, Qt::UserRole + 1).value()); + if (m->type == MEDIA_TYPE_SEQUENCE) { set_sequence(m->sequence); - } + } } } diff --git a/ui/sourcetable.h b/ui/sourcetable.h index b088e9671..77a266f90 100644 --- a/ui/sourcetable.h +++ b/ui/sourcetable.h @@ -2,19 +2,27 @@ #define SOURCETABLE_H #include +#include class Project; class SourceTable : public QTreeWidget { + Q_OBJECT public: SourceTable(QWidget* parent = 0); protected: + void mousePressEvent(QMouseEvent*); void mouseDoubleClickEvent(QMouseEvent *event); void dragEnterEvent(QDragEnterEvent *event); void dragMoveEvent(QDragMoveEvent *event); void dropEvent(QDropEvent *event); private: + QTimer rename_timer; + QTreeWidgetItem* editing_item; +private slots: + void rename_interval(); + void item_click(QTreeWidgetItem* item, int column); }; #endif // SOURCETABLE_H diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 167bea80b..4ca236453 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -23,8 +23,9 @@ #include #include -TimelineWidget::TimelineWidget(QWidget *parent) : QWidget(parent) -{ +#define MAX_TEXT_WIDTH 20 + +TimelineWidget::TimelineWidget(QWidget *parent) : QWidget(parent) { bottom_align = false; track_resizing = false; setMouseTracking(true); @@ -974,8 +975,8 @@ void TimelineWidget::redraw_clips() { clip_pixmap.fill(Qt::transparent); QPainter clip_painter(&clip_pixmap); int video_track_limit = 0; - int audio_track_limit = 0; - QColor transition_color(160, 128, 192); + int audio_track_limit = 0; + QColor transition_color(255, 0, 0, 16); for (int i=0;iclip_count();i++) { Clip* clip = sequence->get_clip(i); if (clip != NULL && is_track_visible(clip->track)) { @@ -988,17 +989,58 @@ void TimelineWidget::redraw_clips() { QRect clip_rect(panel_timeline->getScreenPointFromFrame(clip->timeline_in), getScreenPointFromTrack(clip->track), clip->getLength() * panel_timeline->zoom, panel_timeline->calculate_track_height(clip->track, -1)); clip_painter.fillRect(clip_rect, QColor(clip->color_r, clip->color_g, clip->color_b)); + int thumb_x = clip_rect.x() + 1; + + QRect text_rect(clip_rect.left() + CLIP_TEXT_PADDING, clip_rect.top() + CLIP_TEXT_PADDING, clip_rect.width() - CLIP_TEXT_PADDING - 1, clip_rect.height() - CLIP_TEXT_PADDING - 1); + + // draw clip transitions + for (char i=0;i<2;i++) { + Transition* t; + if (i == 0) { + t = clip->opening_transition; + } else { + t = clip->closing_transition; + } + if (t != NULL) { + int transition_width = panel_timeline->getScreenPointFromFrame(t->length); + QRect transition_rect; + if (i == 0) { + transition_rect = QRect(clip_rect.x(), clip_rect.y(), transition_width, clip_rect.height()); + text_rect.setX(text_rect.x()+transition_width); + thumb_x += transition_width; + } else { + transition_rect = QRect(clip_rect.right()-transition_width, clip_rect.y(), transition_width, clip_rect.height()); + text_rect.setWidth(text_rect.width()-transition_width); + } + clip_painter.fillRect(transition_rect, transition_color); + QRect transition_text_rect(transition_rect.x() + CLIP_TEXT_PADDING, transition_rect.y() + CLIP_TEXT_PADDING, transition_rect.width() - CLIP_TEXT_PADDING, transition_rect.height() - CLIP_TEXT_PADDING); + if (transition_text_rect.width() > MAX_TEXT_WIDTH) { + clip_painter.setPen(QColor(0, 0, 0, 96)); + if (i == 0) { + clip_painter.drawLine(transition_rect.bottomLeft(), transition_rect.topRight()); + } else { + clip_painter.drawLine(transition_rect.topLeft(), transition_rect.bottomRight()); + } + + clip_painter.setPen(Qt::white); + clip_painter.drawText(transition_text_rect, 0, t->name, &transition_text_rect); + } + clip_painter.setPen(Qt::black); + clip_painter.drawRect(transition_rect); + } + } + // draw thumbnail/waveform if (clip->media_stream->preview_done) { if (clip->track < 0) { int thumb_y = clip_painter.fontMetrics().height()+CLIP_TEXT_PADDING+CLIP_TEXT_PADDING; int thumb_height = clip_rect.height()-thumb_y; int thumb_width = (thumb_height*((float)clip->media_stream->video_preview.width()/(float)clip->media_stream->video_preview.height())); - if (thumb_height > thumb_y && clip_rect.width() > thumb_width) { // at small clip heights, don't even draw it - QRect thumb_rect(clip_rect.x(), clip_rect.y()+thumb_y, thumb_width, thumb_height); + if (thumb_height > thumb_y && text_rect.width() + CLIP_TEXT_PADDING > thumb_width) { // at small clip heights, don't even draw it + QRect thumb_rect(thumb_x, clip_rect.y()+thumb_y, thumb_width, thumb_height); clip_painter.drawImage(thumb_rect, clip->media_stream->video_preview); } - } else { + } else if (clip_rect.height() > TRACK_MIN_HEIGHT) { int divider = clip->media_stream->audio_channels*2; clip_painter.setPen(QColor(80, 80, 80)); @@ -1018,46 +1060,29 @@ void TimelineWidget::redraw_clips() { } } - QRect text_rect(clip_rect.left() + CLIP_TEXT_PADDING, clip_rect.top() + CLIP_TEXT_PADDING, clip_rect.width() - CLIP_TEXT_PADDING - CLIP_TEXT_PADDING, clip_rect.height() - CLIP_TEXT_PADDING - CLIP_TEXT_PADDING); - - if (clip->opening_transition != NULL) { - int transition_width = panel_timeline->getScreenPointFromFrame(clip->opening_transition->length); - QRect transition_rect(clip_rect.x(), clip_rect.y(), transition_width, clip_rect.height()); - text_rect.setX(text_rect.x()+transition_width); - clip_painter.fillRect(transition_rect, transition_color); - clip_painter.setPen(Qt::black); - clip_painter.drawRect(transition_rect); - } - if (clip->closing_transition != NULL) { - int transition_width = panel_timeline->getScreenPointFromFrame(clip->opening_transition->length); - QRect transition_rect(clip_rect.right()-transition_width, clip_rect.y(), transition_width, clip_rect.height()); - text_rect.setWidth(text_rect.width()-transition_width); - clip_painter.fillRect(transition_rect, transition_color); - clip_painter.setPen(Qt::black); - clip_painter.drawRect(transition_rect); - } - // top left bevel clip_painter.setPen(Qt::white); clip_painter.drawLine(clip_rect.bottomLeft(), clip_rect.topLeft()); clip_painter.drawLine(clip_rect.topLeft(), clip_rect.topRight()); // draw text - if (color_brightness(clip->color_r, clip->color_g, clip->color_b) > 160) { - // set to black if color is bright - clip_painter.setPen(Qt::black); - } - if (clip->linked.size() > 0) { - int underline_y = CLIP_TEXT_PADDING + clip_painter.fontMetrics().height() + clip_rect.top(); - int underline_width = qMin(text_rect.width(), clip_painter.fontMetrics().width(clip->name)); - clip_painter.drawLine(text_rect.x(), underline_y, text_rect.x() + underline_width, underline_y); - } - clip_painter.drawText(text_rect, 0, clip->name, &text_rect); + if (text_rect.width() > MAX_TEXT_WIDTH) { + if (color_brightness(clip->color_r, clip->color_g, clip->color_b) > 160) { + // set to black if color is bright + clip_painter.setPen(Qt::black); + } + if (clip->linked.size() > 0) { + int underline_y = CLIP_TEXT_PADDING + clip_painter.fontMetrics().height() + clip_rect.top(); + int underline_width = qMin(text_rect.width() - 1, clip_painter.fontMetrics().width(clip->name)); + clip_painter.drawLine(text_rect.x(), underline_y, text_rect.x() + underline_width, underline_y); + } + clip_painter.drawText(text_rect, 0, clip->name, &text_rect); - // bottom right gray - clip_painter.setPen(Qt::gray); - clip_painter.drawLine(clip_rect.bottomLeft(), clip_rect.bottomRight()); - clip_painter.drawLine(clip_rect.bottomRight(), clip_rect.topRight()); + // bottom right gray + clip_painter.setPen(Qt::gray); + clip_painter.drawLine(clip_rect.bottomLeft(), clip_rect.bottomRight()); + clip_painter.drawLine(clip_rect.bottomRight(), clip_rect.topRight()); + } } } @@ -1140,7 +1165,7 @@ void TimelineWidget::paintEvent(QPaintEvent*) { p.drawLine(0, edge_y, rect().width(), edge_y); // draw snap point - if (panel_timeline->snapping && panel_timeline->snapped) { + if (panel_timeline->snapped) { p.setPen(Qt::white); int snap_x = panel_timeline->getScreenPointFromFrame(panel_timeline->snap_point); p.drawLine(snap_x, 0, snap_x, height()); diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index a0f037aea..f19c90215 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -59,8 +59,6 @@ void ViewerWidget::paintGL() if (multithreaded) retry_timer.stop(); glClear(GL_COLOR_BUFFER_BIT); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor4f(1.0, 1.0, 1.0, 1.0); current_clips.clear(); @@ -114,6 +112,9 @@ void ViewerWidget::paintGL() qDebug() << "[WARNING] Texture hasn't been created yet"; texture_failed = true; } else if (panel_timeline->playhead >= c->timeline_in) { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glColor4f(1.0, 1.0, 1.0, 1.0); + glLoadIdentity(); int half_width = c->sequence->width/2; int half_height = c->sequence->height/2;