Merge branch 'master' of https://github.com/olive-editor/olive into proxies

This commit is contained in:
itsmattkc
2019-02-01 19:49:42 +11:00
24 changed files with 480 additions and 96 deletions
+140 -13
View File
@@ -1,6 +1,7 @@
#include "preferencesdialog.h"
#include "io/config.h"
#include "io/path.h"
#include "playback/audio.h"
#include "mainwindow.h"
@@ -24,6 +25,7 @@
#include <QFileDialog>
#include <QMessageBox>
#include <QAudioDeviceInfo>
#include <QApplication>
#include "debug.h"
@@ -140,7 +142,6 @@ void PreferencesDialog::save() {
|| config.preferred_audio_input != audio_input_devices->currentData().toString());
config.preferred_audio_output = audio_output_devices->currentData().toString();
config.preferred_audio_input = audio_input_devices->currentData().toString();
qDebug() << "selected audio input" << audio_input_devices->currentData().toString();
config.audio_rate = audio_sample_rate->currentData().toInt();
// the following settings may require a restart of Olive to take effect:
@@ -149,13 +150,81 @@ void PreferencesDialog::save() {
if (config.effect_textbox_lines != effect_textbox_lines_field->value()) {
needs_restart = true;
config.effect_textbox_lines = effect_textbox_lines_field->value();
}
config.effect_textbox_lines = effect_textbox_lines_field->value();
if (config.use_software_fallback != use_software_fallbacks_checkbox->isChecked()) {
needs_restart = true;
config.use_software_fallback = use_software_fallbacks_checkbox->isChecked();
}
if (config.language_file != language_combobox->currentData().toString()) {
needs_restart = true;
config.language_file = language_combobox->currentData().toString();
}
if (config.thumbnail_resolution != thumbnail_res_spinbox->value()
|| config.waveform_resolution != waveform_res_spinbox->value()) {
// we're changing the size of thumbnails and waveforms, so let's delete them and regenerate them next start
needs_restart = true;
// delete nothing
char delete_match = 0;
if (config.thumbnail_resolution != thumbnail_res_spinbox->value()) {
// delete existing thumbnails
config.thumbnail_resolution = thumbnail_res_spinbox->value();
// delete only thumbnails
delete_match = 't';
}
if (config.waveform_resolution != waveform_res_spinbox->value()) {
// delete existing waveforms
config.waveform_resolution = waveform_res_spinbox->value();
// if we're already deleting thumbnails
if (delete_match == 't') {
// delete all
delete_match = 1;
} else {
// just delete waveforms
delete_match = 'w';
}
}
if (delete_match != 0) {
QDir preview_path(get_data_path() + "/previews");
if (delete_match == 1) {
// indiscriminately delete everything
preview_path.removeRecursively();
} else {
QStringList preview_file_list = preview_path.entryList(QDir::Files | QDir::NoDotAndDotDot);
for (int i=0;i<preview_file_list.size();i++) {
const QString& preview_file_str = preview_file_list.at(i);
// use filename to determine whether this is a thumbnail or a waveform
int identifier_char_index = qMax(0, preview_file_str.size()-2);
// find identifier char
while (identifier_char_index >= 0
&& preview_file_str.at(identifier_char_index) >= 48
&& preview_file_str.at(identifier_char_index) <= 57) {
identifier_char_index--;
}
// thumbnails will have a 't' towards the end of the filenames, waveforms will have a 'w'
// if they match the type of preview we're deleting, remove them
if (preview_file_str.at(identifier_char_index) == delete_match) {
QFile::remove(preview_path.filePath(preview_file_str));
}
}
}
}
}
config.use_software_fallback = use_software_fallbacks_checkbox->isChecked();
// save keyboard shortcuts
for (int i=0;i<key_shortcut_fields.size();i++) {
@@ -299,49 +368,107 @@ void PreferencesDialog::setup_ui() {
QVBoxLayout* verticalLayout = new QVBoxLayout(this);
QTabWidget* tabWidget = new QTabWidget(this);
// row counter used to ease adding new rows
int row = 0;
// General
QWidget* general_tab = new QWidget(this);
QGridLayout* general_layout = new QGridLayout(general_tab);
// General -> Language
general_layout->addWidget(new QLabel(tr("Language:")), row, 0, 1, 1);
language_combobox = new QComboBox();
// add default language (en-US)
language_combobox->addItem(QLocale::languageToString(QLocale("en-US").language()));
// add languages from file
QDir translation_dir(QApplication::applicationDirPath().append("/ts"));
QStringList translation_files = translation_dir.entryList({"*.qm"}, QDir::Files | QDir::NoDotAndDotDot);
for (int i=0;i<translation_files.size();i++) {
QString locale_full_path = translation_dir.filePath(translation_files.at(i));
QFileInfo locale_file(translation_files.at(i));
QString locale_file_basename = locale_file.baseName();
QString locale_str = locale_file_basename.mid(locale_file_basename.lastIndexOf('_')+1);
language_combobox->addItem(QLocale(locale_str).nativeLanguageName(), locale_full_path);
if (config.language_file == locale_full_path) {
language_combobox->setCurrentIndex(language_combobox->count() - 1);
}
}
general_layout->addWidget(language_combobox, row, 1, 1, 3);
row++;
// General -> Custom CSS
general_layout->addWidget(new QLabel(tr("Custom CSS:"), this), 0, 0, 1, 1);
general_layout->addWidget(new QLabel(tr("Custom CSS:"), this), row, 0, 1, 1);
custom_css_fn = new QLineEdit(general_tab);
custom_css_fn->setText(config.css_path);
general_layout->addWidget(custom_css_fn, 0, 1, 1, 1);
general_layout->addWidget(custom_css_fn, row, 1, 1, 2);
QPushButton* custom_css_browse = new QPushButton(tr("Browse"), general_tab);
connect(custom_css_browse, SIGNAL(clicked(bool)), this, SLOT(browse_css_file()));
general_layout->addWidget(custom_css_browse, 0, 2, 1, 1);
general_layout->addWidget(custom_css_browse, row, 3, 1, 1);
row++;
// General -> Image Sequence Formats
general_layout->addWidget(new QLabel(tr("Image sequence formats:"), this), 1, 0, 1, 1);
general_layout->addWidget(new QLabel(tr("Image sequence formats:"), this), row, 0, 1, 1);
imgSeqFormatEdit = new QLineEdit(general_tab);
general_layout->addWidget(imgSeqFormatEdit, 1, 1, 1, 2);
general_layout->addWidget(imgSeqFormatEdit, row, 1, 1, 3);
row++;
// General -> Audio Recording
general_layout->addWidget(new QLabel(tr("Audio Recording:"), this), 2, 0, 1, 1);
general_layout->addWidget(new QLabel(tr("Audio Recording:"), this), row, 0, 1, 1);
recordingComboBox = new QComboBox(general_tab);
recordingComboBox->addItem(tr("Mono"));
recordingComboBox->addItem(tr("Stereo"));
general_layout->addWidget(recordingComboBox, 2, 1, 1, 2);
general_layout->addWidget(recordingComboBox, row, 1, 1, 3);
row++;
// General -> Effect Textbox Lines
general_layout->addWidget(new QLabel(tr("Effect Textbox Lines:"), this), 3, 0, 1, 1);
general_layout->addWidget(new QLabel(tr("Effect Textbox Lines:"), this), row, 0, 1, 1);
effect_textbox_lines_field = new QSpinBox(general_tab);
effect_textbox_lines_field->setMinimum(1);
effect_textbox_lines_field->setValue(config.effect_textbox_lines);
general_layout->addWidget(effect_textbox_lines_field, 3, 1, 1, 2);
general_layout->addWidget(effect_textbox_lines_field, row, 1, 1, 3);
row++;
// General -> Thumbnail and Waveform Resolution
general_layout->addWidget(new QLabel(tr("Thumbnail Resolution:"), this), row, 0, 1, 1);
thumbnail_res_spinbox = new QSpinBox(this);
thumbnail_res_spinbox->setMinimum(1);
thumbnail_res_spinbox->setMaximum(INT_MAX);
thumbnail_res_spinbox->setValue(config.thumbnail_resolution);
general_layout->addWidget(thumbnail_res_spinbox, row, 1, 1, 1);
general_layout->addWidget(new QLabel(tr("Waveform Resolution:"), this), row, 2, 1, 1);
waveform_res_spinbox = new QSpinBox(this);
waveform_res_spinbox->setMinimum(1);
waveform_res_spinbox->setMaximum(INT_MAX);
waveform_res_spinbox->setValue(config.waveform_resolution);
general_layout->addWidget(waveform_res_spinbox, row, 3, 1, 1);
row++;
// General -> Use Software Fallbacks When Possible
use_software_fallbacks_checkbox = new QCheckBox(general_tab);
use_software_fallbacks_checkbox->setText(tr("Use Software Fallbacks When Possible"));
use_software_fallbacks_checkbox->setChecked(config.use_software_fallback);
general_layout->addWidget(use_software_fallbacks_checkbox, 4, 0, 1, 1);
general_layout->addWidget(use_software_fallbacks_checkbox, row, 0, 1, 4);
tabWidget->addTab(general_tab, tr("General"));
+3
View File
@@ -65,6 +65,9 @@ private:
QComboBox* audio_output_devices;
QComboBox* audio_input_devices;
QComboBox* audio_sample_rate;
QComboBox* language_combobox;
QSpinBox* thumbnail_res_spinbox;
QSpinBox* waveform_res_spinbox;
QVector<QAction*> key_shortcut_actions;
QVector<QTreeWidgetItem*> key_shortcut_items;
+15 -1
View File
@@ -48,7 +48,9 @@ Config::Config()
seek_also_selects(false),
effect_textbox_lines(3),
use_software_fallback(false),
center_timeline_timecodes(true)
center_timeline_timecodes(true),
waveform_resolution(64),
thumbnail_resolution(120)
{}
void Config::load(QString path) {
@@ -179,6 +181,15 @@ void Config::load(QString path) {
} else if (stream.name() == "PreferredAudioInput") {
stream.readNext();
preferred_audio_input = stream.text().toString();
} else if (stream.name() == "LanguageFile") {
stream.readNext();
language_file = stream.text().toString();
} else if (stream.name() == "ThumbnailResolution") {
stream.readNext();
thumbnail_resolution = stream.text().toInt();
} else if (stream.name() == "WaveformResolution") {
stream.readNext();
waveform_resolution = stream.text().toInt();
}
}
}
@@ -243,6 +254,9 @@ void Config::save(QString path) {
stream.writeTextElement("CenterTimelineTimecodes", QString::number(center_timeline_timecodes));
stream.writeTextElement("PreferredAudioOutput", preferred_audio_output);
stream.writeTextElement("PreferredAudioInput", preferred_audio_input);
stream.writeTextElement("LanguageFile", language_file);
stream.writeTextElement("ThumbnailResolution", QString::number(thumbnail_resolution));
stream.writeTextElement("WaveformResolution", QString::number(waveform_resolution));
stream.writeEndElement(); // configuration
stream.writeEndDocument(); // doc
+3
View File
@@ -66,6 +66,9 @@ struct Config {
bool center_timeline_timecodes;
QString preferred_audio_output;
QString preferred_audio_input;
QString language_file;
int waveform_resolution;
int thumbnail_resolution;
void load(QString path);
void save(QString path);
+16 -2
View File
@@ -431,10 +431,24 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) {
}
}
if (cancelled) return false;
} else if (stream.isStartElement() && (stream.name() == "effect" || stream.name() == "opening" || stream.name() == "closing")) {
} else if (stream.isStartElement()
&& (stream.name() == "effect"
|| stream.name() == "opening"
|| stream.name() == "closing")) {
// "opening" and "closing" are backwards compatibility code
load_effect(stream, c);
}
} else if (stream.name() == "marker" && stream.isStartElement()) {
Marker m;
for (int j=0;j<stream.attributes().size();j++) {
const QXmlStreamAttribute& attr = stream.attributes().at(j);
if (attr.name() == "frame") {
m.frame = attr.value().toLong();
} else if (attr.name() == "name") {
m.name = attr.value().toString();
}
}
c->markers.append(m);
}
}
}
if (cancelled) return false;
+2 -5
View File
@@ -16,9 +16,6 @@
#include <QFile>
#include <QDir>
#define WAVEFORM_RESOLUTION 64
#define THUMBNAIL_RESOLUTION 120
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
@@ -266,7 +263,7 @@ void PreviewGenerator::generate_waveform() {
if (s != nullptr) {
if (fmt_ctx->streams[packet->stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
if (!s->preview_done) {
int dstH = THUMBNAIL_RESOLUTION;
int dstH = config.thumbnail_resolution;
int dstW = qRound(dstH * (float(temp_frame->width)/float(temp_frame->height)));
uint8_t* data = new uint8_t[size_t(dstW*dstH*4)];
@@ -305,7 +302,7 @@ void PreviewGenerator::generate_waveform() {
}
media_lengths[packet->stream_index]++;
} else if (fmt_ctx->streams[packet->stream_index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
int interval = qFloor((temp_frame->sample_rate/WAVEFORM_RESOLUTION)/4)*4;
int interval = qFloor((temp_frame->sample_rate/config.waveform_resolution)/4)*4;
AVFrame* swr_frame = av_frame_alloc();
swr_frame->channel_layout = temp_frame->channel_layout;
+58 -4
View File
@@ -51,6 +51,7 @@
#include <QLayout>
#include <QApplication>
#include <QPushButton>
#include <QTranslator>
MainWindow* mainWindow;
@@ -206,10 +207,18 @@ MainWindow::MainWindow(QWidget *parent, const QString &an) :
}
}
// load preferred language from file
if (!config.language_file.isEmpty()
&& QFileInfo::exists(config.language_file)) {
QTranslator* translator = new QTranslator(this);
translator->load(config.language_file);
QApplication::installTranslator(translator);
}
alloc_panels(this);
QStatusBar* statusBar = new QStatusBar(this);
statusBar->showMessage("Welcome to " + appName);
statusBar->showMessage(tr("Welcome to %1").arg(appName));
setStatusBar(statusBar);
// populate menu bars
@@ -743,6 +752,8 @@ void MainWindow::setup_menus() {
full_screen->setProperty("id", "fullscreen");
full_screen->setCheckable(true);
view_menu->addAction(tr("Full Screen Viewer"), this, SLOT(full_screen_viewer()))->setProperty("id", "fullscreenviewer");
// INITIALIZE PLAYBACK MENU
QMenu* playback_menu = menuBar->addMenu(tr("&Playback"));
@@ -806,7 +817,11 @@ void MainWindow::setup_menus() {
window_sequenceviewer_action->setCheckable(true);
window_sequenceviewer_action->setData(reinterpret_cast<quintptr>(panel_sequence_viewer));
window_menu->addSeparator();
window_menu->addSeparator();
window_menu->addAction(tr("Maximize Panel"), this, SLOT(maximize_panel()), QKeySequence("`"))->setProperty("id", "maximizepanel");
window_menu->addSeparator();
window_menu->addAction(tr("Reset to Default Layout"), this, SLOT(reset_layout()))->setProperty("id", "resetdefaultlayout");
@@ -1195,7 +1210,34 @@ void MainWindow::next_cut() {
QDockWidget* focused_panel = get_focused_panel();
if (sequence != nullptr && (panel_timeline == focused_panel || panel_sequence_viewer == focused_panel)) {
panel_timeline->next_cut();
}
}
}
void MainWindow::maximize_panel() {
// toggles between normal state and a state of one panel being maximized
if (temp_panel_state.isEmpty()) {
// get currently hovered panel
QDockWidget* focused_panel = get_focused_panel(true);
// if the mouse is in fact hovering over a panel
if (focused_panel != nullptr) {
// store the current state of panels
temp_panel_state = saveState();
// remove all dock widgets (kind of painful having to do each individually)
if (focused_panel != panel_project) removeDockWidget(panel_project);
if (focused_panel != panel_effect_controls) removeDockWidget(panel_effect_controls);
if (focused_panel != panel_timeline) removeDockWidget(panel_timeline);
if (focused_panel != panel_sequence_viewer) removeDockWidget(panel_sequence_viewer);
if (focused_panel != panel_footage_viewer) removeDockWidget(panel_footage_viewer);
}
} else {
// we must be maximized, restore previous state
restoreState(temp_panel_state);
// clear temp panel state for next maximize call
temp_panel_state.clear();
}
}
void MainWindow::preferences()
@@ -1210,7 +1252,15 @@ void MainWindow::zoom_in_tracks() {
}
void MainWindow::zoom_out_tracks() {
panel_timeline->decrease_track_height();
panel_timeline->decrease_track_height();
}
void MainWindow::full_screen_viewer() {
if (get_focused_panel() == panel_footage_viewer) {
panel_footage_viewer->viewer_widget->set_fullscreen();
} else {
panel_sequence_viewer->viewer_widget->set_fullscreen();
}
}
void MainWindow::windowMenu_About_To_Be_Shown() {
@@ -1595,6 +1645,10 @@ void MainWindow::toggle_panel_visibility() {
QAction* action = static_cast<QAction*>(sender());
QDockWidget* w = reinterpret_cast<QDockWidget*>(action->data().value<quintptr>());
w->setVisible(!w->isVisible());
// layout has changed, we're no longer in maximized panel mode,
// so we clear this byte array
temp_panel_state.clear();
}
void MainWindow::set_timecode_view() {
+6 -1
View File
@@ -78,14 +78,16 @@ private slots:
void prev_cut();
void next_cut();
void maximize_panel();
void reset_layout();
void preferences();
void zoom_in_tracks();
void zoom_out_tracks();
void full_screen_viewer();
void fileMenu_About_To_Be_Shown();
void fileMenu_About_To_Hide();
void editMenu_About_To_Be_Shown();
@@ -204,6 +206,9 @@ private:
bool enable_launch_with_project;
QString appName;
// used to store the panel state when one panel is maximized
QByteArray temp_panel_state;
};
extern MainWindow* mainWindow;
+2 -2
View File
@@ -115,9 +115,9 @@ void update_ui(bool modified) {
panel_graph_editor->update_panel();
}
QDockWidget *get_focused_panel() {
QDockWidget *get_focused_panel(bool force_hover) {
QDockWidget* w = nullptr;
if (config.hover_focus) {
if (config.hover_focus || force_hover) {
if (panel_project->underMouse()) {
w = panel_project;
} else if (panel_effect_controls->underMouse()) {
+1 -1
View File
@@ -19,7 +19,7 @@ extern Timeline* panel_timeline;
extern GraphEditor* panel_graph_editor;
void update_ui(bool modified);
QDockWidget* get_focused_panel();
QDockWidget* get_focused_panel(bool force_hover = false);
void alloc_panels(QWidget *parent);
void free_panels();
void scroll_to_frame_internal(QScrollBar* bar, long frame, double zoom, int area_width);
+18 -5
View File
@@ -130,7 +130,11 @@ Project::Project(QWidget *parent) :
connect(toolbar_redo, SIGNAL(clicked(bool)), mainWindow, SLOT(redo()));
toolbar->addWidget(toolbar_redo);
toolbar->addStretch();
QLineEdit* toolbar_search = new QLineEdit();
toolbar_search->setPlaceholderText(tr("Search media, markers, etc."));
connect(toolbar_search, SIGNAL(textChanged(QString)), sorter, SLOT(update_search_filter(const QString&)));
toolbar->addWidget(toolbar_search);
QPushButton* toolbar_tree_view = new QPushButton();
QIcon icon6;
icon6.addFile(QStringLiteral(":/icons/treeview.png"), QSize(), QIcon::Normal, QIcon::On);
@@ -915,6 +919,13 @@ void Project::load_project(bool autorecovery) {
ld.exec();
}
void save_marker(QXmlStreamWriter& stream, const Marker& m) {
stream.writeStartElement("marker");
stream.writeAttribute("frame", QString::number(m.frame));
stream.writeAttribute("name", m.name);
stream.writeEndElement();
}
void Project::save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only, const QModelIndex& parent) {
for (int i=0;i<project_model.rowCount(parent);i++) {
const QModelIndex& item = project_model.index(i, 0, parent);
@@ -1049,6 +1060,11 @@ void Project::save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only,
}
}
// save markers
for (int k=0;k<c->markers.size();k++) {
save_marker(stream, c->markers.at(k));
}
stream.writeStartElement("linked"); // linked
for (int k=0;k<c->linked.size();k++) {
stream.writeStartElement("link"); // link
@@ -1067,10 +1083,7 @@ void Project::save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only,
}
}
for (int j=0;j<s->markers.size();j++) {
stream.writeStartElement("marker");
stream.writeAttribute("frame", QString::number(s->markers.at(j).frame));
stream.writeAttribute("name", s->markers.at(j).name);
stream.writeEndElement();
save_marker(stream, s->markers.at(j));
}
stream.writeEndElement();
}
+30 -3
View File
@@ -1426,7 +1426,14 @@ bool Timeline::snap_to_timeline(long* l, bool use_playhead, bool use_markers, bo
} else if (c->get_closing_transition() != nullptr
&& snap_to_point(c->timeline_out - c->get_closing_transition()->get_true_length(), l)) {
return true;
}
} else {
// try to snap to clip markers
for (int j=0;j<c->markers.size();j++) {
if (snap_to_point(c->markers.at(j).frame + c->timeline_in - c->clip_in, l)) {
return true;
}
}
}
}
}
}
@@ -1446,9 +1453,29 @@ void Timeline::set_marker() {
marker_name = d.textValue();
}
if (add_marker) {
undo_stack.push(new AddMarkerAction(sequence, sequence->playhead, marker_name));
ComboAction* ca = new ComboAction();
// see if any clips are selected, and if so add a marker to them
bool clip_mode = false;
for (int i=0;i<sequence->clips.size();i++) {
Clip* c = sequence->clips.at(i);
if (c != nullptr
&& is_clip_selected(c, true)) {
ca->append(new AddMarkerAction(false,
c,
sequence->playhead - c->timeline_in + c->clip_in,
marker_name));
clip_mode = true;
}
}
// if no clips are selected, we're adding a marker to the sequence
if (!clip_mode) {
ca->append(new AddMarkerAction(true, sequence, sequence->playhead, marker_name));
}
undo_stack.push(ca);
}
}
+5
View File
@@ -5,6 +5,8 @@
#include <QMutex>
#include <QVector>
#include "marker.h"
#define SKIP_TYPE_DISCARD 0
#define SKIP_TYPE_SEEK 1
@@ -73,6 +75,9 @@ struct Clip
bool maintain_audio_pitch;
bool autoscale;
// markers
QVector<Marker> markers;
// other variables (should be deep copied/duplicated in copy())
QList<Effect*> effects;
QVector<int> linked;
+17
View File
@@ -1 +1,18 @@
#include "marker.h"
void draw_marker(QPainter &p, int x, int y, int bottom, bool selected, bool flipped) {
const QPoint points[5] = {
QPoint(x, bottom),
QPoint(x + MARKER_SIZE, bottom - MARKER_SIZE),
QPoint(x + MARKER_SIZE, y),
QPoint(x - MARKER_SIZE, y),
QPoint(x - MARKER_SIZE, bottom - MARKER_SIZE)
};
p.setPen(Qt::black);
if (selected) {
p.setBrush(QColor(208, 255, 208));
} else {
p.setBrush(QColor(128, 224, 128));
}
p.drawPolygon(points, 5);
}
+5
View File
@@ -1,11 +1,16 @@
#ifndef MARKER_H
#define MARKER_H
#define MARKER_SIZE 4
#include <QString>
#include <QPainter>
struct Marker {
long frame;
QString name;
};
void draw_marker(QPainter& p, int x, int y, int bottom, bool selected, bool flipped);
#endif // MARKER_H
+36 -4
View File
@@ -1,6 +1,7 @@
#include "projectfilter.h"
#include "project/media.h"
#include "project/sequence.h"
#include <QDebug>
@@ -15,17 +16,48 @@ bool ProjectFilter::get_show_sequences() {
void ProjectFilter::set_show_sequences(bool b) {
show_sequences = b;
invalidateFilter();
invalidateFilter();
}
void ProjectFilter::update_search_filter(const QString &s) {
search_filter = s;
invalidateFilter();
}
bool ProjectFilter::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const {
// retrieve media object from index
QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
Media* media = static_cast<Media*>(index.internalPointer());
// hide sequences if show_sequences is false
if (!show_sequences) {
// hide sequences if show_sequences is false
QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
Media* media = static_cast<Media*>(index.internalPointer());
if (media != nullptr && media->get_type() == MEDIA_TYPE_SEQUENCE) {
return false;
}
}
// filter by search filter string
if (!search_filter.isEmpty()) {
// search markers if media is a sequene
bool marker_contains_search = false;
if (media->get_type() == MEDIA_TYPE_SEQUENCE) {
Sequence* s = media->to_sequence();
for (int i=0;i<s->markers.size();i++) {
if (s->markers.at(i).name.contains(search_filter, Qt::CaseInsensitive)) {
marker_contains_search = true;
break;
}
}
}
// hide any rows that don't contain the search string (unless it's a folder)
if (!marker_contains_search
&& media->get_type() != MEDIA_TYPE_FOLDER
&& !media->get_name().contains(search_filter, Qt::CaseInsensitive)) {
return false;
}
}
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
}
+19 -1
View File
@@ -7,13 +7,31 @@ class ProjectFilter : public QSortFilterProxyModel {
Q_OBJECT
public:
ProjectFilter(QObject *parent = nullptr);
// are sequences visible
bool get_show_sequences();
public slots:
// set whether sequences are visible
void set_show_sequences(bool b);
// update search filter
void update_search_filter(const QString& s);
protected:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
// function that filters whether rows are displayed or not
virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
private:
// internal variable for whether to show sequences
bool show_sequences;
// search filter variable
QString search_filter;
};
#endif // PROJECTFILTER_H
+20 -9
View File
@@ -803,18 +803,23 @@ void SetAutoscaleAction::redo() {
mainWindow->setWindowModified(true);
}
AddMarkerAction::AddMarkerAction(Sequence* s, long t, QString n) :
seq(s),
AddMarkerAction::AddMarkerAction(bool is_sequence, void* s, long t, QString n) :
is_sequence_internal(is_sequence),
target(s),
time(t),
name(n),
old_project_changed(mainWindow->isWindowModified())
{}
void AddMarkerAction::undo() {
QVector<Marker>& markers = is_sequence_internal ?
static_cast<Sequence*>(target)->markers :
static_cast<Clip*>(target)->markers;
if (index == -1) {
seq->markers.removeLast();
markers.removeLast();
} else {
seq->markers[index].name = old_name;
markers[index].name = old_name;
}
mainWindow->setWindowModified(old_project_changed);
@@ -822,8 +827,13 @@ void AddMarkerAction::undo() {
void AddMarkerAction::redo() {
index = -1;
for (int i=0;i<seq->markers.size();i++) {
if (seq->markers.at(i).frame == time) {
QVector<Marker>& markers = is_sequence_internal ?
static_cast<Sequence*>(target)->markers :
static_cast<Clip*>(target)->markers;
for (int i=0;i<markers.size();i++) {
if (markers.at(i).frame == time) {
index = i;
break;
}
@@ -832,10 +842,11 @@ void AddMarkerAction::redo() {
if (index == -1) {
Marker m;
m.frame = time;
seq->markers.append(m);
m.name = name;
markers.append(m);
} else {
old_name = seq->markers.at(index).name;
seq->markers[index].name = name;
old_name = markers.at(index).name;
markers[index].name = name;
}
mainWindow->setWindowModified(true);
+3 -2
View File
@@ -384,11 +384,12 @@ private:
class AddMarkerAction : public QUndoCommand {
public:
AddMarkerAction(Sequence* s, long t, QString n);
AddMarkerAction(bool is_sequence, void* s, long t, QString n);
void undo();
void redo();
private:
Sequence* seq;
bool is_sequence_internal;
void* target;
long time;
QString name;
QString old_name;
+1
View File
@@ -23,6 +23,7 @@ apps:
- pulseaudio
- home
- removable-media
- unity7
parts:
olive:
+11 -29
View File
@@ -20,7 +20,6 @@
#define PLAYHEAD_SIZE 6
#define LINE_MIN_PADDING 50
#define SUBLINE_MIN_PADDING 50 // TODO play with this
#define MARKER_SIZE 4
// used only if center_timeline_timecodes is FALSE
#define TEXT_PADDING_FROM_LINE 4
@@ -406,35 +405,18 @@ void TimelineHeader::paintEvent(QPaintEvent*) {
// draw markers
for (int i=0;i<viewer->seq->markers.size();i++) {
const Marker& m = viewer->seq->markers.at(i);
int marker_x = getHeaderScreenPointFromFrame(m.frame);
const QPoint points[5] = {
QPoint(marker_x, height()-1),
QPoint(marker_x + MARKER_SIZE, height() - MARKER_SIZE - 1),
QPoint(marker_x + MARKER_SIZE, yoff),
QPoint(marker_x - MARKER_SIZE, yoff),
QPoint(marker_x - MARKER_SIZE, height() - MARKER_SIZE - 1)
};
/*const QPoint points[5] = {
QPoint(marker_x, height()-1),
QPoint(marker_x + MARKER_SIZE, height() - MARKER_SIZE - 1),
QPoint(marker_x + MARKER_SIZE, yoff),
QPoint(marker_x - MARKER_SIZE, yoff),
QPoint(marker_x - MARKER_SIZE, height() - MARKER_SIZE - 1)
};*/
p.setPen(Qt::black);
bool selected = false;
for (int j=0;j<selected_markers.size();j++) {
if (selected_markers.at(j) == i) {
selected = true;
break;
}
}
if (selected) {
p.setBrush(QColor(208, 255, 208));
} else {
p.setBrush(QColor(128, 224, 128));
}
p.drawPolygon(points, 5);
bool selected = false;
for (int j=0;j<selected_markers.size();j++) {
if (selected_markers.at(j) == i) {
selected = true;
break;
}
}
draw_marker(p, marker_x, yoff, height()-1, selected, false);
}
// draw playhead triangle
+53 -7
View File
@@ -1244,6 +1244,8 @@ void TimelineWidget::update_ghosts(const QPoint& mouse_pos, bool lock_frame) {
// slipping doesn't move the clips so we don't bother snapping for it
for (int i=0;i<panel_timeline->ghosts.size();i++) {
const Ghost& g = panel_timeline->ghosts.at(i);
// snap ghost's in point
if (panel_timeline->trim_target == -1 || g.trim_in) {
fm = g.old_in + frame_diff;
if (panel_timeline->snap_to_timeline(&fm, true, true, true)) {
@@ -1251,6 +1253,8 @@ void TimelineWidget::update_ghosts(const QPoint& mouse_pos, bool lock_frame) {
break;
}
}
// snap ghost's out point
if (panel_timeline->trim_target == -1 || !g.trim_in) {
fm = g.old_out + frame_diff;
if (panel_timeline->snap_to_timeline(&fm, true, true, true)) {
@@ -1258,6 +1262,19 @@ void TimelineWidget::update_ghosts(const QPoint& mouse_pos, bool lock_frame) {
break;
}
}
// if the ghost is attached to a clip, snap its markers too
if (panel_timeline->trim_target == -1 && g.clip >= 0) {
Clip* c = sequence->clips.at(g.clip);
for (int j=0;j<c->markers.size();j++) {
long marker_real_time = c->markers.at(j).frame + c->timeline_in - c->clip_in;
fm = marker_real_time + frame_diff;
if (panel_timeline->snap_to_timeline(&fm, true, true, true)) {
frame_diff = fm - marker_real_time;
break;
}
}
}
}
}
@@ -2147,8 +2164,11 @@ void draw_waveform(Clip* clip, const FootageStream* ms, long media_length, QPain
int divider = ms->audio_channels*2;
int channel_height = clip_rect.height()/ms->audio_channels;
int last_waveform_index = -1;
for (int i=waveform_start;i<waveform_limit;i++) {
int waveform_index = qFloor((((clip->clip_in + ((double) i/zoom))/media_length) * ms->audio_preview.size())/divider)*divider;
if (last_waveform_index < 0) last_waveform_index = waveform_index;
if (clip->reverse) {
waveform_index = ms->audio_preview.size() - waveform_index - (ms->audio_channels * 2);
@@ -2156,21 +2176,35 @@ void draw_waveform(Clip* clip, const FootageStream* ms, long media_length, QPain
for (int j=0;j<ms->audio_channels;j++) {
int mid = (config.rectified_waveforms) ? clip_rect.top()+channel_height*(j+1) : clip_rect.top()+channel_height*j+(channel_height/2);
int offset = waveform_index+(j*2);
if ((offset + 1) < ms->audio_preview.size()) {
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);
int offset_range_start = last_waveform_index+(j*2);
int offset_range_end = waveform_index+(j*2);
qint8 min = qint8(qRound(double(ms->audio_preview.at(offset_range_start)) / 128.0 * (channel_height/2)));
qint8 max = qint8(qRound(double(ms->audio_preview.at(offset_range_start+1)) / 128.0 * (channel_height/2)));
if ((offset_range_end + 1) < ms->audio_preview.size()) {
// for waveform drawings, we get the maximum below 0 and maximum above 0 for this waveform range
for (int k=offset_range_start+2;k<=offset_range_end;k+=2) {
min = qMin(min, qint8(qRound(double(ms->audio_preview.at(k)) / 128.0 * (channel_height/2))));
max = qMax(max, qint8(qRound(double(ms->audio_preview.at(k+1)) / 128.0 * (channel_height/2))));
}
// draw waveforms
if (config.rectified_waveforms) {
// rectified waveforms start from the bottom and draw upwards
p->drawLine(clip_rect.left()+i, mid, clip_rect.left()+i, mid - (max - min));
} else {
// non-rectified waveforms start from the center and draw outwards
p->drawLine(clip_rect.left()+i, mid+min, clip_rect.left()+i, mid+max);
}
}/* else {
qWarning() << "Tried to reach" << offset + 1 << ", limit:" << ms->audio_preview.size();
}*/
}
}
last_waveform_index = waveform_index;
}
}
@@ -2394,6 +2428,18 @@ void TimelineWidget::paintEvent(QPaintEvent*) {
}
}
// draw clip markers
for (int j=0;j<clip->markers.size();j++) {
const Marker& m = clip->markers.at(j);
// convert marker time (in clip time) to sequence time
long marker_time = m.frame + clip->timeline_in - clip->clip_in;
int marker_x = panel_timeline->getTimelineScreenPointFromFrame(marker_time);
if (marker_x > clip_rect.x() && marker_x < clip_rect.right()) {
draw_marker(p, marker_x, clip_rect.bottom()-p.fontMetrics().height(), clip_rect.bottom(), false, false);
}
}
// draw clip transitions
draw_transition(p, clip, clip_rect, text_rect, TA_OPENING_TRANSITION);
draw_transition(p, clip, clip_rect, text_rect, TA_CLOSING_TRANSITION);
+15 -7
View File
@@ -93,7 +93,20 @@ void ViewerWidget::set_waveform_scroll(int s) {
if (waveform) {
waveform_scroll = s;
update();
}
}
}
void ViewerWidget::set_fullscreen(int screen) {
if (screen >= 0 && screen < QGuiApplication::screens().size()) {
QScreen* selected_screen = QGuiApplication::screens().at(screen);
window->showFullScreen();
window->setGeometry(selected_screen->geometry());
// HACK: window seems to show with distorted texture on first showing, so we queue an update after it's shown
QTimer::singleShot(100, window, SLOT(update()));
} else {
qCritical() << "Failed to find requested screen" << screen << "to set fullscreen to";
}
}
void ViewerWidget::show_context_menu() {
@@ -170,12 +183,7 @@ void ViewerWidget::fullscreen_menu_action(QAction *action) {
if (action->data().isNull()) {
window->hide();
} else {
QScreen* selected_screen = QGuiApplication::screens().at(action->data().toInt());
window->showFullScreen();
window->setGeometry(selected_screen->geometry());
// HACK: window seems to show with distorted texture on first showing, so we queue an update after it's shown
QTimer::singleShot(100, window, SLOT(update()));
set_fullscreen(action->data().toInt());
}
}
}
+1
View File
@@ -47,6 +47,7 @@ public:
void set_scroll(double x, double y);
public slots:
void set_waveform_scroll(int s);
void set_fullscreen(int screen = 0);
protected:
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);