diff --git a/io/media.h b/io/media.h
index ac74a30b2..105afa0af 100644
--- a/io/media.h
+++ b/io/media.h
@@ -28,7 +28,7 @@ struct MediaStream {
struct Media {
Media();
- ~Media();
+ ~Media();
QString url;
QString name;
diff --git a/mainwindow.cpp b/mainwindow.cpp
index f75245885..b16ad2455 100644
--- a/mainwindow.cpp
+++ b/mainwindow.cpp
@@ -5,6 +5,8 @@
#include "project/sequence.h"
+#include "ui/sourcetable.h"
+
#include "panels/panels.h"
#include "panels/project.h"
#include "panels/effectcontrols.h"
@@ -590,9 +592,10 @@ void MainWindow::on_actionSlide_Tool_triggered()
if (panel_timeline->focused()) panel_timeline->ui->toolSlideButton->click();
}
-void MainWindow::on_actionFolder_triggered()
-{
- panel_project->new_folder();
+void MainWindow::on_actionFolder_triggered() {
+ TimelineAction* ta = new TimelineAction();
+ ta->add_media(panel_project->new_folder(0), panel_project->get_selected_folder());
+ undo_stack.push(ta);
}
void MainWindow::fileMenu_About_To_Be_Shown() {
diff --git a/mainwindow.ui b/mainwindow.ui
index f5bdadc25..01eceb3b9 100644
--- a/mainwindow.ui
+++ b/mainwindow.ui
@@ -24,7 +24,7 @@
0
0
653
- 17
+ 20
@@ -420,6 +419,9 @@
Crash
+
+ false
+
diff --git a/panels/project.cpp b/panels/project.cpp
index 183e075cd..1a17f1074 100644
--- a/panels/project.cpp
+++ b/panels/project.cpp
@@ -15,6 +15,7 @@
#include "project/undo.h"
#include "mainwindow.h"
#include "io/config.h"
+#include "playback/cacher.h"
#include
#include
@@ -104,6 +105,53 @@ void Project::duplicate_selected() {
}
}
+void Project::replace_selected_file() {
+ QList selected_items = ui->treeWidget->selectedItems();
+ if (selected_items.size() == 1) {
+ QTreeWidgetItem* item = selected_items.at(0);
+ if (get_type_from_tree(item) == MEDIA_TYPE_FOOTAGE) {
+ replace_media(item, "");
+ }
+ }
+}
+
+void Project::replace_media(QTreeWidgetItem* item, QString filename) {
+ Media* m = get_media_from_tree(item);
+
+ // close any clips currently using this media
+ QVector all_sequences = list_all_project_sequences();
+ for (int i=0;iclip_count();j++) {
+ Clip* c = s->get_clip(j);
+ if (c != NULL && c->media == m && c->open) {
+ close_clip(c);
+ c->cacher->wait();
+ }
+ }
+ }
+
+ QStringList files;
+ if (filename.isEmpty()) {
+ files.append(QFileDialog::getOpenFileName(this, "Replace '" + item->text(0) + "'", "", "All Files (*)"));
+ } else {
+ files.append(filename);
+ }
+ process_file_list(NULL, files, NULL, item);
+
+ for (int i=0;iclip_count();j++) {
+ Clip* c = s->get_clip(j);
+ if (c != NULL && c->media == m) {
+ c->refresh();
+ }
+ }
+ }
+
+ panel_timeline->redraw_all_clips(true);
+}
+
void Project::new_sequence(TimelineAction *ta, Sequence *s, bool open, QTreeWidgetItem* parent) {
QTreeWidgetItem* item = new_item();
item->setText(0, s->name);
@@ -134,17 +182,16 @@ void Project::start_preview_generator(QTreeWidgetItem* item, Media* media) {
pg->start(QThread::LowPriority);
}
-QTreeWidgetItem* Project::import_file(QString file, QString imported_filename) {
- QTreeWidgetItem* item = new_item();
- Media* m = new Media();
+QString Project::get_file_name_from_path(const QString& path) {
+ return path.mid(path.lastIndexOf('/')+1);
+}
+
+void Project::import_file(QTreeWidgetItem* item, Media* m, QString file, QString imported_filename) {
m->url = file;
- m->name = imported_filename.mid(file.lastIndexOf('/')+1);
- set_media_of_tree(item, m);
+ m->name = get_file_name_from_path(imported_filename);
// generate waveform/thumbnail in another thread
- start_preview_generator(item, m);
-
- return item;
+ start_preview_generator(item, m);
}
QTreeWidgetItem* Project::new_item() {
@@ -157,13 +204,11 @@ bool Project::is_focused() {
return ui->treeWidget->hasFocus();
}
-QTreeWidgetItem* Project::new_folder() {
+QTreeWidgetItem* Project::new_folder(QString name) {
QTreeWidgetItem* item = new_item();
item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
- item->setText(0, "New Folder");
+ item->setText(0, (name.isEmpty()) ? "New Folder" : name);
set_item_to_folder(item);
- ui->treeWidget->addTopLevelItem(item);
- project_changed = true;
return item;
}
@@ -299,103 +344,165 @@ void Project::delete_selected_media() {
}
}
-void Project::process_file_list(QStringList& files) {
+void Project::process_file_list(bool recursive, QStringList& files, QTreeWidgetItem* parent, QTreeWidgetItem* replace) {
bool imported = false;
QVector image_sequence_urls;
QVector image_sequence_importassequence;
QStringList image_sequence_formats = config.img_seq_formats.split("|");
- TimelineAction* ta = new TimelineAction();
+ TimelineAction* ta;
+ if (!recursive) ta = new TimelineAction();
+
for (int i=0;i file.lastIndexOf('/')) {
- // image_sequence_formats
- found = false;
- QString ext = file.mid(lastcharindex+1);
- for (int j=0;jadd_media(folder, parent);
+ } else {
+ parent->addChild(folder);
+ }
- // Check if there are files with the same filename but just different numbers
- if (QFileInfo::exists(QString(file.left(digit_test) + QString("%1").arg(file_number-1, digit_count, 10, QChar('0')) + file.mid(lastcharindex)))
- || QFileInfo::exists(QString(file.left(digit_test) + QString("%1").arg(file_number+1, digit_count, 10, QChar('0')) + file.mid(lastcharindex)))) {
- is_img_sequence = true;
- }
+ imported = true;
+ } else {
+ QString file(files.at(i));
+ bool skip = false;
- if (is_img_sequence) {
- // get the URL that we would pass to FFmpeg to force it to read the image as a sequence
- QString new_filename = file.left(digit_test) + "%" + QString("%1").arg(digit_count, 2, 10, QChar('0')) + "d" + file.mid(lastcharindex);
+ /* Heuristic to determine whether file is part of an image sequence */
- // add image sequence url to a vector in case the user imported several files that
- // we're interpreting as a possible sequence
- found = false;
- for (int i=0;i file.lastIndexOf('/')) {
+ // image_sequence_formats
+ found = false;
+ QString ext = file.mid(lastcharindex+1);
+ for (int j=0;jadd_media(import_file(file, files.at(i)));
- imported = true;
- project_changed = true;
- }
- }
- if (imported) {
- undo_stack.push(ta);
- } else {
- delete ta;
+ if (found && file[lastcharindex-1].isDigit()) {
+ bool is_img_sequence = false;
+
+ // how many digits are in the filename?
+ int digit_count = 0;
+ int digit_test = lastcharindex-1;
+ while (file[digit_test].isDigit()) {
+ digit_count++;
+ digit_test--;
+ }
+
+ // retrieve number from filename
+ digit_test++;
+ int file_number = file.mid(digit_test, digit_count).toInt();
+
+ // Check if there are files with the same filename but just different numbers
+ if (QFileInfo::exists(QString(file.left(digit_test) + QString("%1").arg(file_number-1, digit_count, 10, QChar('0')) + file.mid(lastcharindex)))
+ || QFileInfo::exists(QString(file.left(digit_test) + QString("%1").arg(file_number+1, digit_count, 10, QChar('0')) + file.mid(lastcharindex)))) {
+ is_img_sequence = true;
+ }
+
+ if (is_img_sequence) {
+ // get the URL that we would pass to FFmpeg to force it to read the image as a sequence
+ QString new_filename = file.left(digit_test) + "%" + QString("%1").arg(digit_count, 2, 10, QChar('0')) + "d" + file.mid(lastcharindex);
+
+ // add image sequence url to a vector in case the user imported several files that
+ // we're interpreting as a possible sequence
+ found = false;
+ for (int i=0;ireset();
+ } else {
+ item = new_item();
+ m = new Media();
+ }
+
+ import_file(item, m, file, files.at(i));
+ set_media_of_tree(item, m);
+
+ if (recursive) {
+ parent->addChild(item);
+ } else {
+ ta->add_media(item, parent);
+ }
+
+ imported = true;
+ }
+ }
}
+ if (!recursive) {
+ if (imported) {
+ undo_stack.push(ta);
+ } else {
+ delete ta;
+ }
+ }
+}
+
+QTreeWidgetItem* Project::get_selected_folder() {
+ // if one item is selected and it's a folder, return it
+ QList selected_items = panel_project->source_table->selectedItems();
+ if (selected_items.size() == 1 && get_type_from_tree(selected_items.at(0)) == MEDIA_TYPE_FOLDER) {
+ return selected_items.at(0);
+ }
+ return NULL;
}
void Project::import_dialog() {
- QStringList files = QFileDialog::getOpenFileNames(this, "Import media...", "", "All Files (*)");
- process_file_list(files);
+ QFileDialog fd(this, "Import media...", "", "All Files (*)");
+ fd.setFileMode(QFileDialog::ExistingFiles);
+
+ if (fd.exec()) {
+ QStringList files = fd.selectedFiles();
+ process_file_list(NULL, files, get_selected_folder(), NULL);
+ }
}
void set_item_to_folder(QTreeWidgetItem* item) {
@@ -435,9 +542,35 @@ void Project::delete_media(QTreeWidgetItem* item) {
Sequence* s = get_sequence_from_tree(item);
delete s;
break;
- }
+ }
+}
- project_changed = true;
+void Project::delete_clips_using_selected_media() {
+ if (sequence == NULL) {
+ QMessageBox::critical(this, "No active sequence", "No sequence is active, please open the sequence you want to delete clips from.", QMessageBox::Ok);
+ } else {
+ TimelineAction* ta = new TimelineAction();
+ bool deleted = false;
+ for (int i=0;iclip_count();i++) {
+ Clip* c = sequence->get_clip(i);
+ if (c != NULL) {
+ QList items = source_table->selectedItems();
+ for (int j=0;jmedia == m) {
+ ta->delete_clip(sequence, i);
+ deleted = true;
+ }
+ }
+ }
+ }
+ if (deleted) {
+ undo_stack.push(ta);
+ panel_timeline->redraw_all_clips(true);
+ } else {
+ delete ta;
+ }
+ }
}
void Project::clear() {
@@ -516,7 +649,7 @@ bool Project::load_worker(QFile& f, QXmlStreamReader& stream, int type) {
switch (type) {
case MEDIA_TYPE_FOLDER:
{
- QTreeWidgetItem* folder = new_folder();
+ QTreeWidgetItem* folder = new_folder(0);
for (int j=0;jdata(0, Qt::UserRole + 4).toInt();
- if (parent > 0) {
- ui->treeWidget->takeTopLevelItem(ui->treeWidget->indexOfTopLevelItem(folder));
+ if (parent > 0) {
find_loaded_folder_by_id(parent)->addChild(folder);
- }
+ } else {
+ ui->treeWidget->addTopLevelItem(folder);
+ }
}
cont = load_worker(file, stream, MEDIA_TYPE_FOOTAGE);
diff --git a/panels/project.h b/panels/project.h
index 8d4d202fb..7194d03b2 100644
--- a/panels/project.h
+++ b/panels/project.h
@@ -51,17 +51,19 @@ public:
~Project();
bool is_focused();
void clear();
- QTreeWidgetItem* import_file(QString url, QString imported_filename);
+ void import_file(QTreeWidgetItem* item, Media* m, QString url, QString imported_filename);
void new_sequence(TimelineAction* ta, Sequence* s, bool open, QTreeWidgetItem* parent);
QString get_next_sequence_name();
void delete_media(QTreeWidgetItem* item);
- void process_file_list(QStringList& files);
+ void process_file_list(bool recursive, QStringList& files, QTreeWidgetItem *parent, QTreeWidgetItem* replace);
+ void replace_media(QTreeWidgetItem* item, QString filename);
+ QTreeWidgetItem* get_selected_folder();
void new_project();
void load_project();
void save_project(bool autorecovery);
- QTreeWidgetItem* new_folder();
+ QTreeWidgetItem* new_folder(QString name);
void save_recent_projects();
@@ -69,9 +71,11 @@ public:
SourceTable* source_table;
public slots:
- void import_dialog();
+ void import_dialog();
void delete_selected_media();
void duplicate_selected();
+ void delete_clips_using_selected_media();
+ void replace_selected_file();
private:
Ui::Project *ui;
QTreeWidgetItem* new_item();
@@ -92,6 +96,7 @@ private:
void get_media_from_table(QList items, QList& list, int type);
void start_preview_generator(QTreeWidgetItem* item, Media* media);
void list_all_sequences_worker(QVector* list, QTreeWidgetItem* parent);
+ QString get_file_name_from_path(const QString &path);
private slots:
void rename_media(QTreeWidgetItem* item, int column);
void clear_recent_projects();
diff --git a/panels/timeline.cpp b/panels/timeline.cpp
index c6c85e7ae..2e8be1ce2 100644
--- a/panels/timeline.cpp
+++ b/panels/timeline.cpp
@@ -264,8 +264,7 @@ void Timeline::repaint_timeline() {
}
void Timeline::redraw_all_clips(bool changed) {
- if (changed) {
- project_changed = true;
+ if (changed) {
if (!playing) reset_all_audio();
panel_viewer->viewer_widget->update();
}
diff --git a/playback/cacher.cpp b/playback/cacher.cpp
index 4ac960e83..96fbb4e3c 100644
--- a/playback/cacher.cpp
+++ b/playback/cacher.cpp
@@ -182,7 +182,6 @@ void reset_cache(Clip* c, long target_frame) {
// seeks to nearest keyframe (target_frame represents internal clip frame)
av_seek_frame(c->formatCtx, ms->file_index, (int64_t) qFloor(clip_frame_to_seconds(c, target_frame) / timebase), AVSEEK_FLAG_BACKWARD);
- qDebug() << target_frame;
// play up to the frame we actually want
long retrieved_frame = 0;
diff --git a/playback/playback.cpp b/playback/playback.cpp
index 578e6099c..9f29586a3 100644
--- a/playback/playback.cpp
+++ b/playback/playback.cpp
@@ -246,7 +246,7 @@ void retrieve_next_frame_raw_data(Clip* c, AVFrame* output) {
}
bool is_clip_active(Clip* c, long playhead) {
- return c->timeline_in < playhead + ceil(c->sequence->frame_rate) && c->timeline_out > playhead && c->enabled;
+ return c->timeline_in < playhead + ceil(c->sequence->frame_rate) && c->timeline_out > playhead && c->enabled;
}
void set_sequence(Sequence* s) {
diff --git a/project/undo.cpp b/project/undo.cpp
index 35bbf7f16..9953572b5 100644
--- a/project/undo.cpp
+++ b/project/undo.cpp
@@ -31,7 +31,8 @@ TimelineAction::TimelineAction() :
done(false),
change_seq(false),
ripple_enabled(false),
- change_in_out(false)
+ change_in_out(false),
+ old_project_changed(project_changed)
{}
TimelineAction::~TimelineAction() {
@@ -129,8 +130,9 @@ void TimelineAction::delete_clip(Sequence* s, int clip) {
new_action(s, TA_DELETE, clip, 0, 0);
}
-void TimelineAction::add_media(QTreeWidgetItem* item) {
+void TimelineAction::add_media(QTreeWidgetItem* item, QTreeWidgetItem *parent) {
media_to_add.append(item);
+ media_to_add_parents.append(parent);
}
void TimelineAction::delete_media(QTreeWidgetItem* item) {
@@ -242,20 +244,20 @@ void TimelineAction::undo() {
}
// delete added clips
- if (clips_to_add.size() > 0) {
- int delete_count = 0;
- for (int i=0;idestroy_clip(added_indexes.at(i)-delete_count, true);
- delete_count++;
- }
- }
+ int delete_count = 0;
+ for (int i=0;idestroy_clip(added_indexes.at(i)-delete_count, true);
+ delete_count++;
+ }
// remove any added media
- if (media_to_add.size() > 0) {
- for (int i=0;isource_table->takeTopLevelItem(panel_project->source_table->indexOfTopLevelItem(media_to_add.at(i)));
- }
- }
+ for (int i=0;isource_table->takeTopLevelItem(panel_project->source_table->indexOfTopLevelItem(media_to_add.at(i)));
+ } else {
+ media_to_add_parents.at(i)->removeChild(media_to_add.at(i));
+ }
+ }
// un-change workarea
if (change_in_out) {
@@ -269,6 +271,8 @@ void TimelineAction::undo() {
set_sequence(old_seq);
}
+ project_changed = old_project_changed;
+
done = false;
}
@@ -411,34 +415,34 @@ void TimelineAction::redo() {
}
// delete media
- if (deleted_media.size() > 0) {
- for (int i=0;iparent());
+ for (int i=0;iparent());
- // if we're deleting the open sequence, close it
- if (get_type_from_tree(item) == MEDIA_TYPE_SEQUENCE &&
- get_sequence_from_tree(item) == sequence &&
- !change_seq) {
- old_seq = sequence;
- new_seq = NULL;
- change_seq = true;
- }
+ // if we're deleting the open sequence, close it
+ if (get_type_from_tree(item) == MEDIA_TYPE_SEQUENCE &&
+ get_sequence_from_tree(item) == sequence &&
+ !change_seq) {
+ old_seq = sequence;
+ new_seq = NULL;
+ change_seq = true;
+ }
- if (item->parent() == NULL) {
- panel_project->source_table->takeTopLevelItem(panel_project->source_table->indexOfTopLevelItem(item));
- } else {
- item->parent()->removeChild(item);
- }
- }
- }
+ if (item->parent() == NULL) {
+ panel_project->source_table->takeTopLevelItem(panel_project->source_table->indexOfTopLevelItem(item));
+ } else {
+ item->parent()->removeChild(item);
+ }
+ }
// add any new media
- if (media_to_add.size() > 0) {
- for (int i=0;isource_table->addTopLevelItem(media_to_add.at(i));
- }
- }
+ for (int i=0;isource_table->addTopLevelItem(media_to_add.at(i));
+ } else {
+ media_to_add_parents.at(i)->addChild(media_to_add.at(i));
+ }
+ }
// change sequence workarea
if (change_in_out) {
@@ -453,6 +457,8 @@ void TimelineAction::redo() {
set_sequence(new_seq);
}
+ project_changed = true;
+
done = true;
}
diff --git a/project/undo.h b/project/undo.h
index b66fdf075..12deb4131 100644
--- a/project/undo.h
+++ b/project/undo.h
@@ -28,7 +28,7 @@ public:
void set_track(Sequence* s, int clip, int value);
void increase_track(Sequence* s, int clip, int value);
void delete_clip(Sequence* s, int clip);
- void add_media(QTreeWidgetItem* item);
+ void add_media(QTreeWidgetItem* item, QTreeWidgetItem* parent);
void delete_media(QTreeWidgetItem* item);
void ripple(Sequence* s, long point, long length);
void ripple(Sequence* s, long point, long length, QVector &ignore);
@@ -68,6 +68,7 @@ private:
QVector deleted_media_parents;
QVector media_to_add;
+ QVector media_to_add_parents;
Sequence* ripple_sequence;
bool ripple_enabled;
@@ -87,6 +88,8 @@ private:
void new_action(Sequence* s, int action, int clip, long old_val, long new_val);
void offset_links(QVector& clips, int offset);
+
+ bool old_project_changed;
};
class LinkCommand : public QUndoCommand {
diff --git a/ui/sourcetable.cpp b/ui/sourcetable.cpp
index c1748a004..1f2b9436b 100644
--- a/ui/sourcetable.cpp
+++ b/ui/sourcetable.cpp
@@ -12,6 +12,8 @@
#include
#include
#include
+#include
+#include
#include
SourceTable::SourceTable(QWidget* parent) : QTreeWidget(parent) {
@@ -35,23 +37,36 @@ void SourceTable::show_context_menu(const QPoint& pos) {
if (selectedItems().size() == 1) {
// replace footage
if (get_type_from_tree(selectedItems().at(0)) == MEDIA_TYPE_FOOTAGE) {
- menu.addAction("Replace/Relink Media");
+ QAction* replace_action = menu.addAction("Replace/Relink Media");
+ connect(replace_action, SIGNAL(triggered(bool)), panel_project, SLOT(replace_media()));
}
menu.addAction("Replace Clips Using This Media");
}
// duplicate item
bool all_sequences = true;
+ bool all_footage = true;
for (int i=0;imimeData();
+ QTreeWidgetItem* drop_item = itemAt(event->pos());
if (mimeData->hasUrls()) {
// drag files in from outside
QList urls = mimeData->urls();
- if (!urls.isEmpty()) {
+ if (!urls.isEmpty()) {
QStringList paths;
- for (int i=0;iprocess_file_list(paths);
+ bool replace = false;
+ if (urls.size() == 1
+ && drop_item != NULL
+ && get_type_from_tree(drop_item) == MEDIA_TYPE_FOOTAGE
+ && !QFileInfo(paths.at(0)).isDir()
+ && QMessageBox::question(this, "Replace Media", "You dropped a file onto '" + drop_item->text(0) + "'. Would you like to replace it with the dropped file?", QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) {
+ replace = true;
+ panel_project->replace_media(drop_item, paths.at(0));
+ }
+ if (!replace) {
+ QTreeWidgetItem* parent = NULL;
+ if (drop_item != NULL && get_type_from_tree(drop_item) == MEDIA_TYPE_FOLDER) {
+ parent = drop_item;
+ }
+ panel_project->process_file_list(NULL, paths, parent, NULL);
+ }
}
event->acceptProposedAction();
} else {
// dragging files within project
QVector move_items;
- QTreeWidgetItem* drop_item = itemAt(event->pos());
// if we dragged to the root OR dragged to a folder
if (drop_item == NULL || (drop_item != NULL && get_type_from_tree(drop_item) == MEDIA_TYPE_FOLDER)) {
QList selected_items = selectedItems();
diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp
index 8c4381b82..b03984b60 100644
--- a/ui/timelinewidget.cpp
+++ b/ui/timelinewidget.cpp
@@ -815,12 +815,12 @@ void TimelineWidget::update_ghosts(QPoint& mouse_pos) {
validator = g.ghost_length + frame_diff;
if (validator < 1) frame_diff += (1 - validator);
- // prevent clip length exceeding media length
- if (c->media_type == MEDIA_TYPE_SEQUENCE
+ // prevent clip length exceeding media length
+ if (c->media_type == MEDIA_TYPE_SEQUENCE
|| (c->media_type == MEDIA_TYPE_FOOTAGE && !static_cast(c->media)->get_stream_from_file_index(c->media_stream)->infinite_length)) {
validator = g.old_clip_in + g.ghost_length + frame_diff;
if (validator > g.media_length) frame_diff -= validator - g.media_length;
- }
+ }
}
// ripple ops
@@ -1433,30 +1433,22 @@ void TimelineWidget::redraw_clips() {
}
if (clip->media_type == MEDIA_TYPE_FOOTAGE) {
+ bool draw_checkerboard = false;
+ QRect checkerboard_rect = clip_rect;
Media* m = static_cast(clip->media);
MediaStream* ms = m->get_stream_from_file_index(clip->media_stream);
if (ms == NULL) {
- // draw "error lines" if media stream is missing
- clip_painter.setPen(QPen(QColor(64, 64, 64), 2));
- int limit = clip_rect.width();
- int clip_height = clip_rect.bottom()-clip_rect.top();
- for (int j=-clip_height;j clip_rect.right()) {
- lines_end_y -= (clip_rect.right() - lines_end_x);
- lines_end_x = clip_rect.right();
- }
- clip_painter.drawLine(lines_start_x, lines_start_y, lines_end_x, lines_end_y);
- }
+ draw_checkerboard = true;
} else if (ms->preview_done) {
// draw thumbnail/waveform
+ long media_length = m->get_length_in_frames(clip->sequence->frame_rate);
+ int waveform_limit = qMin(clip_rect.width(), panel_timeline->getScreenPointFromFrame(media_length - clip->clip_in));
+
+ if (waveform_limit < clip_rect.width()) {
+ draw_checkerboard = true;
+ checkerboard_rect.setLeft(clip_rect.left() + waveform_limit);
+ }
+
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;
@@ -1465,33 +1457,47 @@ void TimelineWidget::redraw_clips() {
QRect thumb_rect(thumb_x, clip_rect.y()+thumb_y, thumb_width, thumb_height);
clip_painter.drawImage(thumb_rect, ms->video_preview);
}
- } else if (clip_rect.height() > TRACK_MIN_HEIGHT) {
+ } else if (clip_rect.height() > TRACK_MIN_HEIGHT) {
int divider = ms->audio_channels*2;
clip_painter.setPen(QColor(80, 80, 80));
int channel_height = clip_rect.height()/ms->audio_channels;
- long media_length = m->get_length_in_frames(clip->sequence->frame_rate);
- for (int i=0;iclip_in + ((double) i/panel_timeline->zoom))/media_length) * ms->audio_preview.size())/divider)*divider;
- for (int j=0;jaudio_channels;j++) {
- int mid = clip_rect.top()+channel_height*j+(channel_height/2);
- int offset = waveform_index+(j*2);
+ for (int j=0;jaudio_channels;j++) {
+ int mid = clip_rect.top()+channel_height*j+(channel_height/2);
+ int offset = waveform_index+(j*2);
- qint8 min = (double)ms->audio_preview.at(offset) / 128.0 * (channel_height/2);
- qint8 max = (double)ms->audio_preview.at(offset+1) / 128.0 * (channel_height/2);
- clip_painter.drawLine(clip_rect.left()+i, mid+min, clip_rect.left()+i, mid+max);
-
- /*if (offset >= 0 && offset < ms->audio_preview.size()) {
-
- } else {
- QMessageBox::critical(this, "AAAAAAAAAAAAA", "Here's that terrible, no-good bug again!!! I've stepped around it but plz report the following to Matt:\n\n" + QString::number(offset) + " vs " + QString::number(clip->media_stream->audio_preview.size()), QMessageBox::Ok);
- break;
- }*/
- }
- }
+ qint8 min = (double)ms->audio_preview.at(offset) / 128.0 * (channel_height/2);
+ qint8 max = (double)ms->audio_preview.at(offset+1) / 128.0 * (channel_height/2);
+ clip_painter.drawLine(clip_rect.left()+i, mid+min, clip_rect.left()+i, mid+max);
+ }
+ }
}
}
+ if (draw_checkerboard) {
+ // draw "error lines" if media stream is missing
+ clip_painter.setPen(QPen(QColor(64, 64, 64), 2));
+ int limit = checkerboard_rect.width();
+ int clip_height = checkerboard_rect.bottom()-checkerboard_rect.top();
+ for (int j=-clip_height;j checkerboard_rect.right()) {
+ lines_end_y -= (checkerboard_rect.right() - lines_end_x);
+ lines_end_x = checkerboard_rect.right();
+ }
+ clip_painter.drawLine(lines_start_x, lines_start_y, lines_end_x, lines_end_y);
+ }
+ }
}
// top left bevel
diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp
index 8058a96e5..59723471a 100644
--- a/ui/viewerwidget.cpp
+++ b/ui/viewerwidget.cpp
@@ -110,19 +110,22 @@ void ViewerWidget::compose_sequence(Clip* nest, bool render_audio) {
case MEDIA_TYPE_FOOTAGE:
{
Media* m = static_cast(c->media);
- if (m->ready
- && m->get_stream_from_file_index(c->media_stream) != NULL
- && is_clip_active(c, playhead)) {
- // if thread is already working, we don't want to touch this,
- // but we also don't want to hang the UI thread
- if (!c->open) {
- open_clip(c, multithreaded);
- }
+ if (m->ready) {
+ if (m->get_stream_from_file_index(c->media_stream) != NULL
+ && is_clip_active(c, playhead)) {
+ // if thread is already working, we don't want to touch this,
+ // but we also don't want to hang the UI thread
+ if (!c->open) {
+ open_clip(c, multithreaded);
+ }
- clip_is_active = true;
- } else if (c->open) {
- close_clip(c);
- }
+ clip_is_active = true;
+ } else if (c->open) {
+ close_clip(c);
+ }
+ } else {
+ texture_failed = true;
+ }
}
break;
case MEDIA_TYPE_SEQUENCE: