From 94fae972cf3c3dda82588b4f5c0b992da9abb67f Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sun, 10 Jun 2018 00:14:29 -0700 Subject: [PATCH] basic save support added --- effects/effects.h | 3 + effects/paneffect.cpp | 11 +-- effects/transformeffect.cpp | 5 +- effects/volumeeffect.cpp | 9 +-- io/media.h | 1 + mainwindow.cpp | 5 ++ mainwindow.h | 2 + olive.pro.user | 2 +- panels/project.cpp | 138 +++++++++++++++++++++++++++++++++++- panels/project.h | 10 +++ project/effect.cpp | 22 ++++-- project/effect.h | 6 ++ ui/sourcetable.cpp | 3 +- ui/timelinewidget.cpp | 4 +- 14 files changed, 196 insertions(+), 25 deletions(-) diff --git a/effects/effects.h b/effects/effects.h index 15d77aecb..daa5bdf5b 100644 --- a/effects/effects.h +++ b/effects/effects.h @@ -3,6 +3,7 @@ #include "project/effect.h" +#include class QSpinBox; class QCheckBox; @@ -52,6 +53,7 @@ public: VolumeEffect(Clip* c); void process_audio(uint8_t* samples, int nb_bytes); Effect* copy(); + void save(QXmlStreamWriter* stream); QSpinBox* volume_val; }; @@ -61,6 +63,7 @@ public: PanEffect(Clip* c); void process_audio(uint8_t* samples, int nb_bytes); Effect* copy(); + void save(QXmlStreamWriter* stream); QSpinBox* pan_val; }; diff --git a/effects/paneffect.cpp b/effects/paneffect.cpp index 34ffe1f2b..685f441ad 100644 --- a/effects/paneffect.cpp +++ b/effects/paneffect.cpp @@ -7,12 +7,9 @@ #include "ui/collapsiblewidget.h" PanEffect::PanEffect(Clip* c) : Effect(c) { - container = new CollapsibleWidget(); - container->setText(audio_effect_names[AUDIO_PAN_EFFECT]); + setup_effect(EFFECT_TYPE_AUDIO, AUDIO_PAN_EFFECT); - ui = new QWidget(); - - QGridLayout* ui_layout = new QGridLayout(); + QGridLayout* ui_layout = new QGridLayout(); ui_layout->addWidget(new QLabel("Pan:"), 0, 0); pan_val = new QSpinBox(); @@ -34,6 +31,10 @@ Effect* PanEffect::copy() { return p; } +void PanEffect::save(QXmlStreamWriter *stream) { + stream->writeTextElement("pan", QString::number(pan_val->value())); +} + void PanEffect::process_audio(uint8_t *samples, int nb_bytes) { for (int i=0;isetText(video_effect_names[VIDEO_TRANSFORM_EFFECT]); - - ui = new QWidget(); + setup_effect(EFFECT_TYPE_VIDEO, VIDEO_TRANSFORM_EFFECT); QGridLayout* ui_layout = new QGridLayout(); diff --git a/effects/volumeeffect.cpp b/effects/volumeeffect.cpp index 986a8c23c..3caca736c 100644 --- a/effects/volumeeffect.cpp +++ b/effects/volumeeffect.cpp @@ -7,10 +7,7 @@ #include "ui/collapsiblewidget.h" VolumeEffect::VolumeEffect(Clip* c) : Effect(c) { - container = new CollapsibleWidget(); - container->setText(audio_effect_names[AUDIO_VOLUME_EFFECT]); - - ui = new QWidget(); + setup_effect(EFFECT_TYPE_AUDIO, AUDIO_VOLUME_EFFECT); QGridLayout* ui_layout = new QGridLayout(); @@ -34,6 +31,10 @@ Effect* VolumeEffect::copy() { return v; } +void VolumeEffect::save(QXmlStreamWriter *stream) { + stream->writeTextElement("volume", QString::number(volume_val->value())); +} + void VolumeEffect::process_audio(uint8_t *samples, int nb_bytes) { for (int i=0;i video_tracks; QVector audio_tracks; Sequence* sequence; + int save_id; long get_length_in_frames(float frame_rate); }; diff --git a/mainwindow.cpp b/mainwindow.cpp index c8c089cd2..3783b73a2 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -203,3 +203,8 @@ void MainWindow::on_action_Paste_triggered() panel_timeline->paste(); } } + +void MainWindow::on_action_Save_Project_triggered() +{ + panel_project->save_project(); +} diff --git a/mainwindow.h b/mainwindow.h index 987fe430a..453c20f59 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -63,6 +63,8 @@ private slots: void on_action_Paste_triggered(); + void on_action_Save_Project_triggered(); + private: Ui::MainWindow *ui; void setup_layout(); diff --git a/olive.pro.user b/olive.pro.user index 4aa700891..abdb7381c 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 49c4227ba..d0f00c3bb 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -2,15 +2,22 @@ #include "ui_project.h" #include "io/media.h" +#include "panels/panels.h" +#include "panels/timeline.h" +#include "panels/viewer.h" + #include #include #include #include #include #include +#include +#include #include "panels/timeline.h" #include "project/sequence.h" +#include "project/effect.h" extern "C" { #include @@ -58,7 +65,7 @@ void Project::new_sequence(Sequence *s) { QTreeWidgetItem* item = new QTreeWidgetItem(); item->setText(0, s->name); - item->setData(0, Qt::UserRole + 1, QVariant::fromValue(reinterpret_cast(m))); + set_media_of_tree(item, m); ui->treeWidget->addTopLevelItem(item); source_table = ui->treeWidget; @@ -153,7 +160,7 @@ void Project::import_dialog() { } item->setText(0, m->name); item->setText(1, QString::number(m->length)); - item->setData(0, Qt::UserRole + 1, QVariant::fromValue(reinterpret_cast(m))); + set_media_of_tree(item, m); ui->treeWidget->addTopLevelItem(item); } @@ -162,3 +169,130 @@ void Project::import_dialog() { delete [] filename; } } + +Media* Project::get_media_from_tree(QTreeWidgetItem* item) { + return reinterpret_cast(item->data(0, Qt::UserRole + 1).value()); +} + +void Project::set_media_of_tree(QTreeWidgetItem* item, Media* media) { + item->setData(0, Qt::UserRole + 1, QVariant::fromValue(reinterpret_cast(media))); +} + +void Project::remove_item(int i) { + Media* m = get_media_from_tree(ui->treeWidget->topLevelItem(i)); + if (m->is_sequence) { + delete m->sequence; + } + delete m; + ui->treeWidget->takeTopLevelItem(i); +} + +void Project::clear() { + int len = ui->treeWidget->topLevelItemCount(); + for (int i=0;iset_sequence(s); + panel_viewer->set_sequence(s); +} + +void Project::load_project() { + // clear existing project + set_sequence(NULL); + clear(); + + QFile file("C:/Users/Matt/Desktop/test.xml"); + if (!file.open(QIODevice::ReadOnly/* | QIODevice::Text*/)) { + qDebug() << "[ERROR] Could not open file"; + return; + } + + QXmlStreamReader stream(&file); + + while (!stream.atEnd()) { + stream.readNext(); + + } + if (stream.hasError()) { + qDebug() << "[ERROR] Error parsing XML." << stream.error(); + } +} + +void Project::save_project() { + QFile file("C:/Users/Matt/Desktop/test.xml"); + if (!file.open(QIODevice::WriteOnly/* | QIODevice::Text*/)) { + qDebug() << "[ERROR] Could not open file"; + return; + } + + QXmlStreamWriter stream(&file); + stream.setAutoFormatting(true); + stream.writeStartDocument(); + + int len = ui->treeWidget->topLevelItemCount(); + stream.writeStartElement("media"); + for (int i=0;itreeWidget->topLevelItem(i)); + if (!m->is_sequence) { + m->save_id = i; + stream.writeStartElement("footage"); + stream.writeAttribute("id", QString::number(m->save_id)); + stream.writeTextElement("name", m->name); + stream.writeTextElement("url", m->url); + stream.writeEndElement(); + } + } + stream.writeEndElement(); + + stream.writeStartElement("timeline"); + for (int i=0;itreeWidget->topLevelItem(i)); + if (m->is_sequence) { + Sequence* s = m->sequence; + stream.writeStartElement("sequence"); + stream.writeTextElement("name", s->name); + stream.writeTextElement("width", QString::number(s->width)); + stream.writeTextElement("height", QString::number(s->height)); + stream.writeTextElement("framerate", QString::number(s->frame_rate)); + stream.writeTextElement("afreq", QString::number(s->audio_frequency)); + stream.writeTextElement("alayout", QString::number(s->audio_layout)); + stream.writeStartElement("clips"); + for (int i=0;iclip_count();i++) { + Clip* c = s->get_clip(i); + + stream.writeStartElement("clip"); + stream.writeTextElement("name", c->name); + stream.writeTextElement("clipin", QString::number(c->clip_in)); + stream.writeTextElement("in", QString::number(c->timeline_in)); + stream.writeTextElement("out", QString::number(c->timeline_out)); + stream.writeTextElement("track", QString::number(c->track)); + stream.writeStartElement("color"); + stream.writeAttribute("r", QString::number(c->color_r)); + stream.writeAttribute("g", QString::number(c->color_g)); + stream.writeAttribute("b", QString::number(c->color_b)); + stream.writeEndElement(); + stream.writeTextElement("media", QString::number(c->media->save_id)); + stream.writeTextElement("stream", QString::number(c->media_stream->file_index)); + stream.writeStartElement("effects"); + for (int j=0;jeffects.size();j++) { + stream.writeStartElement("effect"); + Effect* e = c->effects.at(j); + stream.writeAttribute("id", QString::number(e->id)); + e->save(&stream); + stream.writeEndElement(); + } + stream.writeEndElement(); + stream.writeEndElement(); + } + stream.writeEndElement(); + } + } + stream.writeEndElement(); + + stream.writeEndDocument(); + + file.close(); +} diff --git a/panels/project.h b/panels/project.h index b184082dd..a95c34f8f 100644 --- a/panels/project.h +++ b/panels/project.h @@ -9,6 +9,7 @@ struct Sequence; class Timeline; class Viewer; class SourceTable; +class QTreeWidgetItem; namespace Ui { class Project; @@ -21,9 +22,18 @@ class Project : public QDockWidget public: explicit Project(QWidget *parent = 0); ~Project(); + void clear(); void import_dialog(); + void set_sequence(Sequence* s); void new_sequence(Sequence* s); QString get_next_sequence_name(); + void remove_item(int i); + + void load_project(); + void save_project(); + + Media* get_media_from_tree(QTreeWidgetItem* item); + void set_media_of_tree(QTreeWidgetItem* item, Media* media); SourceTable* source_table; diff --git a/project/effect.cpp b/project/effect.cpp index 0d505e3b1..f45ea6ad9 100644 --- a/project/effect.cpp +++ b/project/effect.cpp @@ -3,6 +3,8 @@ #include "panels/panels.h" #include "panels/viewer.h" #include "ui/viewerwidget.h" +#include "ui/collapsiblewidget.h" +#include "effects/effects.h" Effect::Effect(Clip* c) : parent_clip(c) { @@ -10,16 +12,24 @@ Effect::Effect(Clip* c) : parent_clip(c) type = EFFECT_TYPE_INVALID; } +void Effect::setup_effect(int t, int i) { + type = t; + id = i; + container = new CollapsibleWidget(); + if (type == EFFECT_TYPE_VIDEO) { + container->setText(video_effect_names[i]); + } else if (type == EFFECT_TYPE_AUDIO) { + container->setText(audio_effect_names[i]); + } + ui = new QWidget(); +} + void Effect::field_changed() { panel_viewer->viewer_widget->update(); } -Effect* Effect::copy() { - Effect* e = new Effect(parent_clip); - name = e->name; - type = e->type; - return e; -} +Effect* Effect::copy() {return NULL;} +void Effect::save(QXmlStreamWriter *stream) {} void Effect::process_gl(int*, int*) {} void Effect::process_audio(uint8_t*, int) {} diff --git a/project/effect.h b/project/effect.h index d1c99b746..9a092d538 100644 --- a/project/effect.h +++ b/project/effect.h @@ -7,6 +7,7 @@ class QWidget; class CollapsibleWidget; struct Clip; +class QXmlStreamWriter; enum EffectTypes { EFFECT_TYPE_INVALID, EFFECT_TYPE_VIDEO, EFFECT_TYPE_AUDIO }; @@ -16,18 +17,23 @@ class Effect : public QObject public: Effect(Clip* c); // default constructor int type; + int id; QString name; CollapsibleWidget* container; QWidget* ui; Clip* parent_clip; virtual Effect* copy(); + virtual void save(QXmlStreamWriter* stream); virtual void process_gl(int* anchor_x, int* anchor_y); virtual void process_audio(uint8_t* samples, int nb_bytes); public slots: void field_changed(); + +protected: + void setup_effect(int t, int i); }; #endif // EFFECT_H diff --git a/ui/sourcetable.cpp b/ui/sourcetable.cpp index 06f632b06..edb63c38b 100644 --- a/ui/sourcetable.cpp +++ b/ui/sourcetable.cpp @@ -19,8 +19,7 @@ void SourceTable::mouseDoubleClickEvent(QMouseEvent* ) } else if (selectedItems().count() == 1) { Media* m = reinterpret_cast(selectedItems().at(0)->data(0, Qt::UserRole + 1).value()); if (m->is_sequence) { - panel_timeline->set_sequence(m->sequence); - panel_viewer->set_sequence(m->sequence); + panel_project->set_sequence(m->sequence); } } } diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 9d83270f1..36a26586c 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -47,7 +47,7 @@ void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) { panel_timeline->drag_track_start = (bottom_align) ? -1 : 0; for (int i=0;i(items.at(i)->data(0, Qt::UserRole + 1).value()); + Media* m = panel_project->get_media_from_tree(items.at(i)); long duration = m->get_length_in_frames(panel_timeline->sequence->frame_rate); Ghost g = {NULL, entry_point, entry_point + duration}; g.media = m; @@ -544,6 +544,8 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { panel_timeline->cursor_frame > panel_timeline->playhead-limit-1 && panel_timeline->cursor_frame < panel_timeline->playhead+limit+1) { panel_timeline->cursor_frame = panel_timeline->playhead; + panel_timeline->snapped = true; + panel_timeline->snap_point = panel_timeline->playhead; } else { panel_timeline->snap_to_clip(&panel_timeline->cursor_frame); }