diff --git a/dialogs/autocutsilencedialog.cpp b/dialogs/autocutsilencedialog.cpp index 66f6110ab..3659cde2c 100644 --- a/dialogs/autocutsilencedialog.cpp +++ b/dialogs/autocutsilencedialog.cpp @@ -31,7 +31,7 @@ #include "panels/panels.h" #include "panels/timeline.h" -AutoCutSilenceDialog::AutoCutSilenceDialog(QWidget *parent, QVector clips) : +AutoCutSilenceDialog::AutoCutSilenceDialog(QWidget *parent, QVector clips) : QDialog(parent), clips_(clips) { @@ -124,16 +124,16 @@ void AutoCutSilenceDialog::cut_silence() { // Loop over clips provided to this dialog for (int j=0;jclips.at(clips_.at(j)).get(); + Clip* clip = clips_.at(j); // Check if this clip is an audio footage clip - if (clip->track() >= 0 + if (clip->type() == Track::kTypeAudio && clip->media() != nullptr && clip->media_stream()->preview_done) { // TODO provide warning for preview not being done QVector split_positions; - int clip_start = clip->timeline_in(); + long clip_start = clip->timeline_in(); const FootageStream* ms = clip->media_stream(); long media_length = clip->media_length(); @@ -156,7 +156,7 @@ void AutoCutSilenceDialog::cut_silence() { // read the current sample into the circular array qint8 tmp = 0; - for (int k=start; kaudio_preview.at(k))))); } vols[circular_index] = tmp; @@ -202,13 +202,13 @@ void AutoCutSilenceDialog::cut_silence() { } } - panel_timeline->split_clip_at_positions(ca, clips_.at(j), split_positions); + clip->track()->sequence()->SplitClipAtPositions(ca, clips_.at(j), split_positions); } } if (ca->hasActions()) { - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); } else { delete ca; } diff --git a/dialogs/autocutsilencedialog.h b/dialogs/autocutsilencedialog.h index 3b379f5ae..37fe57a61 100644 --- a/dialogs/autocutsilencedialog.h +++ b/dialogs/autocutsilencedialog.h @@ -31,7 +31,7 @@ class AutoCutSilenceDialog : public QDialog { Q_OBJECT public: - AutoCutSilenceDialog(QWidget* parent, QVector clips); + AutoCutSilenceDialog(QWidget* parent, QVector clips); public slots: virtual int exec() override; private slots: @@ -39,7 +39,7 @@ private slots: private: void cut_silence(); - QVector clips_; + QVector clips_; LabelSlider* attack_threshold; LabelSlider* release_threshold; diff --git a/dialogs/clippropertiesdialog.cpp b/dialogs/clippropertiesdialog.cpp index 9d109b648..9a5f51f43 100644 --- a/dialogs/clippropertiesdialog.cpp +++ b/dialogs/clippropertiesdialog.cpp @@ -92,7 +92,7 @@ ClipPropertiesDialog::ClipPropertiesDialog(QWidget *parent, QVector clip } // it's assumed all the clips come from the same sequence - duration_field_->SetFrameRate(first_clip->sequence->frame_rate); + duration_field_->SetFrameRate(first_clip->track()->sequence()->frame_rate); if (all_clips_have_same_duration) { duration_field_->SetDefault(first_clip->length()); @@ -124,7 +124,7 @@ void ClipPropertiesDialog::accept() long clip_duration_rounded = qRound(clip_duration); if (clip->length() != clip_duration_rounded) { - clip->move(ca, + clip->Move(ca, clip->timeline_in(), clip->timeline_in() + clip_duration_rounded, clip->clip_in(), @@ -135,7 +135,7 @@ void ClipPropertiesDialog::accept() } if (ca->hasActions()) { - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); update_ui(false); } else { delete ca; diff --git a/dialogs/exportdialog.cpp b/dialogs/exportdialog.cpp index b667ef3d3..797bcf946 100644 --- a/dialogs/exportdialog.cpp +++ b/dialogs/exportdialog.cpp @@ -68,14 +68,15 @@ enum ExportFormats { FORMAT_SIZE }; -ExportDialog::ExportDialog(QWidget *parent) : - QDialog(parent) +ExportDialog::ExportDialog(QWidget *parent, Sequence* sequence) : + QDialog(parent), + sequence_(sequence) { - setWindowTitle(tr("Export \"%1\"").arg(olive::ActiveSequence->name)); + setWindowTitle(tr("Export \"%1\"").arg(sequence->name)); setup_ui(); rangeCombobox->setCurrentIndex(0); - if (olive::ActiveSequence->using_workarea) { + if (sequence->using_workarea) { rangeCombobox->setEnabled(true); rangeCombobox->setCurrentIndex(1); } @@ -109,10 +110,10 @@ ExportDialog::ExportDialog(QWidget *parent) : formatCombobox->setCurrentIndex(FORMAT_MPEG4); // default to sequence's native dimensions - widthSpinbox->setValue(olive::ActiveSequence->width); - heightSpinbox->setValue(olive::ActiveSequence->height); - samplingRateSpinbox->setValue(olive::ActiveSequence->audio_frequency); - framerateSpinbox->setValue(olive::ActiveSequence->frame_rate); + widthSpinbox->setValue(sequence->width); + heightSpinbox->setValue(sequence->height); + samplingRateSpinbox->setValue(sequence->audio_frequency); + framerateSpinbox->setValue(sequence->frame_rate); // set some advanced defaults vcodec_params.threads = 0; @@ -537,6 +538,7 @@ void ExportDialog::StartExport() { // Set up export parameters to send to the ExportThread ExportParams params; + params.sequence = sequence_; params.filename = filename; params.video_enabled = videoGroupbox->isChecked(); if (params.video_enabled) { @@ -555,10 +557,10 @@ void ExportDialog::StartExport() { } params.start_frame = 0; - params.end_frame = olive::ActiveSequence->getEndFrame(); // entire sequence + params.end_frame = sequence_->GetEndFrame(); // entire sequence if (rangeCombobox->currentIndex() == 1) { - params.start_frame = qMax(olive::ActiveSequence->workarea_in, params.start_frame); - params.end_frame = qMin(olive::ActiveSequence->workarea_out, params.end_frame); + params.start_frame = qMax(sequence_->workarea_in, params.start_frame); + params.end_frame = qMin(sequence_->workarea_out, params.end_frame); } // Create export thread @@ -573,7 +575,7 @@ void ExportDialog::StartExport() { panel_effect_controls->Clear(); // Close all currently open clips - olive::ActiveSequence->Close(); + sequence_->Close(); olive::Global->set_export_state(true); @@ -654,7 +656,7 @@ void ExportDialog::comp_type_changed(int) { case COMPRESSION_TYPE_CBR: case COMPRESSION_TYPE_TARGETBR: videoBitrateLabel->setText(tr("Bitrate (Mbps):")); - videobitrateSpinbox->setValue(qMax(0.5, (double) qRound((0.01528 * olive::ActiveSequence->height) - 4.5))); + videobitrateSpinbox->setValue(qMax(0.5, (double) qRound((0.01528 * sequence_->height) - 4.5))); break; case COMPRESSION_TYPE_CFR: videoBitrateLabel->setText(tr("Quality (CRF):")); diff --git a/dialogs/exportdialog.h b/dialogs/exportdialog.h index 0d92fd4b2..d76d359f3 100644 --- a/dialogs/exportdialog.h +++ b/dialogs/exportdialog.h @@ -50,7 +50,7 @@ public: * * QWidget parent. Usually MainWindow. */ - explicit ExportDialog(QWidget *parent); + explicit ExportDialog(QWidget *parent, Sequence *sequence); private slots: /** @@ -270,6 +270,8 @@ private: * @brief Time value set when exporting begins to determine the total duration of the export */ qint64 total_export_time_start; + + Sequence* sequence_; }; #endif // EXPORTDIALOG_H diff --git a/dialogs/mediapropertiesdialog.cpp b/dialogs/mediapropertiesdialog.cpp index 45832cf79..01154ffb6 100644 --- a/dialogs/mediapropertiesdialog.cpp +++ b/dialogs/mediapropertiesdialog.cpp @@ -114,12 +114,12 @@ MediaPropertiesDialog::MediaPropertiesDialog(QWidget *parent, Media *i) : interlacing_box = new QComboBox(this); interlacing_box->addItem( tr("Auto (%1)").arg( - get_interlacing_name(f->video_tracks.at(0).video_auto_interlacing) + Footage::get_interlacing_name(f->video_tracks.at(0).video_auto_interlacing) ) ); - interlacing_box->addItem(get_interlacing_name(VIDEO_PROGRESSIVE)); - interlacing_box->addItem(get_interlacing_name(VIDEO_TOP_FIELD_FIRST)); - interlacing_box->addItem(get_interlacing_name(VIDEO_BOTTOM_FIELD_FIRST)); + interlacing_box->addItem(Footage::get_interlacing_name(VIDEO_PROGRESSIVE)); + interlacing_box->addItem(Footage::get_interlacing_name(VIDEO_TOP_FIELD_FIRST)); + interlacing_box->addItem(Footage::get_interlacing_name(VIDEO_BOTTOM_FIELD_FIRST)); interlacing_box->setCurrentIndex( (f->video_tracks.at(0).video_auto_interlacing == f->video_tracks.at(0).video_interlacing) @@ -232,7 +232,7 @@ void MediaPropertiesDialog::accept() { } ca->appendPost(new UpdateViewer()); - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); QDialog::accept(); } diff --git a/dialogs/newsequencedialog.cpp b/dialogs/newsequencedialog.cpp index 6860a77cd..5d23f49af 100644 --- a/dialogs/newsequencedialog.cpp +++ b/dialogs/newsequencedialog.cpp @@ -108,8 +108,8 @@ void NewSequenceDialog::accept() { s->audio_layout = AV_CH_LAYOUT_STEREO; ComboAction* ca = new ComboAction(); - panel_project->create_sequence_internal(ca, s, true, nullptr); - olive::UndoStack.push(ca); + olive::project_model.CreateSequence(ca, s, true, nullptr); + olive::undo_stack.push(ca); } else if (existing_item != nullptr) { @@ -128,14 +128,12 @@ void NewSequenceDialog::accept() { esc->audio_layout = AV_CH_LAYOUT_STEREO; ca->append(esc); - for (int i=0;iclips.size();i++) { - ClipPtr c = existing_sequence->clips.at(i); - if (c != nullptr) { - c->refactor_frame_rate(ca, multiplier, true); - } + QVector existing_sequence_clips = existing_sequence->GetAllClips(); + for (int i=0;irefactor_frame_rate(ca, multiplier, true); } - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); } else if (existing_sequence != nullptr) { @@ -235,13 +233,13 @@ void NewSequenceDialog::setup_ui() { videoLayout->addWidget(new QLabel(tr("Width:"), this), 0, 0, 1, 1); width_numeric = new QSpinBox(videoGroupBox); width_numeric->setMaximum(9999); - width_numeric->setValue(olive::CurrentConfig.default_sequence_width); + width_numeric->setValue(olive::config.default_sequence_width); videoLayout->addWidget(width_numeric, 0, 2, 1, 2); videoLayout->addWidget(new QLabel(tr("Height:"), this), 1, 0, 1, 2); height_numeric = new QSpinBox(videoGroupBox); height_numeric->setMaximum(9999); - height_numeric->setValue(olive::CurrentConfig.default_sequence_height); + height_numeric->setValue(olive::config.default_sequence_height); videoLayout->addWidget(height_numeric, 1, 2, 1, 2); videoLayout->addWidget(new QLabel(tr("Frame Rate:"), this), 2, 0, 1, 1); @@ -258,7 +256,7 @@ void NewSequenceDialog::setup_ui() { frame_rate_combobox->addItem("59.94 FPS", 59.94); frame_rate_combobox->addItem("60 FPS", 60.0); for (int i=0;icount();i++) { - if (qFuzzyCompare(frame_rate_combobox->itemData(i).toDouble(), olive::CurrentConfig.default_sequence_framerate)) { + if (qFuzzyCompare(frame_rate_combobox->itemData(i).toDouble(), olive::config.default_sequence_framerate)) { frame_rate_combobox->setCurrentIndex(i); } } @@ -288,7 +286,7 @@ void NewSequenceDialog::setup_ui() { audio_frequency_combobox = new QComboBox(audioGroupBox); combobox_audio_sample_rates(audio_frequency_combobox); for (int i=0;icount();i++) { - if (audio_frequency_combobox->itemData(i) == olive::CurrentConfig.default_sequence_audio_frequency) { + if (audio_frequency_combobox->itemData(i) == olive::config.default_sequence_audio_frequency) { audio_frequency_combobox->setCurrentIndex(i); } } diff --git a/dialogs/preferencesdialog.cpp b/dialogs/preferencesdialog.cpp index 03a2ce45a..f70a369b1 100644 --- a/dialogs/preferencesdialog.cpp +++ b/dialogs/preferencesdialog.cpp @@ -90,11 +90,11 @@ PreferencesDialog::PreferencesDialog(QWidget *parent) : // set up default sequence default_sequence.name = tr("Default Sequence"); - default_sequence.width = olive::CurrentConfig.default_sequence_width; - default_sequence.height = olive::CurrentConfig.default_sequence_height; - default_sequence.frame_rate = olive::CurrentConfig.default_sequence_framerate; - default_sequence.audio_frequency = olive::CurrentConfig.default_sequence_audio_frequency; - default_sequence.audio_layout = olive::CurrentConfig.default_sequence_audio_channel_layout; + default_sequence.width = olive::config.default_sequence_width; + default_sequence.height = olive::config.default_sequence_height; + default_sequence.frame_rate = olive::config.default_sequence_framerate; + default_sequence.audio_frequency = olive::config.default_sequence_audio_frequency; + default_sequence.audio_layout = olive::config.default_sequence_audio_channel_layout; } void PreferencesDialog::setup_kbd_shortcut_worker(QMenu* menu, QTreeWidgetItem* parent) { @@ -187,13 +187,13 @@ void PreferencesDialog::populate_ocio_menus(OCIO::ConstConfigRcPtr config) ocio_default_input->addItem(colorspace); - if (colorspace == olive::CurrentConfig.ocio_default_input_colorspace) { + if (colorspace == olive::config.ocio_default_input_colorspace) { ocio_default_input->setCurrentIndex(i); } } // Get current display name (if the config is empty, get the current default display) - QString current_display = olive::CurrentConfig.ocio_display; + QString current_display = olive::config.ocio_display; if (current_display.isEmpty()) { current_display = config->getDefaultDisplay(); } @@ -219,7 +219,7 @@ void PreferencesDialog::populate_ocio_menus(OCIO::ConstConfigRcPtr config) ocio_look->addItem(look, look); - if (look == olive::CurrentConfig.ocio_look) { + if (look == olive::config.ocio_look) { ocio_look->setCurrentIndex(i); } } @@ -249,7 +249,7 @@ void PreferencesDialog::update_ocio_view_menu(OCIO::ConstConfigRcPtr config) QString display = ocio_display->currentText(); // Get current view - QString current_view = olive::CurrentConfig.ocio_view; + QString current_view = olive::config.ocio_view; if (current_view.isEmpty()) { current_view = config->getDefaultView(display.toUtf8()); } @@ -351,7 +351,7 @@ void PreferencesDialog::accept() { ); return; - } else if (olive::CurrentConfig.ocio_config_path != ocio_config_file->text()) { + } else if (olive::config.ocio_config_path != ocio_config_file->text()) { // Check whether OCIO can load it OCIO::ConstConfigRcPtr file_config = TestOCIOConfig(ocio_config_file->text().toUtf8()); @@ -375,10 +375,10 @@ void PreferencesDialog::accept() { // Check if any settings will require a restart of Olive (including the bool options determined above) if (bool_requires_restart - || olive::CurrentConfig.thumbnail_resolution != thumbnail_res_spinbox->value() - || olive::CurrentConfig.waveform_resolution != waveform_res_spinbox->value() - || olive::CurrentConfig.css_path != custom_css_fn->text() - || olive::CurrentConfig.style != static_cast(ui_style->currentData().toInt())) { + || olive::config.thumbnail_resolution != thumbnail_res_spinbox->value() + || olive::config.waveform_resolution != waveform_res_spinbox->value() + || olive::config.css_path != custom_css_fn->text() + || olive::config.style != static_cast(ui_style->currentData().toInt())) { // any changes to these settings will require a restart - ask the user if we should do one now or later @@ -406,65 +406,65 @@ void PreferencesDialog::accept() { // Everything checks out, start saving settings from the UI to the backend - olive::CurrentConfig.css_path = custom_css_fn->text(); - olive::CurrentConfig.recording_mode = recordingComboBox->currentIndex() + 1; - olive::CurrentConfig.img_seq_formats = imgSeqFormatEdit->text(); - olive::CurrentConfig.upcoming_queue_size = upcoming_queue_spinbox->value(); - olive::CurrentConfig.upcoming_queue_type = upcoming_queue_type->currentIndex(); - olive::CurrentConfig.previous_queue_size = previous_queue_spinbox->value(); - olive::CurrentConfig.previous_queue_type = previous_queue_type->currentIndex(); + olive::config.css_path = custom_css_fn->text(); + olive::config.recording_mode = recordingComboBox->currentIndex() + 1; + olive::config.img_seq_formats = imgSeqFormatEdit->text(); + olive::config.upcoming_queue_size = upcoming_queue_spinbox->value(); + olive::config.upcoming_queue_type = upcoming_queue_type->currentIndex(); + olive::config.previous_queue_size = previous_queue_spinbox->value(); + olive::config.previous_queue_type = previous_queue_type->currentIndex(); // Audio settings may require the audio device to be re-initiated. - if (olive::CurrentConfig.preferred_audio_output != audio_output_devices->currentData().toString() - || olive::CurrentConfig.preferred_audio_input != audio_input_devices->currentData().toString() - || olive::CurrentConfig.audio_rate != audio_sample_rate->currentData().toInt()) { + if (olive::config.preferred_audio_output != audio_output_devices->currentData().toString() + || olive::config.preferred_audio_input != audio_input_devices->currentData().toString() + || olive::config.audio_rate != audio_sample_rate->currentData().toInt()) { reinit_audio = true; } - olive::CurrentConfig.preferred_audio_output = audio_output_devices->currentData().toString(); - olive::CurrentConfig.preferred_audio_input = audio_input_devices->currentData().toString(); - olive::CurrentConfig.audio_rate = audio_sample_rate->currentData().toInt(); + olive::config.preferred_audio_output = audio_output_devices->currentData().toString(); + olive::config.preferred_audio_input = audio_input_devices->currentData().toString(); + olive::config.audio_rate = audio_sample_rate->currentData().toInt(); - olive::CurrentConfig.effect_textbox_lines = effect_textbox_lines_field->value(); + olive::config.effect_textbox_lines = effect_textbox_lines_field->value(); // see if the language file should be reloaded (not necessary if the app is restarting anyway) if (!restart_after_saving - && olive::CurrentConfig.language_file != language_combobox->currentData().toString()) { + && olive::config.language_file != language_combobox->currentData().toString()) { reload_language = true; } - olive::CurrentConfig.language_file = language_combobox->currentData().toString(); + olive::config.language_file = language_combobox->currentData().toString(); // Check whether OCIO settings will require a reset of the render threads - if (olive::CurrentConfig.playback_bit_depth != playback_bit_depth->currentIndex() - || olive::CurrentConfig.export_bit_depth != export_bit_depth->currentIndex()) { + if (olive::config.playback_bit_depth != playback_bit_depth->currentIndex() + || olive::config.export_bit_depth != export_bit_depth->currentIndex()) { reset_render_threads = true; } - if (olive::CurrentConfig.ocio_config_path != ocio_config_file->text() - || olive::CurrentConfig.ocio_display != ocio_display->currentText() - || olive::CurrentConfig.ocio_view != ocio_view->currentText() - || olive::CurrentConfig.ocio_look != ocio_look->currentData().toString()) { + if (olive::config.ocio_config_path != ocio_config_file->text() + || olive::config.ocio_display != ocio_display->currentText() + || olive::config.ocio_view != ocio_view->currentText() + || olive::config.ocio_look != ocio_look->currentData().toString()) { reset_ocio_shaders = true; } - if (olive::CurrentConfig.ocio_config_path != ocio_config_file->text()) { + if (olive::config.ocio_config_path != ocio_config_file->text()) { OCIO::SetCurrentConfig(OCIO::Config::CreateFromFile(ocio_config_file->text().toUtf8())); - olive::CurrentConfig.ocio_config_path = ocio_config_file->text(); + olive::config.ocio_config_path = ocio_config_file->text(); } - olive::CurrentConfig.enable_color_management = enable_color_management->isChecked(); - olive::CurrentConfig.playback_bit_depth = playback_bit_depth->currentIndex(); - olive::CurrentConfig.export_bit_depth = export_bit_depth->currentIndex(); - olive::CurrentConfig.ocio_display = ocio_display->currentText(); - olive::CurrentConfig.ocio_default_input_colorspace = ocio_default_input->currentText(); - olive::CurrentConfig.ocio_view = ocio_view->currentText(); + olive::config.enable_color_management = enable_color_management->isChecked(); + olive::config.playback_bit_depth = playback_bit_depth->currentIndex(); + olive::config.export_bit_depth = export_bit_depth->currentIndex(); + olive::config.ocio_display = ocio_display->currentText(); + olive::config.ocio_default_input_colorspace = ocio_default_input->currentText(); + olive::config.ocio_view = ocio_view->currentText(); // We use data here instead of text because there's a "(None)" option with an empty string - olive::CurrentConfig.ocio_look = ocio_look->currentData().toString(); + olive::config.ocio_look = ocio_look->currentData().toString(); // Set default sequence options - olive::CurrentConfig.default_sequence_width = default_sequence.width; - olive::CurrentConfig.default_sequence_height = default_sequence.height; - olive::CurrentConfig.default_sequence_framerate = default_sequence.frame_rate; - olive::CurrentConfig.default_sequence_audio_frequency = default_sequence.audio_frequency; - olive::CurrentConfig.default_sequence_audio_channel_layout = default_sequence.audio_layout; + olive::config.default_sequence_width = default_sequence.width; + olive::config.default_sequence_height = default_sequence.height; + olive::config.default_sequence_framerate = default_sequence.frame_rate; + olive::config.default_sequence_audio_frequency = default_sequence.audio_frequency; + olive::config.default_sequence_audio_channel_layout = default_sequence.audio_layout; // Set all bool options for (int i=0;i(ui_style->currentData().toInt()); + olive::config.style = static_cast(ui_style->currentData().toInt()); // Check if the thumbnail or waveform icon fields have changed, we may need to recreate the previews if so - if (olive::CurrentConfig.thumbnail_resolution != thumbnail_res_spinbox->value() - || olive::CurrentConfig.waveform_resolution != waveform_res_spinbox->value()) { + if (olive::config.thumbnail_resolution != thumbnail_res_spinbox->value() + || olive::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 // delete nothing PreviewDeleteTypes delete_type = DELETE_NONE; - if (olive::CurrentConfig.thumbnail_resolution != thumbnail_res_spinbox->value()) { + if (olive::config.thumbnail_resolution != thumbnail_res_spinbox->value()) { // delete existing thumbnails - olive::CurrentConfig.thumbnail_resolution = thumbnail_res_spinbox->value(); + olive::config.thumbnail_resolution = thumbnail_res_spinbox->value(); // delete only thumbnails delete_type = DELETE_THUMBNAILS; } - if (olive::CurrentConfig.waveform_resolution != waveform_res_spinbox->value()) { + if (olive::config.waveform_resolution != waveform_res_spinbox->value()) { // delete existing waveforms - olive::CurrentConfig.waveform_resolution = waveform_res_spinbox->value(); + olive::config.waveform_resolution = waveform_res_spinbox->value(); // if we're already deleting thumbnails if (delete_type == DELETE_THUMBNAILS) { @@ -749,7 +749,7 @@ void PreferencesDialog::setup_ui() { QString locale_str = locale_file_basename.mid(locale_file_basename.lastIndexOf('_')+1); language_combobox->addItem(QLocale(locale_str).nativeLanguageName(), locale_relative_path); - if (olive::CurrentConfig.language_file == locale_relative_path) { + if (olive::config.language_file == locale_relative_path) { language_combobox->setCurrentIndex(language_combobox->count() - 1); } } @@ -764,7 +764,7 @@ void PreferencesDialog::setup_ui() { general_layout->addWidget(new QLabel(tr("Image sequence formats:"), this), row, 0); imgSeqFormatEdit = new QLineEdit(general_tab); - imgSeqFormatEdit->setText(olive::CurrentConfig.img_seq_formats); + imgSeqFormatEdit->setText(olive::config.img_seq_formats); general_layout->addWidget(imgSeqFormatEdit, row, 1, 1, 4); row++; @@ -775,7 +775,7 @@ void PreferencesDialog::setup_ui() { thumbnail_res_spinbox = new QSpinBox(this); thumbnail_res_spinbox->setMinimum(0); thumbnail_res_spinbox->setMaximum(INT_MAX); - thumbnail_res_spinbox->setValue(olive::CurrentConfig.thumbnail_resolution); + thumbnail_res_spinbox->setValue(olive::config.thumbnail_resolution); general_layout->addWidget(thumbnail_res_spinbox, row, 1); general_layout->addWidget(new QLabel(tr("Waveform Resolution:"), this), row, 2); @@ -783,7 +783,7 @@ void PreferencesDialog::setup_ui() { waveform_res_spinbox = new QSpinBox(this); waveform_res_spinbox->setMinimum(0); waveform_res_spinbox->setMaximum(INT_MAX); - waveform_res_spinbox->setValue(olive::CurrentConfig.waveform_resolution); + waveform_res_spinbox->setValue(olive::config.waveform_resolution); general_layout->addWidget(waveform_res_spinbox, row, 3); QPushButton* delete_preview_btn = new QPushButton(tr("Delete Previews")); @@ -796,13 +796,13 @@ void PreferencesDialog::setup_ui() { // General -> Use Software Fallbacks When Possible QCheckBox* use_software_fallbacks_checkbox = new QCheckBox(tr("Use Software Fallbacks When Possible")); - AddBoolPair(use_software_fallbacks_checkbox, &olive::CurrentConfig.use_software_fallback, true); + AddBoolPair(use_software_fallbacks_checkbox, &olive::config.use_software_fallback, true); misc_general->addWidget(use_software_fallbacks_checkbox); // General -> Don't Use Proxies When Exporting QCheckBox* dont_use_proxies_when_exporting = new QCheckBox(tr("Don't Use Proxies When Exporting")); dont_use_proxies_when_exporting->setToolTip(tr("Use originals instead of proxies when exporting")); - AddBoolPair(dont_use_proxies_when_exporting, &olive::CurrentConfig.dont_use_proxies_on_export); + AddBoolPair(dont_use_proxies_when_exporting, &olive::config.dont_use_proxies_on_export); misc_general->addWidget(dont_use_proxies_when_exporting); // General -> Default Sequence Settings @@ -823,68 +823,68 @@ void PreferencesDialog::setup_ui() { ColumnedGridLayout* behavior_tab_layout = new ColumnedGridLayout(behavior_tab, 2); QCheckBox* add_default_effects_to_clips = new QCheckBox(tr("Add Default Effects to New Clips")); - AddBoolPair(add_default_effects_to_clips, &olive::CurrentConfig.add_default_effects_to_clips); + AddBoolPair(add_default_effects_to_clips, &olive::config.add_default_effects_to_clips); behavior_tab_layout->Add(add_default_effects_to_clips); QCheckBox* auto_seek_to_beginning = new QCheckBox(tr("Automatically Seek to the Beginning When Playing at the End of a Sequence")); - AddBoolPair(auto_seek_to_beginning, &olive::CurrentConfig.auto_seek_to_beginning); + AddBoolPair(auto_seek_to_beginning, &olive::config.auto_seek_to_beginning); behavior_tab_layout->Add(auto_seek_to_beginning); QCheckBox* selecting_also_seeks = new QCheckBox(tr("Selecting Also Seeks")); - AddBoolPair(selecting_also_seeks, &olive::CurrentConfig.select_also_seeks); + AddBoolPair(selecting_also_seeks, &olive::config.select_also_seeks); behavior_tab_layout->Add(selecting_also_seeks); QCheckBox* edit_tool_also_seeks = new QCheckBox(tr("Edit Tool Also Seeks")); - AddBoolPair(edit_tool_also_seeks, &olive::CurrentConfig.edit_tool_also_seeks); + AddBoolPair(edit_tool_also_seeks, &olive::config.edit_tool_also_seeks); behavior_tab_layout->Add(edit_tool_also_seeks); QCheckBox* edit_tool_selects_links = new QCheckBox(tr("Edit Tool Selects Links")); - AddBoolPair(edit_tool_selects_links, &olive::CurrentConfig.edit_tool_selects_links); + AddBoolPair(edit_tool_selects_links, &olive::config.edit_tool_selects_links); behavior_tab_layout->Add(edit_tool_selects_links); QCheckBox* seek_also_selects = new QCheckBox(tr("Seek Also Selects")); - AddBoolPair(seek_also_selects, &olive::CurrentConfig.seek_also_selects); + AddBoolPair(seek_also_selects, &olive::config.seek_also_selects); behavior_tab_layout->Add(seek_also_selects); QCheckBox* seek_to_end_of_pastes = new QCheckBox(tr("Seek to the End of Pastes")); - AddBoolPair(seek_to_end_of_pastes, &olive::CurrentConfig.paste_seeks); + AddBoolPair(seek_to_end_of_pastes, &olive::config.paste_seeks); behavior_tab_layout->Add(seek_to_end_of_pastes); QCheckBox* scroll_wheel_zooms = new QCheckBox(tr("Scroll Wheel Zooms")); scroll_wheel_zooms->setToolTip(tr("Hold CTRL to toggle this setting")); - AddBoolPair(scroll_wheel_zooms, &olive::CurrentConfig.scroll_zooms); + AddBoolPair(scroll_wheel_zooms, &olive::config.scroll_zooms); behavior_tab_layout->Add(scroll_wheel_zooms); QCheckBox* invert_timeline_scroll_axes = new QCheckBox(tr("Invert Timeline Scroll Axes")); - AddBoolPair(invert_timeline_scroll_axes, &olive::CurrentConfig.invert_timeline_scroll_axes); + AddBoolPair(invert_timeline_scroll_axes, &olive::config.invert_timeline_scroll_axes); behavior_tab_layout->Add(invert_timeline_scroll_axes); QCheckBox* enable_drag_files_to_timeline = new QCheckBox(tr("Enable Drag Files to Timeline")); - AddBoolPair(enable_drag_files_to_timeline, &olive::CurrentConfig.enable_drag_files_to_timeline); + AddBoolPair(enable_drag_files_to_timeline, &olive::config.enable_drag_files_to_timeline); behavior_tab_layout->Add(enable_drag_files_to_timeline); QCheckBox* autoscale_by_default = new QCheckBox(tr("Auto-Scale By Default")); - AddBoolPair(autoscale_by_default, &olive::CurrentConfig.autoscale_by_default); + AddBoolPair(autoscale_by_default, &olive::config.autoscale_by_default); behavior_tab_layout->Add(autoscale_by_default); QCheckBox* enable_seek_to_import = new QCheckBox(tr("Auto-Seek to Imported Clips")); - AddBoolPair(enable_seek_to_import, &olive::CurrentConfig.enable_seek_to_import); + AddBoolPair(enable_seek_to_import, &olive::config.enable_seek_to_import); behavior_tab_layout->Add(enable_seek_to_import); QCheckBox* enable_audio_scrubbing = new QCheckBox(tr("Audio Scrubbing")); - AddBoolPair(enable_audio_scrubbing, &olive::CurrentConfig.enable_audio_scrubbing); + AddBoolPair(enable_audio_scrubbing, &olive::config.enable_audio_scrubbing); behavior_tab_layout->Add(enable_audio_scrubbing); QCheckBox* enable_drop_on_media_to_replace = new QCheckBox(tr("Drop Files on Media to Replace")); - AddBoolPair(enable_drop_on_media_to_replace, &olive::CurrentConfig.drop_on_media_to_replace); + AddBoolPair(enable_drop_on_media_to_replace, &olive::config.drop_on_media_to_replace); behavior_tab_layout->Add(enable_drop_on_media_to_replace); QCheckBox* enable_hover_focus = new QCheckBox(tr("Enable Hover Focus")); - AddBoolPair(enable_hover_focus, &olive::CurrentConfig.hover_focus); + AddBoolPair(enable_hover_focus, &olive::config.hover_focus); behavior_tab_layout->Add(enable_hover_focus); QCheckBox* set_name_and_marker = new QCheckBox(tr("Ask For Name When Setting Marker")); - AddBoolPair(set_name_and_marker, &olive::CurrentConfig.set_name_with_marker); + AddBoolPair(set_name_and_marker, &olive::config.set_name_with_marker); behavior_tab_layout->Add(set_name_and_marker); // Appearance @@ -903,7 +903,7 @@ void PreferencesDialog::setup_ui() { ui_style->addItem(tr("Olive Light"), olive::styling::kOliveDefaultLight); ui_style->addItem(tr("Native"), olive::styling::kNativeDarkIcons); ui_style->addItem(tr("Native (Light Icons)"), olive::styling::kNativeLightIcons); - ui_style->setCurrentIndex(olive::CurrentConfig.style); + ui_style->setCurrentIndex(olive::config.style); appearance_layout->addWidget(ui_style, row, 1, 1, 2); row++; @@ -922,7 +922,7 @@ void PreferencesDialog::setup_ui() { appearance_layout->addWidget(new QLabel(tr("Custom CSS:"), this), row, 0); custom_css_fn = new QLineEdit(general_tab); - custom_css_fn->setText(olive::CurrentConfig.css_path); + custom_css_fn->setText(olive::config.css_path); appearance_layout->addWidget(custom_css_fn, row, 1); QPushButton* custom_css_browse = new QPushButton(tr("Browse"), general_tab); @@ -936,7 +936,7 @@ void PreferencesDialog::setup_ui() { effect_textbox_lines_field = new QSpinBox(general_tab); effect_textbox_lines_field->setMinimum(1); - effect_textbox_lines_field->setValue(olive::CurrentConfig.effect_textbox_lines); + effect_textbox_lines_field->setValue(olive::config.effect_textbox_lines); appearance_layout->addWidget(effect_textbox_lines_field, row, 1, 1, 2); row++; @@ -951,21 +951,21 @@ void PreferencesDialog::setup_ui() { QGridLayout* memory_usage_layout = new QGridLayout(memory_usage_group); memory_usage_layout->addWidget(new QLabel(tr("Upcoming Frame Queue:"), playback_tab), 0, 0); upcoming_queue_spinbox = new QDoubleSpinBox(playback_tab); - upcoming_queue_spinbox->setValue(olive::CurrentConfig.upcoming_queue_size); + upcoming_queue_spinbox->setValue(olive::config.upcoming_queue_size); memory_usage_layout->addWidget(upcoming_queue_spinbox, 0, 1); upcoming_queue_type = new QComboBox(playback_tab); upcoming_queue_type->addItem(tr("frames")); upcoming_queue_type->addItem(tr("seconds")); - upcoming_queue_type->setCurrentIndex(olive::CurrentConfig.upcoming_queue_type); + upcoming_queue_type->setCurrentIndex(olive::config.upcoming_queue_type); memory_usage_layout->addWidget(upcoming_queue_type, 0, 2); memory_usage_layout->addWidget(new QLabel(tr("Previous Frame Queue:"), playback_tab), 1, 0); previous_queue_spinbox = new QDoubleSpinBox(playback_tab); - previous_queue_spinbox->setValue(olive::CurrentConfig.previous_queue_size); + previous_queue_spinbox->setValue(olive::config.previous_queue_size); memory_usage_layout->addWidget(previous_queue_spinbox, 1, 1); previous_queue_type = new QComboBox(playback_tab); previous_queue_type->addItem(tr("frames")); previous_queue_type->addItem(tr("seconds")); - previous_queue_type->setCurrentIndex(olive::CurrentConfig.previous_queue_type); + previous_queue_type->setCurrentIndex(olive::config.previous_queue_type); memory_usage_layout->addWidget(previous_queue_type, 1, 2); playback_tab_layout->addWidget(memory_usage_group); @@ -991,7 +991,7 @@ void PreferencesDialog::setup_ui() { for (int i=0;iaddItem(devs.at(i).deviceName(), devs.at(i).deviceName()); if (!found_preferred_device - && devs.at(i).deviceName() == olive::CurrentConfig.preferred_audio_output) { + && devs.at(i).deviceName() == olive::config.preferred_audio_output) { audio_output_devices->setCurrentIndex(audio_output_devices->count()-1); found_preferred_device = true; } @@ -1014,7 +1014,7 @@ void PreferencesDialog::setup_ui() { for (int i=0;iaddItem(devs.at(i).deviceName(), devs.at(i).deviceName()); if (!found_preferred_device - && devs.at(i).deviceName() == olive::CurrentConfig.preferred_audio_input) { + && devs.at(i).deviceName() == olive::config.preferred_audio_input) { audio_input_devices->setCurrentIndex(audio_input_devices->count()-1); found_preferred_device = true; } @@ -1031,7 +1031,7 @@ void PreferencesDialog::setup_ui() { audio_sample_rate = new QComboBox(); combobox_audio_sample_rates(audio_sample_rate); for (int i=0;icount();i++) { - if (audio_sample_rate->itemData(i).toInt() == olive::CurrentConfig.audio_rate) { + if (audio_sample_rate->itemData(i).toInt() == olive::config.audio_rate) { audio_sample_rate->setCurrentIndex(i); break; } @@ -1047,7 +1047,7 @@ void PreferencesDialog::setup_ui() { recordingComboBox = new QComboBox(general_tab); recordingComboBox->addItem(tr("Mono")); recordingComboBox->addItem(tr("Stereo")); - recordingComboBox->setCurrentIndex(olive::CurrentConfig.recording_mode - 1); + recordingComboBox->setCurrentIndex(olive::config.recording_mode - 1); audio_tab_layout->addWidget(recordingComboBox, row, 1); row++; @@ -1066,7 +1066,7 @@ void PreferencesDialog::setup_ui() { // COLOR MANAGEMENT -> Enable Color Management enable_color_management = new QCheckBox(tr("Enable Color Management")); - enable_color_management->setChecked(olive::CurrentConfig.enable_color_management); + enable_color_management->setChecked(olive::config.enable_color_management); color_management_layout->addWidget(enable_color_management, row, 0); row++; @@ -1078,7 +1078,7 @@ void PreferencesDialog::setup_ui() { opencolorio_groupbox_layout->addWidget(new QLabel(tr("OpenColorIO Config File:")), 0, 0); ocio_config_file = new QLineEdit(); - ocio_config_file->setText(olive::CurrentConfig.ocio_config_path); + ocio_config_file->setText(olive::config.ocio_config_path); connect(ocio_config_file, SIGNAL(textChanged(const QString &)), this, SLOT(update_ocio_config(const QString&))); opencolorio_groupbox_layout->addWidget(ocio_config_file, 0, 1, 1, 4); @@ -1120,7 +1120,7 @@ void PreferencesDialog::setup_ui() { for (int i=0;iaddItem(olive::pixel_formats.at(i).name, i); } - playback_bit_depth->setCurrentIndex(olive::CurrentConfig.playback_bit_depth); + playback_bit_depth->setCurrentIndex(olive::config.playback_bit_depth); bit_depth_groupbox_layout->addWidget(new QLabel(tr("Playback (Offline):")), 0, 0); bit_depth_groupbox_layout->addWidget(playback_bit_depth, 0, 1); @@ -1129,7 +1129,7 @@ void PreferencesDialog::setup_ui() { for (int i=0;iaddItem(olive::pixel_formats.at(i).name, i); } - export_bit_depth->setCurrentIndex(olive::CurrentConfig.export_bit_depth); + export_bit_depth->setCurrentIndex(olive::config.export_bit_depth); bit_depth_groupbox_layout->addWidget(new QLabel(tr("Export (Online):")), 0, 2); bit_depth_groupbox_layout->addWidget(export_bit_depth, 0, 3); diff --git a/dialogs/replaceclipmediadialog.cpp b/dialogs/replaceclipmediadialog.cpp index 67e73e386..d90452a6e 100644 --- a/dialogs/replaceclipmediadialog.cpp +++ b/dialogs/replaceclipmediadialog.cpp @@ -95,7 +95,10 @@ void ReplaceClipMediaDialog::accept() { QMessageBox::Ok ); } else { - if (new_item->get_type() == MEDIA_TYPE_SEQUENCE && olive::ActiveSequence == new_item->to_sequence()) { + + SequencePtr top_sequence = Timeline::GetTopSequence(); + + if (new_item->get_type() == MEDIA_TYPE_SEQUENCE && top_sequence == new_item->to_sequence()) { QMessageBox::critical( this, tr("Active sequence selected"), @@ -109,14 +112,15 @@ void ReplaceClipMediaDialog::accept() { use_same_media_in_points->isChecked() ); - for (int i=0;iclips.size();i++) { - ClipPtr c = olive::ActiveSequence->clips.at(i); - if (c != nullptr && c->media() == media) { + QVector all_clips = top_sequence->GetAllClips(); + for (int i=0;imedia() == media) { rcmc->clips.append(c); } } - olive::UndoStack.push(rcmc); + olive::undo_stack.push(rcmc); QDialog::accept(); } diff --git a/dialogs/speeddialog.cpp b/dialogs/speeddialog.cpp index ff3f9ddd5..0e11063f9 100644 --- a/dialogs/speeddialog.cpp +++ b/dialogs/speeddialog.cpp @@ -61,7 +61,7 @@ SpeedDialog::SpeedDialog(QWidget *parent, QVector clips) : QDialog(parent grid->addWidget(new QLabel(tr("Duration:"), this), 2, 0); duration = new LabelSlider(this); duration->SetDisplayType(LabelSlider::FrameNumber); - duration->SetFrameRate(olive::ActiveSequence->frame_rate); + duration->SetFrameRate(clips_.first()->track()->sequence()->frame_rate); grid->addWidget(duration, 2, 1); main_layout->addLayout(grid); @@ -103,7 +103,7 @@ int SpeedDialog::exec() { // get default frame rate/percentage clip_percent = c->speed().value; - if (c->track() < 0) { + if (c->type() == Track::kTypeVideo) { bool process_video = true; if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) { FootageStream* ms = c->media_stream(); @@ -131,7 +131,7 @@ int SpeedDialog::exec() { enable_frame_rate = true; } - } else { + } else if (c->type() == Track::kTypeAudio) { maintain_pitch->setEnabled(true); if (!multiple_audio) { @@ -192,7 +192,7 @@ void SpeedDialog::percent_update() { Clip* c = clips_.at(i); // get frame rate - if (frame_rate->isEnabled() && c->track() < 0) { + if (frame_rate->isEnabled() && c->type() == Track::kTypeVideo) { double clip_fr = c->media_frame_rate() * percent->value(); if (got_fr) { if (!qIsNaN(fr_val) && !qFuzzyCompare(fr_val, clip_fr)) { @@ -236,7 +236,7 @@ void SpeedDialog::duration_update() { } // get frame rate - if (frame_rate->isEnabled() && c->track() < 0) { + if (frame_rate->isEnabled() && c->type() == Track::kTypeVideo) { double clip_fr = c->media_frame_rate() * clip_pc; if (got_fr) { if (!qIsNaN(fr_val) && !qFuzzyCompare(fr_val, clip_fr)) { @@ -276,7 +276,7 @@ void SpeedDialog::frame_rate_update() { old_pc_val = qSNaN(); } - if (c->track() < 0) { + if (c->type() == Track::kTypeVideo) { // what would the new speed be based on this frame rate double new_clip_speed = frame_rate->value() / c->media_frame_rate(); if (!got_pc_val) { @@ -301,7 +301,7 @@ void SpeedDialog::frame_rate_update() { for (int i=0;itrack() >= 0) { + if (c->type() == Track::kTypeAudio) { long new_clip_len = (qIsNaN(old_pc_val) || qIsNaN(pc_val)) ? c->length() : qRound((c->length() * c->speed().value) / pc_val); @@ -318,15 +318,17 @@ void SpeedDialog::frame_rate_update() { } void set_speed(ComboAction* ca, Clip* c, double speed, bool ripple, long& ep, long& lr) { - panel_timeline->deselect_area(c->timeline_in(), c->timeline_out(), c->track()); + c->track()->DeselectArea(c->timeline_in(), c->timeline_out()); long proposed_out = c->timeline_out(); double multiplier = (c->speed().value / speed); proposed_out = qRound(c->timeline_in() + (c->length() * multiplier)); ca->append(new SetSpeedAction(c, speed)); if (!ripple && proposed_out > c->timeline_out()) { - for (int i=0;isequence->clips.size();i++) { - ClipPtr compare = c->sequence->clips.at(i); + QVector all_clips = c->track()->sequence()->GetAllClips(); + + for (int i=0;itrack() == c->track() && compare->timeline_in() >= c->timeline_out() && compare->timeline_in() < proposed_out) { @@ -336,15 +338,16 @@ void set_speed(ComboAction* ca, Clip* c, double speed, bool ripple, long& ep, lo } ep = qMin(ep, c->timeline_out()); lr = qMax(lr, proposed_out - c->timeline_out()); - c->move(ca, c->timeline_in(), proposed_out, qRound(c->clip_in() * multiplier), c->track()); + c->track()->sequence()->MoveClip(c, + ca, + c->timeline_in(), + proposed_out, + qRound(c->clip_in() * multiplier), + c->track()); c->refactor_frame_rate(ca, multiplier, false); - Selection sel; - sel.in = c->timeline_in(); - sel.out = proposed_out; - sel.track = c->track(); - olive::ActiveSequence->selections.append(sel); + c->track()->SelectArea(c->timeline_in(), proposed_out); } void SpeedDialog::accept() { @@ -357,8 +360,8 @@ void SpeedDialog::accept() { SetClipProperty* reversed_action = new SetClipProperty(kSetClipPropertyReversed); // undoable action for restoring clip selections - SetSelectionsCommand* sel_command = new SetSelectionsCommand(olive::ActiveSequence.get()); - sel_command->old_data = olive::ActiveSequence->selections; + Sequence* sequence = clips_.first()->track()->sequence(); + QVector old_selections = sequence->Selections(); // variables used to calculate ripples long earliest_point = LONG_MAX; @@ -373,7 +376,7 @@ void SpeedDialog::accept() { } // set maintain audio pitch if the user made a selection - if (c->track() >= 0 + if (c->type() == Track::kTypeAudio && maintain_pitch->checkState() != Qt::PartiallyChecked && c->speed().maintain_audio_pitch != maintain_pitch->isChecked()) { audio_pitch_action->AddSetting(c, maintain_pitch->isChecked()); @@ -382,7 +385,12 @@ void SpeedDialog::accept() { // set reverse setting if the user made a selection if (reverse->checkState() != Qt::PartiallyChecked && c->reversed() != reverse->isChecked()) { long new_clip_in = (c->media_length() - (c->length() + c->clip_in())); - c->move(ca, c->timeline_in(), c->timeline_out(), new_clip_in, c->track()); + c->track()->sequence()->MoveClip(c, + ca, + c->timeline_in(), + c->timeline_out(), + new_clip_in, + c->track()); c->set_clip_in(new_clip_in); reversed_action->AddSetting(c, reverse->isChecked()); } @@ -423,7 +431,7 @@ void SpeedDialog::accept() { // make changes for (int i=0;itrack() < 0) { + if (c->type() == Track::kTypeVideo) { set_speed(ca, c, frame_rate->value() / c->media_frame_rate(), ripple->isChecked(), earliest_point, longest_ripple); } else if (can_change_all) { set_speed(ca, c, frame_rate->value() / cached_fr, ripple->isChecked(), earliest_point, longest_ripple); @@ -438,16 +446,15 @@ void SpeedDialog::accept() { } if (ripple->isChecked()) { - ripple_clips(ca, clips_.at(0)->sequence, earliest_point, longest_ripple); + sequence->Ripple(ca, earliest_point, longest_ripple); } - sel_command->new_data = olive::ActiveSequence->selections; - ca->append(sel_command); + ca->append(new SetSelectionsCommand(sequence, old_selections, sequence->Selections())); ca->append(reversed_action); ca->append(audio_pitch_action); - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); update_ui(true); QDialog::accept(); diff --git a/effects/effect.cpp b/effects/effect.cpp index e142ad890..727bcff50 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -48,7 +48,7 @@ #include "global/path.h" #include "ui/mainwindow.h" #include "global/math.h" -#include "project/clipboard.h" +#include "global/clipboard.h" #include "global/config.h" #include "transition.h" #include "undo/undostack.h" @@ -412,7 +412,7 @@ void Effect::FieldChanged() { } void Effect::delete_self() { - olive::UndoStack.push(new EffectDeleteCommand(this)); + olive::undo_stack.push(new EffectDeleteCommand(this)); update_ui(true); } @@ -426,7 +426,7 @@ void Effect::move_up() { command->clip = parent_clip; command->from = index_of_effect; command->to = command->from - 1; - olive::UndoStack.push(command); + olive::undo_stack.push(command); panel_effect_controls->Reload(); panel_sequence_viewer->viewer_widget()->frame_update(); } @@ -441,7 +441,7 @@ void Effect::move_down() { command->clip = parent_clip; command->from = index_of_effect; command->to = command->from + 1; - olive::UndoStack.push(command); + olive::undo_stack.push(command); panel_effect_controls->Reload(); panel_sequence_viewer->viewer_widget()->frame_update(); } @@ -488,7 +488,7 @@ void Effect::load_from_file() { QFile file_handle(file); if (file_handle.open(QFile::ReadOnly)) { - olive::UndoStack.push(new SetEffectData(this, file_handle.readAll())); + olive::undo_stack.push(new SetEffectData(this, file_handle.readAll())); file_handle.close(); @@ -743,7 +743,7 @@ void Effect::open() { qWarning() << "Tried to open an effect that was already open"; close(); } - if (olive::CurrentRuntimeConfig.shaders_are_enabled && (Flags() & ShaderFlag)) { + if (olive::runtime_config.shaders_are_enabled && (Flags() & ShaderFlag)) { if (QOpenGLContext::currentContext() == nullptr) { qWarning() << "No current context to create a shader program for - will retry next repaint"; } else { @@ -1023,7 +1023,7 @@ void Effect::gizmo_move(EffectGizmo* gizmo, int x_movement, int y_movement, doub ca->append(gizmo_dragging_actions_.at(j)); } - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); gizmo_dragging_actions_.clear(); } @@ -1044,10 +1044,10 @@ void Effect::gizmo_world_to_screen(const QMatrix4x4& matrix, const QMatrix4x4& p projection, QRect(0, 0, - parent_clip->sequence->width, - parent_clip->sequence->height)); + parent_clip->track()->sequence()->width, + parent_clip->track()->sequence()->height)); - g->screen_pos[j] = QPoint(screen_pos.x(), parent_clip->sequence->height-screen_pos.y()); + g->screen_pos[j] = QPoint(screen_pos.x(), parent_clip->track()->sequence()->height-screen_pos.y()); } } diff --git a/effects/effectfield.cpp b/effects/effectfield.cpp index 61d6a0431..7446fbc5f 100644 --- a/effects/effectfield.cpp +++ b/effects/effectfield.cpp @@ -235,13 +235,13 @@ void EffectField::SetValueAt(double time, const QVariant &value) double EffectField::Now() { Clip* c = GetParentRow()->GetParentEffect()->parent_clip; - return playhead_to_clip_seconds(c, c->sequence->playhead); + return playhead_to_clip_seconds(c, c->track()->sequence()->playhead); } long EffectField::NowInFrames() { Clip* c = GetParentRow()->GetParentEffect()->parent_clip; - return playhead_to_clip_frame(c, c->sequence->playhead); + return playhead_to_clip_frame(c, c->track()->sequence()->playhead); } void EffectField::PrepareDataForKeyframing(bool enabled, ComboAction *ca) @@ -331,11 +331,11 @@ double EffectField::GetValidKeyframeHandlePosition(int key, bool post) { } double EffectField::FrameToSeconds(long frame) { - return (double(frame) / GetParentRow()->GetParentEffect()->parent_clip->sequence->frame_rate); + return (double(frame) / GetParentRow()->GetParentEffect()->parent_clip->track()->sequence()->frame_rate); } long EffectField::SecondsToFrame(double seconds) { - return qRound(seconds * GetParentRow()->GetParentEffect()->parent_clip->sequence->frame_rate); + return qRound(seconds * GetParentRow()->GetParentEffect()->parent_clip->track()->sequence()->frame_rate); } void EffectField::GetKeyframeData(double timecode, int &before, int &after, double &progress) { diff --git a/effects/effectloaders.cpp b/effects/effectloaders.cpp index 131db86f5..ebb840fbd 100644 --- a/effects/effectloaders.cpp +++ b/effects/effectloaders.cpp @@ -34,7 +34,7 @@ QMutex olive::effects_loaded; void load_internal_effects() { - if (!olive::CurrentRuntimeConfig.shaders_are_enabled) { + if (!olive::runtime_config.shaders_are_enabled) { qWarning() << "Shaders are disabled, some effects may be nonfunctional"; } @@ -44,7 +44,7 @@ void load_internal_effects() { em.path = ":/internalshaders"; em.type = EFFECT_TYPE_EFFECT; - em.subtype = EFFECT_TYPE_AUDIO; + em.subtype = Track::kTypeAudio; em.name = "Volume"; em.internal = EFFECT_INTERNAL_VOLUME; @@ -70,7 +70,7 @@ void load_internal_effects() { em.internal = EFFECT_INTERNAL_FILLLEFTRIGHT; olive::effects.append(em); - em.subtype = EFFECT_TYPE_VIDEO; + em.subtype = Track::kTypeVideo; em.name = "Transform"; em.category = "Distort"; @@ -115,7 +115,7 @@ void load_internal_effects() { em.internal = TRANSITION_INTERNAL_CROSSDISSOLVE; olive::effects.append(em); - em.subtype = EFFECT_TYPE_AUDIO; + em.subtype = Track::kTypeAudio; em.name = "Linear Fade"; em.internal = TRANSITION_INTERNAL_LINEARFADE; @@ -181,7 +181,7 @@ void load_shader_effects_worker(const QString& effects_path) { if (!effect_name.isEmpty()) { EffectMeta em; em.type = EFFECT_TYPE_EFFECT; - em.subtype = EFFECT_TYPE_VIDEO; + em.subtype = Track::kTypeVideo; em.name = effect_name; em.category = effect_cat; em.filename = file.fileName(); diff --git a/effects/effectrow.cpp b/effects/effectrow.cpp index f78a017ce..02305a7f8 100644 --- a/effects/effectrow.cpp +++ b/effects/effectrow.cpp @@ -93,7 +93,7 @@ void EffectRow::SetKeyframingEnabled(bool enabled) { Field(i)->PrepareDataForKeyframing(true, ca); } - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); update_ui(false); @@ -116,7 +116,7 @@ void EffectRow::SetKeyframingEnabled(bool enabled) { // Disable keyframing setting on this row ca->append(new SetIsKeyframing(this, false)); - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); update_ui(false); @@ -131,7 +131,7 @@ void EffectRow::SetKeyframingEnabled(bool enabled) { void EffectRow::GoToPreviousKeyframe() { long key = LONG_MIN; Clip* c = GetParentEffect()->parent_clip; - long sequence_playhead = c->sequence->playhead; + long sequence_playhead = c->track()->sequence()->playhead; // Used to convert clip frame number to sequence frame number long time_adjustment = c->timeline_in() - c->clip_in(); @@ -158,7 +158,7 @@ void EffectRow::GoToPreviousKeyframe() { void EffectRow::ToggleKeyframe() { Clip* c = GetParentEffect()->parent_clip; - long sequence_playhead = c->sequence->playhead; + long sequence_playhead = c->track()->sequence()->playhead; // Used to convert clip frame number to sequence frame number long time_adjustment = c->timeline_in() - c->clip_in(); @@ -222,7 +222,7 @@ void EffectRow::ToggleKeyframe() { } - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); update_ui(false); } @@ -233,7 +233,7 @@ void EffectRow::GoToNextKeyframe() { EffectField* f = Field(i); for (int j=0;jkeyframes.size();j++) { long comp = f->keyframes.at(j).time - c->clip_in() + c->timeline_in(); - if (comp > olive::ActiveSequence->playhead) { + if (comp > c->track()->sequence()->playhead) { key = qMin(comp, key); } } diff --git a/effects/fields/boolfield.cpp b/effects/fields/boolfield.cpp index f4db7d85d..13c958912 100644 --- a/effects/fields/boolfield.cpp +++ b/effects/fields/boolfield.cpp @@ -92,5 +92,5 @@ void BoolField::UpdateFromWidget(bool b) SetValueAt(Now(), b); kdc->SetNewKeyframes(); - olive::UndoStack.push(kdc); + olive::undo_stack.push(kdc); } diff --git a/effects/fields/colorfield.cpp b/effects/fields/colorfield.cpp index 66433db10..b294f9e78 100644 --- a/effects/fields/colorfield.cpp +++ b/effects/fields/colorfield.cpp @@ -67,5 +67,5 @@ void ColorField::UpdateFromWidget(const QColor& c) SetValueAt(Now(), c); kdc->SetNewKeyframes(); - olive::UndoStack.push(kdc); + olive::undo_stack.push(kdc); } diff --git a/effects/fields/combofield.cpp b/effects/fields/combofield.cpp index f5b803679..133e704d3 100644 --- a/effects/fields/combofield.cpp +++ b/effects/fields/combofield.cpp @@ -87,5 +87,5 @@ void ComboField::UpdateFromWidget(int index) SetValueAt(Now(), items_.at(index).data); kdc->SetNewKeyframes(); - olive::UndoStack.push(kdc); + olive::undo_stack.push(kdc); } diff --git a/effects/fields/doublefield.cpp b/effects/fields/doublefield.cpp index 9e0527a7d..58603d4b0 100644 --- a/effects/fields/doublefield.cpp +++ b/effects/fields/doublefield.cpp @@ -143,7 +143,7 @@ void DoubleField::UpdateFromWidget(double d) if (!ls->IsDragging() && kdc_ != nullptr) { kdc_->SetNewKeyframes(); - olive::UndoStack.push(kdc_); + olive::undo_stack.push(kdc_); kdc_ = nullptr; } diff --git a/effects/fields/filefield.cpp b/effects/fields/filefield.cpp index 2756fa8a5..b40eede59 100644 --- a/effects/fields/filefield.cpp +++ b/effects/fields/filefield.cpp @@ -62,5 +62,5 @@ void FileField::UpdateFromWidget(const QString &s) SetValueAt(Now(), s); kdc->SetNewKeyframes(); - olive::UndoStack.push(kdc); + olive::undo_stack.push(kdc); } diff --git a/effects/fields/fontfield.cpp b/effects/fields/fontfield.cpp index 9479fb60c..5876bdd78 100644 --- a/effects/fields/fontfield.cpp +++ b/effects/fields/fontfield.cpp @@ -89,5 +89,5 @@ void FontField::UpdateFromWidget(const QString& s) SetValueAt(Now(), s); kdc->SetNewKeyframes(); - olive::UndoStack.push(kdc); + olive::undo_stack.push(kdc); } diff --git a/effects/fields/stringfield.cpp b/effects/fields/stringfield.cpp index 89ea1f74b..57439473a 100644 --- a/effects/fields/stringfield.cpp +++ b/effects/fields/stringfield.cpp @@ -51,7 +51,7 @@ QWidget *StringField::CreateWidget(QWidget *existing) text_edit->setUndoRedoEnabled(true); // the "2" is because the height needs one extra pixel of padding on the top and the bottom - text_edit->setTextHeight(qCeil(text_edit->fontMetrics().lineSpacing()*olive::CurrentConfig.effect_textbox_lines + text_edit->setTextHeight(qCeil(text_edit->fontMetrics().lineSpacing()*olive::config.effect_textbox_lines + text_edit->document()->documentMargin() + text_edit->document()->documentMargin() + 2)); @@ -95,5 +95,5 @@ void StringField::UpdateFromWidget(const QString &s) SetValueAt(Now(), s); kdc->SetNewKeyframes(); - olive::UndoStack.push(kdc); + olive::undo_stack.push(kdc); } diff --git a/effects/internal/timecodeeffect.cpp b/effects/internal/timecodeeffect.cpp index 84276fc34..613b39383 100644 --- a/effects/internal/timecodeeffect.cpp +++ b/effects/internal/timecodeeffect.cpp @@ -88,14 +88,16 @@ TimecodeEffect::TimecodeEffect(Clip* c, const EffectMeta* em) : void TimecodeEffect::redraw(double timecode) { + Sequence* sequence = parent_clip->track()->sequence(); + if (tc_select->GetValueAt(timecode).toBool()) { - display_timecode = prepend_text->GetStringAt(timecode) + frame_to_timecode(olive::ActiveSequence->playhead, - olive::CurrentConfig.timecode_view, - olive::ActiveSequence->frame_rate); + display_timecode = prepend_text->GetStringAt(timecode) + frame_to_timecode(sequence->playhead, + olive::config.timecode_view, + sequence->frame_rate); } else { double media_rate = parent_clip->media_frame_rate(); display_timecode = prepend_text->GetStringAt(timecode) + frame_to_timecode(qRound(timecode * media_rate), - olive::CurrentConfig.timecode_view, + olive::config.timecode_view, media_rate); } img.fill(Qt::transparent); diff --git a/effects/internal/toneeffect.cpp b/effects/internal/toneeffect.cpp index b88cfbedc..f877083b6 100644 --- a/effects/internal/toneeffect.cpp +++ b/effects/internal/toneeffect.cpp @@ -55,7 +55,7 @@ void ToneEffect::process_audio(double timecode_start, double timecode_end, quint double timecode = timecode_start+(interval*i); qint16 left_tone_sample = qint16(qRound(qSin((2*M_PI*sinX*freq_val->GetDoubleAt(timecode)) - /parent_clip->sequence->audio_frequency) + /parent_clip->track()->sequence()->audio_frequency) *log_volume(amount_val->GetDoubleAt(timecode)*0.01)*INT16_MAX)); qint16 right_tone_sample = left_tone_sample; diff --git a/effects/internal/transformeffect.cpp b/effects/internal/transformeffect.cpp index 75d9ccc70..425c00bae 100644 --- a/effects/internal/transformeffect.cpp +++ b/effects/internal/transformeffect.cpp @@ -152,13 +152,13 @@ TransformEffect::TransformEffect(Clip* c, const EffectMeta* em) : Effect(c, em) } void TransformEffect::refresh() { - if (parent_clip != nullptr && parent_clip->sequence != nullptr) { + if (parent_clip != nullptr && parent_clip->track()->sequence() != nullptr) { - position_x->SetDefault(parent_clip->sequence->width/2); - position_y->SetDefault(parent_clip->sequence->height/2); + position_x->SetDefault(parent_clip->track()->sequence()->width/2); + position_y->SetDefault(parent_clip->track()->sequence()->height/2); - double x_percent_multipler = 200.0 / parent_clip->sequence->width; - double y_percent_multipler = 200.0 / parent_clip->sequence->height; + double x_percent_multipler = 200.0 / parent_clip->track()->sequence()->width; + double y_percent_multipler = 200.0 / parent_clip->track()->sequence()->height; top_left_gizmo->x_field_multi1 = -x_percent_multipler; top_left_gizmo->y_field_multi1 = -y_percent_multipler; @@ -190,8 +190,8 @@ void TransformEffect::toggle_uniform_scale(bool enabled) { void TransformEffect::process_coords(double timecode, GLTextureCoords& coords, int) { // position - coords.matrix.translate(position_x->GetDoubleAt(timecode)-(parent_clip->sequence->width/2), - position_y->GetDoubleAt(timecode)-(parent_clip->sequence->height/2), + coords.matrix.translate(position_x->GetDoubleAt(timecode)-(parent_clip->track()->sequence()->width/2), + position_y->GetDoubleAt(timecode)-(parent_clip->track()->sequence()->height/2), 0); // anchor point diff --git a/effects/keyframe.cpp b/effects/keyframe.cpp index 83f580207..870de3123 100644 --- a/effects/keyframe.cpp +++ b/effects/keyframe.cpp @@ -60,7 +60,7 @@ void delete_keyframes(QVector& selected_key_fields, QVector for (int i=0;iappend(new KeyframeDelete(fields.at(i), key_indices.at(i))); } - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); selected_keys.clear(); selected_key_fields.clear(); update_ui(false); diff --git a/effects/transition.cpp b/effects/transition.cpp index e7f3585e3..469aa59dd 100644 --- a/effects/transition.cpp +++ b/effects/transition.cpp @@ -24,8 +24,7 @@ #include "timeline/clip.h" #include "timeline/sequence.h" #include "global/debug.h" - -#include "project/clipboard.h" +#include "global/clipboard.h" #include "effects/internal/crossdissolvetransition.h" #include "effects/internal/linearfadetransition.h" @@ -50,8 +49,8 @@ Transition::Transition(Clip *c, Clip *s, const EffectMeta* em) : length_field->SetDefault(30); length_field->SetMinimum(1); length_field->SetDisplayType(LabelSlider::FrameNumber); - length_field->SetFrameRate(parent_clip->sequence == nullptr ? - parent_clip->cached_frame_rate() : parent_clip->sequence->frame_rate); + length_field->SetFrameRate(parent_clip->track()->sequence() == nullptr ? + parent_clip->cached_frame_rate() : parent_clip->track()->sequence()->frame_rate); connect(length_field, SIGNAL(Changed()), this, SLOT(UpdateMaximumLength())); } diff --git a/project/clipboard.cpp b/global/clipboard.cpp similarity index 86% rename from project/clipboard.cpp rename to global/clipboard.cpp index 9644dd840..c2157ba22 100644 --- a/project/clipboard.cpp +++ b/global/clipboard.cpp @@ -34,6 +34,16 @@ void Clipboard::Append(VoidPtr obj) clipboard_.append(obj); } +void Clipboard::Insert(int pos, VoidPtr obj) +{ + clipboard_.insert(pos, obj); +} + +void Clipboard::RemoveAt(int pos) +{ + clipboard_.removeAt(pos); +} + void Clipboard::Clear() { clipboard_.clear(); @@ -50,6 +60,16 @@ VoidPtr Clipboard::Get(int i) return clipboard_.at(i); } +void Clipboard::SetType(Clipboard::Type type) +{ + if (type == type_) { + return; + } + + Clear(); + type_ = type; +} + bool Clipboard::IsEmpty() { return clipboard_.isEmpty(); diff --git a/project/clipboard.h b/global/clipboard.h similarity index 95% rename from project/clipboard.h rename to global/clipboard.h index 6cbdb0992..9a2366256 100644 --- a/project/clipboard.h +++ b/global/clipboard.h @@ -36,6 +36,8 @@ public: Clipboard(); void Append(VoidPtr obj); + void Insert(int pos, VoidPtr obj); + void RemoveAt(int pos); void Clear(); int Count(); VoidPtr Get(int i); diff --git a/global/config.cpp b/global/config.cpp index 799abe529..cd22f52a0 100644 --- a/global/config.cpp +++ b/global/config.cpp @@ -29,12 +29,11 @@ #include "debug.h" -Config olive::CurrentConfig; -RuntimeConfig olive::CurrentRuntimeConfig; +Config olive::config; +RuntimeConfig olive::runtime_config; Config::Config() - : show_track_lines(true), - scroll_zooms(false), + : scroll_zooms(false), edit_tool_selects_links(false), edit_tool_also_seeks(false), select_also_seeks(false), @@ -94,10 +93,7 @@ void Config::load(QString path) { while (!stream.atEnd()) { stream.readNext(); if (stream.isStartElement()) { - if (stream.name() == "ShowTrackLines") { - stream.readNext(); - show_track_lines = (stream.text() == "1"); - } else if (stream.name() == "ScrollZooms") { + if (stream.name() == "ScrollZooms") { stream.readNext(); scroll_zooms = (stream.text() == "1"); } else if (stream.name() == "InvertTimelineScrollAxes") { @@ -295,7 +291,6 @@ void Config::save(QString path) { stream.writeStartElement("Configuration"); // configuration stream.writeTextElement("Version", QString::number(olive::kSaveVersion)); - stream.writeTextElement("ShowTrackLines", QString::number(show_track_lines)); stream.writeTextElement("ScrollZooms", QString::number(scroll_zooms)); stream.writeTextElement("InvertTimelineScrollAxes", QString::number(invert_timeline_scroll_axes)); stream.writeTextElement("EditToolSelectsLinks", QString::number(edit_tool_selects_links)); @@ -320,7 +315,7 @@ void Config::save(QString path) { stream.writeTextElement("HoverFocus", QString::number(hover_focus)); stream.writeTextElement("ProjectViewType", QString::number(project_view_type)); stream.writeTextElement("SetNameWithMarker", QString::number(set_name_with_marker)); - stream.writeTextElement("ShowProjectToolbar", QString::number(panel_project->IsToolbarVisible())); + stream.writeTextElement("ShowProjectToolbar", QString::number(panel_project.first()->IsToolbarVisible())); stream.writeTextElement("PreviousFrameQueueSize", QString::number(previous_queue_size)); stream.writeTextElement("PreviousFrameQueueType", QString::number(previous_queue_type)); stream.writeTextElement("UpcomingFrameQueueSize", QString::number(upcoming_queue_size)); diff --git a/global/config.h b/global/config.h index 3b7bbf2f6..0291a5e3a 100644 --- a/global/config.h +++ b/global/config.h @@ -24,6 +24,7 @@ #include #include "ui/styling.h" +#include "timeline/timelinetools.h" namespace olive { /** @@ -159,13 +160,6 @@ struct Config { */ Config(); - /** - * @brief Show track lines - * - * **TRUE** if the Timeline should show lines between tracks. - */ - bool show_track_lines; - /** * @brief The scroll wheel zooms rather than scrolls * @@ -674,8 +668,8 @@ struct RuntimeConfig { }; namespace olive { -extern Config CurrentConfig; -extern RuntimeConfig CurrentRuntimeConfig; +extern Config config; +extern RuntimeConfig runtime_config; } #endif // CONFIG_H diff --git a/global/global.cpp b/global/global.cpp index 097549e31..4c0854142 100644 --- a/global/global.cpp +++ b/global/global.cpp @@ -30,7 +30,8 @@ #include "panels/panels.h" #include "global/path.h" #include "global/config.h" -#include "project/clipboard.h" +#include "global/timing.h" +#include "global/clipboard.h" #include "rendering/audio.h" #include "dialogs/demonotice.h" #include "dialogs/preferencesdialog.h" @@ -147,12 +148,12 @@ QString OliveGlobal::get_recent_project_list_file() { } void OliveGlobal::load_translation_from_config() { - QString language_file = olive::CurrentRuntimeConfig.external_translation_file.isEmpty() ? - olive::CurrentConfig.language_file : - olive::CurrentRuntimeConfig.external_translation_file; + QString language_file = olive::runtime_config.external_translation_file.isEmpty() ? + olive::config.language_file : + olive::runtime_config.external_translation_file; // clear runtime language file so if the user sets a different language, we won't load it next time - olive::CurrentRuntimeConfig.external_translation_file.clear(); + olive::runtime_config.external_translation_file.clear(); // remove current translation if there is one QApplication::removeTranslator(translator.get()); @@ -195,7 +196,7 @@ void OliveGlobal::add_recent_project(const QString &url) } if (!found) { recent_projects.prepend(url); - if (recent_projects.size() > olive::CurrentConfig.maximum_recent_projects) { + if (recent_projects.size() > olive::config.maximum_recent_projects) { recent_projects.removeLast(); } } @@ -229,6 +230,11 @@ const QString &OliveGlobal::recent_project(int index) return recent_projects.at(index); } +const QString &OliveGlobal::get_autorecovery_filename() +{ + return autorecovery_filename; +} + void OliveGlobal::LoadProject(const QString &fn, bool autorecovery) { // QSortFilterProxyModels are not thread-safe, and as we'll be loading in another thread, leaving it connected @@ -265,7 +271,7 @@ void OliveGlobal::ClearProject() panel_effect_controls->Clear(true); // clear existing project - set_sequence(nullptr); + Timeline::CloseAll(); panel_footage_viewer->set_media(nullptr); // delete sequences first because it's important to close all the clips before deleting the media @@ -278,7 +284,7 @@ void OliveGlobal::ClearProject() olive::project_model.clear(); // clear undo stack - olive::UndoStack.clear(); + olive::undo_stack.clear(); // empty current project filename update_project_filename(""); @@ -308,36 +314,42 @@ void OliveGlobal::save_recent_projects() } } -void OliveGlobal::PasteInternal(Sequence *s) +void OliveGlobal::PasteInternal(Sequence *s, bool insert) { + if (s == nullptr) { + return; + } + if (!olive::clipboard.IsEmpty()) { if (olive::clipboard.type() == Clipboard::CLIPBOARD_TYPE_CLIP) { ComboAction* ca = new ComboAction(); // create copies and delete areas that we'll be pasting to QVector delete_areas; + QVector original_clips; QVector pasted_clips; long paste_start = LONG_MAX; long paste_end = LONG_MIN; - for (int i=0;i(olive::clipboard.at(i)); + for (int i=0;i(olive::clipboard.Get(i)); // create copy of clip and offset by playhead - ClipPtr cc = c->copy(olive::ActiveSequence.get()); + ClipPtr cc = c->copy(s->GetTrackList(c->track()->type())->TrackAt(c->track()->Index())); // convert frame rates - cc->set_timeline_in(rescale_frame_number(cc->timeline_in(), c->cached_frame_rate(), olive::ActiveSequence->frame_rate)); - cc->set_timeline_out(rescale_frame_number(cc->timeline_out(), c->cached_frame_rate(), olive::ActiveSequence->frame_rate)); - cc->set_clip_in(rescale_frame_number(cc->clip_in(), c->cached_frame_rate(), olive::ActiveSequence->frame_rate)); + cc->set_timeline_in(rescale_frame_number(cc->timeline_in(), c->cached_frame_rate(), s->frame_rate)); + cc->set_timeline_out(rescale_frame_number(cc->timeline_out(), c->cached_frame_rate(), s->frame_rate)); + cc->set_clip_in(rescale_frame_number(cc->clip_in(), c->cached_frame_rate(), s->frame_rate)); - cc->set_timeline_in(cc->timeline_in() + olive::ActiveSequence->playhead); - cc->set_timeline_out(cc->timeline_out() + olive::ActiveSequence->playhead); + cc->set_timeline_in(cc->timeline_in() + s->playhead); + cc->set_timeline_out(cc->timeline_out() + s->playhead); cc->set_track(c->track()); paste_start = qMin(paste_start, cc->timeline_in()); paste_end = qMax(paste_end, cc->timeline_out()); + original_clips.append(c.get()); pasted_clips.append(cc); if (!insert) { @@ -345,52 +357,40 @@ void OliveGlobal::PasteInternal(Sequence *s) } } if (insert) { - split_all_clips_at_point(ca, olive::ActiveSequence->playhead); - ripple_clips(ca, olive::ActiveSequence.get(), paste_start, paste_end - paste_start); + s->SplitAllClipsAtPoint(ca, s->playhead); + s->Ripple(ca, paste_start, paste_end - paste_start); } else { - delete_areas_and_relink(ca, delete_areas, false); + s->DeleteAreas(ca, delete_areas, false); } // correct linked clips - for (int i=0;i(clipboard.at(i)); + olive::timeline::RelinkClips(original_clips, pasted_clips); - for (int j=0;jlinked.size();j++) { - for (int k=0;k(clipboard.at(k)); - if (comp->load_id == oc->linked.at(j)) { - pasted_clips.at(i)->linked.append(k); - } - } - } - } + ca->append(new AddClipCommand(pasted_clips)); - ca->append(new AddClipCommand(olive::ActiveSequence.get(), pasted_clips)); - - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); update_ui(true); - if (olive::CurrentConfig.paste_seeks) { + if (olive::config.paste_seeks) { panel_sequence_viewer->seek(paste_end); } - } else if (clipboard_type == CLIPBOARD_TYPE_EFFECT) { + } else if (olive::clipboard.type() == Clipboard::CLIPBOARD_TYPE_EFFECT) { ComboAction* ca = new ComboAction(); bool replace = false; bool skip = false; bool ask_conflict = true; - QVector selected_clips = olive::ActiveSequence->SelectedClips(); + QVector selected_clips = s->SelectedClips(); for (int i=0;i(clipboard.at(j)); - if ((c->track() < 0) == (e->meta->subtype == EFFECT_TYPE_VIDEO)) { + for (int j=0;j(olive::clipboard.Get(j)); + if (c->type() == e->meta->subtype) { int found = -1; if (ask_conflict) { replace = false; @@ -403,7 +403,7 @@ void OliveGlobal::PasteInternal(Sequence *s) } } if (found >= 0 && ask_conflict) { - QMessageBox box(this); + QMessageBox box(olive::MainWindow); box.setWindowTitle(tr("Effect already exists")); box.setText(tr("Clip '%1' already contains a '%2' effect. " "Would you like to replace it with the pasted one or add it as a separate effect?") @@ -441,7 +441,7 @@ void OliveGlobal::PasteInternal(Sequence *s) } if (ca->hasActions()) { ca->appendPost(new ReloadEffectsCommand()); - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); } else { delete ca; } @@ -528,7 +528,7 @@ bool OliveGlobal::can_close_project() { return true; } -void OliveGlobal::new_sequence() +void OliveGlobal::open_new_sequence_dialog() { NewSequenceDialog nsd(olive::MainWindow); nsd.set_sequence_name(olive::project_model.GetNextSequenceName()); @@ -557,7 +557,7 @@ void OliveGlobal::open_import_dialog() void OliveGlobal::open_export_dialog() { if (CheckForActiveSequence()) { - ExportDialog e(olive::MainWindow); + ExportDialog e(olive::MainWindow, Timeline::GetTopSequence().get()); e.exec(); } } @@ -609,15 +609,10 @@ void OliveGlobal::open_preferences() { pd.exec(); } -void OliveGlobal::set_sequence(SequencePtr s) +void OliveGlobal::PrimarySequenceChanged() { panel_graph_editor->set_row(nullptr); panel_effect_controls->Clear(true); - - olive::ActiveSequence = s; - panel_sequence_viewer->set_main_sequence(); - panel_timeline->update_sequence(); - panel_timeline->setFocus(); } void OliveGlobal::clear_recent_projects() @@ -630,12 +625,12 @@ void OliveGlobal::OpenProjectWorker(QString fn, bool autorecovery) { ClearProject(); update_project_filename(fn); LoadProject(fn, autorecovery); - olive::UndoStack.clear(); + olive::undo_stack.clear(); } bool OliveGlobal::CheckForActiveSequence(bool show_msg) { - if (olive::ActiveSequence == nullptr) { + if (Timeline::GetTopSequence() == nullptr) { if (show_msg) { QMessageBox::information(olive::MainWindow, @@ -651,30 +646,26 @@ bool OliveGlobal::CheckForActiveSequence(bool show_msg) void OliveGlobal::undo() { // workaround to prevent crash (and also users should never need to do this) - if (!panel_timeline->importing) { - olive::UndoStack.undo(); + if (!Timeline::IsImporting()) { + olive::undo_stack.undo(); update_ui(true); } } void OliveGlobal::redo() { // workaround to prevent crash (and also users should never need to do this) - if (!panel_timeline->importing) { - olive::UndoStack.redo(); + if (!Timeline::IsImporting()) { + olive::undo_stack.redo(); update_ui(true); } } void OliveGlobal::paste() { - if (olive::ActiveSequence != nullptr) { - panel_timeline->paste(false); - } + PasteInternal(Timeline::GetTopSequence().get(), false); } void OliveGlobal::paste_insert() { - if (olive::ActiveSequence != nullptr) { - panel_timeline->paste(true); - } + PasteInternal(Timeline::GetTopSequence().get(), true); } void OliveGlobal::open_about_dialog() { @@ -687,9 +678,9 @@ void OliveGlobal::open_debug_log() { } void OliveGlobal::open_speed_dialog() { - if (olive::ActiveSequence != nullptr) { + if (Timeline::GetTopSequence() != nullptr) { - QVector selected_clips = olive::ActiveSequence->SelectedClips(); + QVector selected_clips = Timeline::GetTopSequence()->SelectedClips(); if (!selected_clips.isEmpty()) { SpeedDialog s(olive::MainWindow, selected_clips); @@ -701,7 +692,7 @@ void OliveGlobal::open_speed_dialog() { void OliveGlobal::open_autocut_silence_dialog() { if (CheckForActiveSequence()) { - QVector selected_clips = olive::ActiveSequence->SelectedClipIndexes(); + QVector selected_clips = Timeline::GetTopSequence()->SelectedClips(); if (selected_clips.isEmpty()) { QMessageBox::critical(olive::MainWindow, @@ -717,7 +708,7 @@ void OliveGlobal::open_autocut_silence_dialog() { } void OliveGlobal::clear_undo_stack() { - olive::UndoStack.clear(); + olive::undo_stack.clear(); } void OliveGlobal::open_action_search() { diff --git a/global/global.h b/global/global.h index 5543fa0ef..a8a0ee47f 100644 --- a/global/global.h +++ b/global/global.h @@ -204,6 +204,18 @@ public: */ const QString& get_autorecovery_filename(); + /** + * @brief Returns whether a Sequence is currently active or not, and optionally displays a messagebox if not + * + * Checks whether a Sequence is active and can display a messagebox if not to inform users to make one active in + * order to perform said action. + * + * @return + * + * TRUE if there is an active Sequence, FALSE if not. + */ + bool CheckForActiveSequence(bool show_msg = true); + public slots: /** * @brief Undo user's last action @@ -313,7 +325,7 @@ public slots: /** * @brief Opens the NewSequenceDialog to create a new Sequence */ - void new_sequence(); + void open_new_sequence_dialog(); /** * @brief Open a file dialog for importing files into the project @@ -378,19 +390,6 @@ public slots: */ void open_preferences(); - /** - * @brief Set the current active Sequence - * - * Call this to change the active Sequence (e.g. when the user double clicks a Sequence in the Project panel). - * This will affect panel_timeline, panel_sequence_viewer, and panel_effect_controls and can then be retrieved - * using olive::ActiveSequence. - * - * @param s - * - * The Sequence to set as the active Sequence. - */ - void set_sequence(SequencePtr s); - /** * @brief Clear the recent projects list * @@ -398,6 +397,14 @@ public slots: */ void clear_recent_projects(); + /** + * @brief Slot for when the primary sequence has changed. + * + * Usually by opening a sequence or bringing a corresponding + * Timeline widget on top. + */ + void PrimarySequenceChanged(); + private: /** * @brief Internal function to handle loading a project from file @@ -417,18 +424,6 @@ private: */ void OpenProjectWorker(QString fn, bool autorecovery); - /** - * @brief Returns whether a Sequence is currently active or not, and optionally displays a messagebox if not - * - * Checks whether a Sequence is active and can display a messagebox if not to inform users to make one active in - * order to perform said action. - * - * @return - * - * TRUE if there is an active Sequence, FALSE if not. - */ - bool CheckForActiveSequence(bool show_msg = true); - /** * @brief Create a LoadDialog and start a LoadThread to load data from a project * @@ -475,7 +470,7 @@ private: /** * @brief Internal pasting function */ - void PasteInternal(Sequence* s); + void PasteInternal(Sequence* s, bool insert); /** * @brief File filter used for any file dialogs relating to Olive project files. diff --git a/global/math.h b/global/math.h index 9d0c9a9f5..721e4453e 100644 --- a/global/math.h +++ b/global/math.h @@ -41,4 +41,8 @@ QRect fit_size_into_rect(const QRect& r, int width, int height); double amplitude_to_db(double amplitude); double db_to_amplitude(double db); +// frame <-> pixel conversion functions +int getScreenPointFromFrame(double zoom, long frame); +long getFrameFromScreenPoint(double zoom, int x); + #endif // MATH_H diff --git a/global/timing.cpp b/global/timing.cpp index b14315734..f87cacb70 100644 --- a/global/timing.cpp +++ b/global/timing.cpp @@ -5,7 +5,7 @@ #include "global/config.h" double get_timecode(Clip* c, long playhead) { - return double(playhead_to_clip_frame(c, playhead))/c->sequence->frame_rate; + return double(playhead_to_clip_frame(c, playhead))/c->track()->sequence()->frame_rate; } long rescale_frame_number(long framenumber, double source_frame_rate, double target_frame_rate) { @@ -24,7 +24,7 @@ double playhead_to_clip_seconds(Clip* c, long playhead) { clip_frame = c->media_length() - clip_frame - 1; } - double secs = (double(clip_frame)/c->sequence->frame_rate)*c->speed().value; + double secs = (double(clip_frame)/c->track()->sequence()->frame_rate)*c->speed().value; if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) { secs *= c->media()->to_footage()->speed; } diff --git a/main.cpp b/main.cpp index 395ac1813..e387d92e0 100644 --- a/main.cpp +++ b/main.cpp @@ -70,13 +70,13 @@ int main(int argc, char *argv[]) { } else if (!strcmp(argv[i], "--fullscreen") || !strcmp(argv[i], "-f")) { launch_fullscreen = true; } else if (!strcmp(argv[i], "--disable-shaders")) { - olive::CurrentRuntimeConfig.shaders_are_enabled = false; + olive::runtime_config.shaders_are_enabled = false; } else if (!strcmp(argv[i], "--no-debug")) { use_internal_logger = false; } else if (!strcmp(argv[i], "--translation")) { if (i + 1 < argc && argv[i + 1][0] != '-') { // load translation file - olive::CurrentRuntimeConfig.external_translation_file = argv[i + 1]; + olive::runtime_config.external_translation_file = argv[i + 1]; i++; } else { diff --git a/olive.pro b/olive.pro index 40be13dd2..a58ad5db1 100644 --- a/olive.pro +++ b/olive.pro @@ -75,7 +75,6 @@ SOURCES += \ dialogs/preferencesdialog.cpp \ ui/audiomonitor.cpp \ undo/undo.cpp \ - ui/scrollarea.cpp \ ui/comboboxex.cpp \ ui/colorbutton.cpp \ dialogs/replaceclipmediadialog.cpp \ @@ -108,7 +107,6 @@ SOURCES += \ effects/effect.cpp \ effects/effectrow.cpp \ effects/effectgizmo.cpp \ - project/clipboard.cpp \ ui/resizablescrollbar.cpp \ ui/sourceiconview.cpp \ project/sourcescommon.cpp \ @@ -182,7 +180,10 @@ SOURCES += \ timeline/timelineshared.cpp \ ui/timelineview.cpp \ ui/timelinelabel.cpp \ - timeline/selection.cpp + timeline/selection.cpp \ + global/clipboard.cpp \ + timeline/timelinetools.cpp \ + timeline/ghost.cpp HEADERS += \ ui/mainwindow.h \ @@ -204,14 +205,12 @@ HEADERS += \ ui/collapsiblewidget.h \ panels/panels.h \ rendering/exportthread.h \ - ui/timelinetools.h \ ui/timelineheader.h \ project/previewgenerator.h \ ui/labelslider.h \ dialogs/preferencesdialog.h \ ui/audiomonitor.h \ undo/undo.h \ - ui/scrollarea.h \ ui/comboboxex.h \ ui/colorbutton.h \ dialogs/replaceclipmediadialog.h \ @@ -246,7 +245,6 @@ HEADERS += \ effects/effectrow.h \ effects/internal/cubetransition.h \ effects/effectgizmo.h \ - project/clipboard.h \ ui/resizablescrollbar.h \ ui/sourceiconview.h \ project/sourcescommon.h \ @@ -323,7 +321,9 @@ HEADERS += \ ui/timelinearea.h \ timeline/timelineshared.h \ ui/timelineview.h \ - ui/timelinelabel.h + ui/timelinelabel.h \ + global/clipboard.h \ + timeline/timelinetools.h FORMS += diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index 279ddc3c9..2321572a2 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -47,7 +47,7 @@ #include "ui/viewerwidget.h" #include "ui/menuhelper.h" #include "ui/icons.h" -#include "project/clipboard.h" +#include "global/clipboard.h" #include "global/config.h" #include "ui/timelineheader.h" #include "ui/keyframeview.h" @@ -89,7 +89,10 @@ EffectControls::~EffectControls() void EffectControls::set_zoom(bool in) { zoom *= (in) ? 2 : 0.5; update_keyframes(); - scroll_to_frame(olive::ActiveSequence->playhead); + + if (!selected_clips_.isEmpty()) { + scroll_to_frame(selected_clips_.first()->track()->sequence()->playhead); + } } void EffectControls::menu_select(QAction* q) { @@ -104,21 +107,21 @@ void EffectControls::menu_select(QAction* q) { nullptr, nullptr, meta, - olive::CurrentConfig.default_transition_length)); + olive::config.default_transition_length)); } if (c->closing_transition == nullptr) { ca->append(new AddTransitionCommand(nullptr, c, nullptr, meta, - olive::CurrentConfig.default_transition_length)); + olive::config.default_transition_length)); } } else { ca->append(new AddEffectCommand(c, nullptr, meta)); } } } - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); if (effect_menu_type == EFFECT_TYPE_TRANSITION) { update_ui(true); } else { @@ -175,7 +178,7 @@ void EffectControls::copy(bool del) { if (del) { if (ca->hasActions()) { - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); } else { delete ca; } @@ -587,7 +590,7 @@ void EffectControls::DeleteSelectedEffects() { } if (ca->hasActions()) { - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); update_ui(true); } else { delete ca; @@ -620,11 +623,13 @@ void EffectControls::SetClips() { Clear(true); - if (olive::ActiveSequence == nullptr) { + Sequence* top_sequence = Timeline::GetTopSequence().get(); + + if (top_sequence == nullptr) { selected_clips_.clear(); } else { // replace clip vector - selected_clips_ = olive::ActiveSequence->SelectedClips(false); + selected_clips_ = top_sequence->SelectedClips(false); Load(); } diff --git a/panels/grapheditor.cpp b/panels/grapheditor.cpp index dd27a705f..e664b8aba 100644 --- a/panels/grapheditor.cpp +++ b/panels/grapheditor.cpp @@ -27,7 +27,7 @@ #include "ui/keyframenavigator.h" #include "ui/timelineheader.h" -#include "ui/timelinetools.h" +#include "timeline/timelinetools.h" #include "ui/labelslider.h" #include "ui/graphview.h" #include "effects/effect.h" diff --git a/panels/panels.cpp b/panels/panels.cpp index f8ec065cd..6fb3455f8 100644 --- a/panels/panels.cpp +++ b/panels/panels.cpp @@ -25,6 +25,7 @@ #include "effects/transition.h" #include "global/config.h" #include "global/debug.h" +#include "global/math.h" #include #include @@ -33,7 +34,7 @@ QVector panel_project; EffectControls* panel_effect_controls = nullptr; Viewer* panel_sequence_viewer = nullptr; Viewer* panel_footage_viewer = nullptr; -Timeline* panel_timeline = nullptr; +QVector panel_timeline; GraphEditor* panel_graph_editor = nullptr; void update_ui(bool modified) { @@ -41,14 +42,16 @@ void update_ui(bool modified) { panel_effect_controls->SetClips(); } panel_effect_controls->update_keyframes(); - panel_timeline->repaint_timeline(); + for (int i=0;irepaint_timeline(); + } panel_sequence_viewer->update_viewer(); panel_graph_editor->update_panel(); } QDockWidget *get_focused_panel(bool force_hover) { QDockWidget* w = nullptr; - if (olive::CurrentConfig.hover_focus || force_hover) { + if (olive::config.hover_focus || force_hover) { for (int i=0;iunderMouse()) { w = olive::panels.at(i); @@ -78,8 +81,9 @@ void alloc_panels(QWidget* parent) { panel_project.append(first_project_panel); panel_effect_controls = new EffectControls(parent); panel_effect_controls->setObjectName("fx_controls"); - panel_timeline = new Timeline(parent); - panel_timeline->setObjectName("timeline"); + Timeline* first_timeline_panel = new Timeline(parent); + first_timeline_panel->setObjectName("timeline"); + panel_timeline.append(first_timeline_panel); panel_graph_editor = new GraphEditor(parent); panel_graph_editor->setObjectName("graph_editor"); } @@ -89,12 +93,19 @@ void free_panels() { panel_sequence_viewer = nullptr; delete panel_footage_viewer; panel_footage_viewer = nullptr; - delete panel_project; - panel_project = nullptr; + + for (int i=0;i panel_project; extern EffectControls* panel_effect_controls; extern Viewer* panel_sequence_viewer; extern Viewer* panel_footage_viewer; -extern Timeline* panel_timeline; +extern QVector panel_timeline; extern GraphEditor* panel_graph_editor; void update_ui(bool modified); diff --git a/panels/project.cpp b/panels/project.cpp index e58f6ad74..289a1e7be 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -54,7 +54,7 @@ extern "C" { #include "dialogs/mediapropertiesdialog.h" #include "dialogs/newsequencedialog.h" #include "dialogs/loaddialog.h" -#include "project/clipboard.h" +#include "global/clipboard.h" #include "ui/sourcetable.h" #include "ui/sourceiconview.h" #include "ui/icons.h" @@ -83,7 +83,7 @@ Project::Project(QWidget *parent) : // optional toolbar toolbar_widget = new QWidget(); - toolbar_widget->setVisible(olive::CurrentConfig.show_project_toolbar); + toolbar_widget->setVisible(olive::config.show_project_toolbar); toolbar_widget->setObjectName("project_toolbar"); QHBoxLayout* toolbar = new QHBoxLayout(toolbar_widget); @@ -233,7 +233,7 @@ void Project::duplicate_selected() { } } if (duped) { - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); } else { delete ca; } @@ -250,7 +250,9 @@ void Project::replace_selected_file() { } void Project::replace_clip_media() { - if (olive::ActiveSequence == nullptr) { + Sequence* top_sequence = Timeline::GetTopSequence().get(); + + if (top_sequence == nullptr) { QMessageBox::critical(this, tr("No active sequence"), tr("No sequence is active, please open the sequence you want to replace clips from."), @@ -259,7 +261,7 @@ void Project::replace_clip_media() { QModelIndexList selected_items = get_current_selected(); if (selected_items.size() == 1) { Media* item = item_to_media(selected_items.at(0)); - if (item->get_type() == MEDIA_TYPE_SEQUENCE && olive::ActiveSequence == item->to_sequence()) { + if (item->get_type() == MEDIA_TYPE_SEQUENCE && top_sequence == item->to_sequence().get()) { QMessageBox::critical(this, tr("Active sequence selected"), tr("You cannot insert a sequence into itself, so no clips of this media would be in this sequence."), @@ -299,7 +301,7 @@ void Project::open_properties() { item->get_name()); if (!new_name.isEmpty()) { MediaRename* mr = new MediaRename(item, new_name); - olive::UndoStack.push(mr); + olive::undo_stack.push(mr); } } } @@ -308,10 +310,10 @@ void Project::open_properties() { void Project::new_folder() { MediaPtr m = olive::project::CreateFolder(nullptr); - olive::UndoStack.push(new AddMediaCommand(m, get_selected_folder())); + olive::undo_stack.push(new AddMediaCommand(m, get_selected_folder())); QModelIndex index = olive::project_model.create_index(m->row(), 0, m.get()); - switch (olive::CurrentConfig.project_view_type) { + switch (olive::config.project_view_type) { case olive::PROJECT_VIEW_TREE: tree_view->edit(sorter.mapFromSource(index)); break; @@ -451,8 +453,9 @@ void Project::delete_selected_media() { panel_graph_editor->set_row(nullptr); panel_effect_controls->Clear(true); - if (olive::ActiveSequence != nullptr) { - olive::ActiveSequence->ClearSelections(); + Sequence* top_sequence = Timeline::GetTopSequence().get(); + if (top_sequence != nullptr) { + top_sequence->ClearSelections(); } // remove media and parents @@ -474,9 +477,7 @@ void Project::delete_selected_media() { Sequence* s = items.at(i)->to_sequence().get(); - if (s == olive::ActiveSequence.get()) { - ca->append(new ChangeSequenceAction(nullptr)); - } + Timeline::CloseSequence(s); if (s == panel_footage_viewer->seq.get()) { panel_footage_viewer->set_media(nullptr); @@ -487,7 +488,7 @@ void Project::delete_selected_media() { } } } - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); // redraw clips if (redraw) { @@ -527,7 +528,7 @@ bool Project::reveal_media(Media *media, QModelIndex parent) { // retrieve its parent item QModelIndex hierarchy = sorted_index.parent(); - if (olive::CurrentConfig.project_view_type == olive::PROJECT_VIEW_TREE) { + if (olive::config.project_view_type == olive::PROJECT_VIEW_TREE) { // if we're in tree view, expand every folder in the hierarchy containing the media while (hierarchy.isValid()) { @@ -542,7 +543,7 @@ bool Project::reveal_media(Media *media, QModelIndex parent) { ); tree_view->selectionModel()->select(row_select, QItemSelectionModel::Select); - } else if (olive::CurrentConfig.project_view_type == olive::PROJECT_VIEW_ICON) { + } else if (olive::config.project_view_type == olive::PROJECT_VIEW_ICON) { // if we're in icon view, we just "browse" to the parent folder icon_view->setRootIndex(hierarchy); @@ -563,55 +564,42 @@ bool Project::reveal_media(Media *media, QModelIndex parent) { } void Project::delete_clips_using_selected_media() { - if (olive::ActiveSequence == nullptr) { + Sequence* top_sequence = Timeline::GetTopSequence().get(); + + if (top_sequence == nullptr) { QMessageBox::critical(this, tr("No active sequence"), tr("No sequence is active, please open the sequence you want to delete clips from."), QMessageBox::Ok); } else { - ComboAction* ca = new ComboAction(); - bool deleted = false; - QModelIndexList items = get_current_selected(); - QVector sequence_clips = olive::ActiveSequence->GetAllClips(); - for (int i=0;imedia() == m) { - ca->append(new DeleteClipAction(c)); - deleted = true; - } - } - } - for (int j=0;j media; + + media.resize(items.size()); + + for (int i=0;iDeleteClipsUsingMedia(media); + } } void Project::update_view_type() { - tree_view->setVisible(olive::CurrentConfig.project_view_type == olive::PROJECT_VIEW_TREE); - icon_view_container->setVisible(olive::CurrentConfig.project_view_type == olive::PROJECT_VIEW_ICON - || olive::CurrentConfig.project_view_type == olive::PROJECT_VIEW_LIST); + tree_view->setVisible(olive::config.project_view_type == olive::PROJECT_VIEW_TREE); + icon_view_container->setVisible(olive::config.project_view_type == olive::PROJECT_VIEW_ICON + || olive::config.project_view_type == olive::PROJECT_VIEW_LIST); - switch (olive::CurrentConfig.project_view_type) { + switch (olive::config.project_view_type) { case olive::PROJECT_VIEW_TREE: sources_common.view = tree_view; break; case olive::PROJECT_VIEW_ICON: case olive::PROJECT_VIEW_LIST: - icon_view->setViewMode(olive::CurrentConfig.project_view_type == olive::PROJECT_VIEW_ICON ? + icon_view->setViewMode(olive::config.project_view_type == olive::PROJECT_VIEW_ICON ? QListView::IconMode : QListView::ListMode); // update list/grid size since they use this value slightly differently @@ -623,18 +611,18 @@ void Project::update_view_type() { } void Project::set_icon_view() { - olive::CurrentConfig.project_view_type = olive::PROJECT_VIEW_ICON; + olive::config.project_view_type = olive::PROJECT_VIEW_ICON; update_view_type(); } void Project::set_list_view() { - olive::CurrentConfig.project_view_type = olive::PROJECT_VIEW_LIST; + olive::config.project_view_type = olive::PROJECT_VIEW_LIST; update_view_type(); } void Project::set_tree_view() { - olive::CurrentConfig.project_view_type = olive::PROJECT_VIEW_TREE; + olive::config.project_view_type = olive::PROJECT_VIEW_TREE; update_view_type(); } @@ -663,7 +651,7 @@ void Project::make_new_menu() { } QModelIndexList Project::get_current_selected() { - if (olive::CurrentConfig.project_view_type == olive::PROJECT_VIEW_TREE) { + if (olive::config.project_view_type == olive::PROJECT_VIEW_TREE) { return tree_view->selectionModel()->selectedRows(); } return icon_view->selectionModel()->selectedIndexes(); diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 966408348..dbfbf1dc6 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -45,7 +45,8 @@ #include "rendering/cacher.h" #include "rendering/renderfunctions.h" #include "global/config.h" -#include "project/clipboard.h" +#include "global/clipboard.h" +#include "global/math.h" #include "ui/timelineheader.h" #include "ui/resizablescrollbar.h" #include "ui/audiomonitor.h" @@ -60,20 +61,17 @@ Timeline::Timeline(QWidget *parent) : Panel(parent), cursor_frame(0), - cursor_track(0), + cursor_track(nullptr), zoom(1.0), zoom_just_changed(false), showing_all(false), - snapping(true), - snapped(false), - snap_point(0), selecting(false), rect_select_init(false), rect_select_proc(false), moving_init(false), moving_proc(false), move_insert(false), - trim_target(-1), + trim_target(nullptr), trim_type(olive::timeline::TRIM_NONE), splitting(false), importing(false), @@ -81,11 +79,12 @@ Timeline::Timeline(QWidget *parent) : creating(false), transition_tool_init(false), transition_tool_proc(false), - transition_tool_open_clip(-1), - transition_tool_close_clip(-1), + transition_tool_open_clip(nullptr), + transition_tool_close_clip(nullptr), hand_moving(false), block_repaints(false), - scroll(0) + scroll(0), + sequence_(nullptr) { setup_ui(); @@ -124,6 +123,113 @@ Timeline::Timeline(QWidget *parent) : Retranslate(); } +Timeline *Timeline::GetTopTimeline() +{ + for (int i=0;iisVisible()) { + return panel_timeline.at(i); + } + } + + return nullptr; +} + +SequencePtr Timeline::GetTopSequence() +{ + Timeline* top_timeline = GetTopTimeline(); + + if (top_timeline != nullptr) { + return top_timeline->sequence_; + } + + return nullptr; +} + +void Timeline::OpenSequence(SequencePtr s) +{ + Q_ASSERT(s != nullptr); + + for (int i=0;isequence_ == s) { + t->raise(); + return; + } else if (t->sequence_ == nullptr) { + t->SetSequence(s); + t->raise(); + return; + } + } + + Timeline* t = new Timeline(olive::MainWindow); + panel_timeline.append(t); + olive::MainWindow->addDockWidget(Qt::BottomDockWidgetArea, t); + olive::MainWindow->tabifyDockWidget(panel_timeline.last(), t); + t->SetSequence(s); + t->raise(); +} + +void Timeline::CloseSequence(Sequence *s) +{ + Q_ASSERT(s != nullptr); + + // Don't respond to a null sequence + if (s == nullptr) { + return; + } + + // If there's only one Timeline object left, just set it to nullptr without destroying it + if (panel_timeline.size() == 1) { + panel_timeline.first()->SetSequence(nullptr); + return; + } + + // If there are multiple, kill the Timeline object that has the specified sequence + for (int i=0;isequence_.get() == s) { + delete t; + panel_timeline.removeAt(i); + i--; + } + } +} + +void Timeline::CloseAll() +{ + while (panel_timeline.size() > 1) { + delete panel_timeline.last(); + panel_timeline.removeLast(); + } + panel_timeline.first()->SetSequence(nullptr); +} + +bool Timeline::IsImporting() +{ + for (int i=0;iimporting) { + return true; + } + } + return false; +} + +void Timeline::SetSequence(SequencePtr sequence) +{ + if (sequence_ == sequence) { + return; + } + + sequence_ = sequence; + update_sequence(); + video_area->SetTrackList(sequence_.get(), Track::kTypeVideo); + audio_area->SetTrackList(sequence_.get(), Track::kTypeAudio); + repaint_timeline(); + + emit SequenceChanged(sequence_); +} + void Timeline::Retranslate() { toolArrowButton->setToolTip(tr("Pointer Tool") + " (V)"); toolEditButton->setToolTip(tr("Edit Tool") + " (X)"); @@ -143,212 +249,22 @@ void Timeline::Retranslate() { } void Timeline::toggle_show_all() { - if (olive::ActiveSequence != nullptr) { + if (sequence_ != nullptr) { showing_all = !showing_all; if (showing_all) { old_zoom = zoom; - set_zoom_value(double(timeline_area->width() - 200) / double(olive::ActiveSequence->GetEndFrame())); + set_zoom_value(double(timeline_area->width() - 200) / double(sequence_->GetEndFrame())); } else { set_zoom_value(old_zoom); } } } -void Timeline::create_ghosts_from_media(Sequence* seq, long entry_point, QVector& media_list) { - video_ghosts = false; - audio_ghosts = false; - - for (int i=0;iget_type()) { - case MEDIA_TYPE_FOOTAGE: - m = medium->to_footage(); - can_import = m->ready; - if (m->using_inout) { - double source_fr = 30; - if (m->video_tracks.size() > 0 && !qIsNull(m->video_tracks.at(0).video_frame_rate)) { - source_fr = m->video_tracks.at(0).video_frame_rate * m->speed; - } - default_clip_in = rescale_frame_number(m->in, source_fr, seq->frame_rate); - default_clip_out = rescale_frame_number(m->out, source_fr, seq->frame_rate); - } - break; - case MEDIA_TYPE_SEQUENCE: - s = medium->to_sequence().get(); - sequence_length = s->GetEndFrame(); - if (seq != nullptr) sequence_length = rescale_frame_number(sequence_length, s->frame_rate, seq->frame_rate); - can_import = (s != seq && sequence_length != 0); - if (s->using_workarea) { - default_clip_in = rescale_frame_number(s->workarea_in, s->frame_rate, seq->frame_rate); - default_clip_out = rescale_frame_number(s->workarea_out, s->frame_rate, seq->frame_rate); - } - break; - default: - can_import = false; - } - - if (can_import) { - Ghost g; - g.clip = -1; - g.trim_type = olive::timeline::TRIM_NONE; - g.old_clip_in = g.clip_in = default_clip_in; - g.media = medium; - g.in = entry_point; - g.transition = nullptr; - - switch (medium->get_type()) { - case MEDIA_TYPE_FOOTAGE: - // is video source a still image? - if (m->video_tracks.size() > 0 && m->video_tracks.at(0).infinite_length && m->audio_tracks.size() == 0) { - g.out = g.in + 100; - } else { - long length = m->get_length_in_frames(seq->frame_rate); - g.out = entry_point + length - default_clip_in; - if (m->using_inout) { - g.out -= (length - default_clip_out); - } - } - - if (import_data.type() == olive::timeline::kImportAudioOnly - || import_data.type() == olive::timeline::kImportBoth) { - for (int j=0;jaudio_tracks.size();j++) { - if (m->audio_tracks.at(j).enabled) { - g.track = seq->GetTrackList(Track::kTypeAudio)->First() + j; - g.media_stream = m->audio_tracks.at(j).file_index; - ghosts.append(g); - audio_ghosts = true; - } - } - } - - if (import_data.type() == olive::timeline::kImportVideoOnly - || import_data.type() == olive::timeline::kImportBoth) { - for (int j=0;jvideo_tracks.size();j++) { - if (m->video_tracks.at(j).enabled) { - g.track = seq->GetTrackList(Track::kTypeVideo)->First() + j; - g.media_stream = m->video_tracks.at(j).file_index; - ghosts.append(g); - video_ghosts = true; - } - } - } - break; - case MEDIA_TYPE_SEQUENCE: - g.out = entry_point + sequence_length - default_clip_in; - - if (s->using_workarea) { - g.out -= (sequence_length - default_clip_out); - } - - if (import_data.type() == olive::timeline::kImportVideoOnly - || import_data.type() == olive::timeline::kImportBoth) { - g.track = seq->GetTrackList(Track::kTypeVideo)->First(); - ghosts.append(g); - } - - if (import_data.type() == olive::timeline::kImportAudioOnly - || import_data.type() == olive::timeline::kImportBoth) { - g.track = seq->GetTrackList(Track::kTypeAudio)->First(); - ghosts.append(g); - } - - video_ghosts = true; - audio_ghosts = true; - break; - } - entry_point = g.out; - } - } - for (int i=0;i added_clips; - for (int i=0;i(s); - c->set_media(g.media, g.media_stream); - c->set_timeline_in(g.in); - c->set_timeline_out(g.out); - c->set_clip_in(g.clip_in); - c->set_track(g.track); - if (c->media()->get_type() == MEDIA_TYPE_FOOTAGE) { - Footage* m = c->media()->to_footage(); - if (m->video_tracks.size() == 0) { - // audio only (greenish) - c->set_color(128, 192, 128); - } else if (m->audio_tracks.size() == 0) { - // video only (orangeish) - c->set_color(192, 160, 128); - } else { - // video and audio (blueish) - c->set_color(128, 128, 192); - } - c->set_name(m->name); - } else if (c->media()->get_type() == MEDIA_TYPE_SEQUENCE) { - // sequence (red?ish?) - c->set_color(192, 128, 128); - - c->set_name(c->media()->to_sequence()->name); - } - c->refresh(); - added_clips.append(c); - } - ca->append(new AddClipCommand(s, added_clips)); - - // link clips from the same media - for (int i=0;imedia() == cc->media()) { - c->linked.append(cc.get()); - } - } - - if (olive::CurrentConfig.add_default_effects_to_clips) { - if (c->type() == Track::kTypeVideo) { - // add default video effects - c->effects.append(Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_TRANSFORM, EFFECT_TYPE_EFFECT))); - } else if (c->type() == Track::kTypeAudio) { - // add default audio effects - c->effects.append(Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_VOLUME, EFFECT_TYPE_EFFECT))); - c->effects.append(Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_PAN, EFFECT_TYPE_EFFECT))); - } - } - } - if (olive::CurrentConfig.enable_seek_to_import) { - panel_sequence_viewer->seek(earliest_point); - } - ghosts.clear(); - importing = false; - snapped = false; -} - void Timeline::add_transition() { ComboAction* ca = new ComboAction(); bool adding = false; - QVector selected_clips = olive::ActiveSequence->SelectedClips(); + QVector selected_clips = sequence_->SelectedClips(); for (int i=0;i selected_clips = olive::ActiveSequence->SelectedClips(); + QVector selected_clips = sequence_->SelectedClips(); // nest them if (!selected_clips.isEmpty()) { @@ -404,11 +320,11 @@ void Timeline::nest() { SequencePtr s = std::make_shared(); s->name = olive::project_model.GetNextSequenceName(tr("Nested Sequence")); - s->width = olive::ActiveSequence->width; - s->height = olive::ActiveSequence->height; - s->frame_rate = olive::ActiveSequence->frame_rate; - s->audio_frequency = olive::ActiveSequence->audio_frequency; - s->audio_layout = olive::ActiveSequence->audio_layout; + s->width = sequence_->width; + s->height = sequence_->height; + s->frame_rate = sequence_->frame_rate; + s->audio_frequency = sequence_->audio_frequency; + s->audio_layout = sequence_->audio_layout; QVector new_clips; @@ -438,10 +354,10 @@ void Timeline::nest() { // add nested sequence to active sequence QVector media_list; media_list.append(m.get()); - create_ghosts_from_media(olive::ActiveSequence.get(), earliest_point, media_list); + olive::timeline::CreateGhostsFromMedia(sequence_.get(), earliest_point, media_list); // ensure ghosts won't overlap anything - QVector all_sequence_clips = olive::ActiveSequence->GetAllClips(); + QVector all_sequence_clips = sequence_->GetAllClips(); for (int j=0;jAddClipsFromGhosts(ca, ghosts); panel_graph_editor->set_row(nullptr); panel_effect_controls->Clear(true); - olive::ActiveSequence->ClearSelections(); + sequence_->ClearSelections(); - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); update_ui(true); } @@ -480,7 +396,7 @@ void Timeline::nest() { } void Timeline::update_sequence() { - bool null_sequence = (olive::ActiveSequence == nullptr); + bool null_sequence = (sequence_ == nullptr); for (int i=0;isetEnabled(!null_sequence); @@ -495,32 +411,28 @@ void Timeline::update_sequence() { UpdateTitle(); } -long Timeline::get_snap_range() { - return getFrameFromScreenPoint(zoom, 10); -} - bool Timeline::focused() { - return (olive::ActiveSequence != nullptr && (headers->hasFocus() || video_area->hasFocus() || audio_area->hasFocus())); + return (sequence_ != nullptr && (headers->hasFocus() || video_area->hasFocus() || audio_area->hasFocus())); } void Timeline::repaint_timeline() { if (!block_repaints) { bool draw = true; - if (olive::ActiveSequence != nullptr + if (sequence_ != nullptr && !horizontalScrollBar->isSliderDown() && !horizontalScrollBar->is_resizing() && panel_sequence_viewer->playing && !zoom_just_changed) { // auto scroll - if (olive::CurrentConfig.autoscroll == olive::AUTOSCROLL_PAGE_SCROLL) { - int playhead_x = getTimelineScreenPointFromFrame(olive::ActiveSequence->playhead); + if (olive::config.autoscroll == olive::AUTOSCROLL_PAGE_SCROLL) { + int playhead_x = getTimelineScreenPointFromFrame(sequence_->playhead); if (playhead_x < 0 || playhead_x > (editAreas->width())) { - horizontalScrollBar->setValue(getScreenPointFromFrame(zoom, olive::ActiveSequence->playhead)); + horizontalScrollBar->setValue(getScreenPointFromFrame(zoom, sequence_->playhead)); draw = false; } - } else if (olive::CurrentConfig.autoscroll == olive::AUTOSCROLL_SMOOTH_SCROLL) { - if (center_scroll_to_playhead(horizontalScrollBar, zoom, olive::ActiveSequence->playhead)) { + } else if (olive::config.autoscroll == olive::AUTOSCROLL_SMOOTH_SCROLL) { + if (center_scroll_to_playhead(horizontalScrollBar, zoom, sequence_->playhead)) { draw = false; } } @@ -531,7 +443,7 @@ void Timeline::repaint_timeline() { video_area->update(); audio_area->update(); - if (olive::ActiveSequence != nullptr + if (sequence_ != nullptr && !zoom_just_changed) { set_sb_max(); } @@ -542,8 +454,8 @@ void Timeline::repaint_timeline() { } void Timeline::select_all() { - if (olive::ActiveSequence != nullptr) { - olive::ActiveSequence->SelectAll(); + if (sequence_ != nullptr) { + sequence_->SelectAll(); repaint_timeline(); } } @@ -552,15 +464,9 @@ void Timeline::scroll_to_frame(long frame) { scroll_to_frame_internal(horizontalScrollBar, frame, zoom, timeline_area->width()); } -void Timeline::select_from_playhead() { - if (olive::ActiveSequence != nullptr) { - olive::ActiveSequence->SelectAtPlayhead(); - } -} - void Timeline::resizeEvent(QResizeEvent *) { // adjust maximum scrollbar - if (olive::ActiveSequence != nullptr) set_sb_max(); + if (sequence_ != nullptr) set_sb_max(); // resize tool button widget to its contents @@ -590,10 +496,10 @@ void Timeline::resizeEvent(QResizeEvent *) { } void Timeline::toggle_enable_on_selected_clips() { - if (olive::ActiveSequence != nullptr) { + if (sequence_ != nullptr) { // get currently selected clips - QVector selected_clips = olive::ActiveSequence->SelectedClips(); + QVector selected_clips = sequence_->SelectedClips(); if (!selected_clips.isEmpty()) { // if clips are selected, create an undoable action @@ -606,7 +512,7 @@ void Timeline::toggle_enable_on_selected_clips() { } // push the action - olive::UndoStack.push(set_action); + olive::undo_stack.push(set_action); update_ui(false); } } @@ -623,12 +529,12 @@ void Timeline::set_zoom_value(double v) { zoom_just_changed = true; // set scrollbar to center the playhead - if (olive::ActiveSequence != nullptr) { + if (sequence_ != nullptr) { // update scrollbar maximum value for new zoom set_sb_max(); if (!horizontalScrollBar->is_resizing()) { - center_scroll_to_playhead(horizontalScrollBar, zoom, olive::ActiveSequence->playhead); + center_scroll_to_playhead(horizontalScrollBar, zoom, sequence_->playhead); } } @@ -650,8 +556,8 @@ void Timeline::zoom_out() { } void Timeline::ChangeTrackHeightUniformly(int diff) { - if (olive::ActiveSequence != nullptr) { - olive::ActiveSequence->ChangeTrackHeightsRelatively(diff); + if (sequence_ != nullptr) { + sequence_->ChangeTrackHeightsRelatively(diff); } // update the timeline @@ -667,12 +573,12 @@ void Timeline::DecreaseTrackHeight() { } void Timeline::snapping_clicked(bool checked) { - snapping = checked; + olive::timeline::snapping = checked; } /* bool Timeline::split_clip_and_relink(ComboAction *ca, int clip, long frame, bool relink) { - Clip* c = olive::ActiveSequence->clips.at(clip).get(); + Clip* c = sequence_->clips.at(clip).get(); if (c != nullptr) { QVector pre_clips; QVector post_clips; @@ -693,7 +599,7 @@ bool Timeline::split_clip_and_relink(ComboAction *ca, int clip, long frame, bool // find linked clips of old clip for (int i=0;ilinked.size();i++) { int l = c->linked.at(i); - Clip* link = olive::ActiveSequence->clips.at(l).get(); + Clip* link = sequence_->clips.at(l).get(); if ((original_clip_is_selected && link->IsSelected()) || !original_clip_is_selected) { ClipPtr s = split_clip(ca, true, l, frame); if (s != nullptr) { @@ -705,7 +611,7 @@ bool Timeline::split_clip_and_relink(ComboAction *ca, int clip, long frame, bool relink_clips_using_ids(pre_clips, post_clips); } - ca->append(new AddClipCommand(olive::ActiveSequence.get(), post_clips)); + ca->append(new AddClipCommand(sequence_.get(), post_clips)); return true; } } @@ -716,403 +622,119 @@ bool Timeline::split_clip_and_relink(ComboAction *ca, int clip, long frame, bool void Timeline::copy(bool del) { - if (olive::ActiveSequence != nullptr) { - olive::ActiveSequence->AddSelectionsToClipboard(del); - } -} - -void Timeline::paste(bool insert) { - -} - -void Timeline::edit_to_point_internal(bool in, bool ripple) { - if (olive::ActiveSequence != nullptr) { - if (olive::ActiveSequence->clips.size() > 0) { - // get track count - int track_min = INT_MAX; - int track_max = INT_MIN; - long sequence_end = 0; - - bool playhead_falls_on_in = false; - bool playhead_falls_on_out = false; - long next_cut = LONG_MAX; - long prev_cut = 0; - - // find closest in point to playhead - for (int i=0;iclips.size();i++) { - ClipPtr c = olive::ActiveSequence->clips.at(i); - if (c != nullptr) { - track_min = qMin(track_min, c->track()); - track_max = qMax(track_max, c->track()); - - sequence_end = qMax(c->timeline_out(), sequence_end); - - if (c->timeline_in() == olive::ActiveSequence->playhead) - playhead_falls_on_in = true; - if (c->timeline_out() == olive::ActiveSequence->playhead) - playhead_falls_on_out = true; - if (c->timeline_in() > olive::ActiveSequence->playhead) - next_cut = qMin(c->timeline_in(), next_cut); - if (c->timeline_out() > olive::ActiveSequence->playhead) - next_cut = qMin(c->timeline_out(), next_cut); - if (c->timeline_in() < olive::ActiveSequence->playhead) - prev_cut = qMax(c->timeline_in(), prev_cut); - if (c->timeline_out() < olive::ActiveSequence->playhead) - prev_cut = qMax(c->timeline_out(), prev_cut); - } - } - - next_cut = qMin(sequence_end, next_cut); - - QVector areas; - ComboAction* ca = new ComboAction(); - bool push_undo = true; - long seek = olive::ActiveSequence->playhead; - - if ((in && (playhead_falls_on_out || (playhead_falls_on_in && olive::ActiveSequence->playhead == 0))) - || (!in && (playhead_falls_on_in || (playhead_falls_on_out && olive::ActiveSequence->playhead == sequence_end)))) { // one frame mode - if (ripple) { - // set up deletion areas based on track count - long in_point = olive::ActiveSequence->playhead; - if (!in) { - in_point--; - seek--; - } - - if (in_point >= 0) { - Selection s; - s.in = in_point; - s.out = in_point + 1; - for (int i=track_min;i<=track_max;i++) { - s.track = i; - areas.append(s); - } - - // trim and move clips around the in point - delete_areas_and_relink(ca, areas, true); - - if (ripple) ripple_clips(ca, olive::ActiveSequence.get(), in_point, -1); - } else { - push_undo = false; - } - } else { - push_undo = false; - } - } else { - // set up deletion areas based on track count - Selection s; - if (in) seek = prev_cut; - s.in = in ? prev_cut : olive::ActiveSequence->playhead; - s.out = in ? olive::ActiveSequence->playhead : next_cut; - - if (s.in == s.out) { - push_undo = false; - } else { - for (int i=track_min;i<=track_max;i++) { - s.track = i; - areas.append(s); - } - - // trim and move clips around the in point - delete_areas_and_relink(ca, areas, true); - if (ripple) ripple_clips(ca, olive::ActiveSequence.get(), s.in, s.in - s.out); - } - } - - if (push_undo) { - olive::UndoStack.push(ca); - - update_ui(true); - - if (seek != olive::ActiveSequence->playhead && ripple) { - panel_sequence_viewer->seek(seek); - } - } else { - delete ca; - } - } else { - panel_sequence_viewer->seek(0); - } - } -} - -bool Timeline::split_selection(ComboAction* ca) { - bool split = false; - - // temporary relinking vectors - QVector pre_splits; - QVector post_splits; - QVector secondary_post_splits; - - // find clips within selection and split - for (int j=0;jclips.size();j++) { - ClipPtr clip = olive::ActiveSequence->clips.at(j); - if (clip != nullptr) { - for (int i=0;iselections.size();i++) { - const Selection& s = olive::ActiveSequence->selections.at(i); - if (s.track == clip->track()) { - ClipPtr post_b = split_clip(ca, true, j, s.out); - ClipPtr post_a = split_clip(ca, true, j, s.in); - - pre_splits.append(j); - post_splits.append(post_a); - secondary_post_splits.append(post_b); - - if (post_a != nullptr) { - post_a->set_timeline_out(qMin(post_a->timeline_out(), s.out)); - } - - split = true; - } - } - } - } - - if (split) { - // relink after splitting - relink_clips_using_ids(pre_splits, post_splits); - relink_clips_using_ids(pre_splits, secondary_post_splits); - - ca->append(new AddClipCommand(olive::ActiveSequence.get(), post_splits)); - ca->append(new AddClipCommand(olive::ActiveSequence.get(), secondary_post_splits)); - - return true; - } - return false; -} - -void Timeline::split_at_playhead() { - ComboAction* ca = new ComboAction(); - bool split_selected = false; - - if (olive::ActiveSequence->selections.size() > 0) { - // see if whole clips are selected - QVector pre_clips; - QVector post_clips; - for (int j=0;jclips.size();j++) { - Clip* clip = olive::ActiveSequence->clips.at(j).get(); - if (clip != nullptr && clip->IsSelected()) { - ClipPtr s = split_clip(ca, true, j, olive::ActiveSequence->playhead); - if (s != nullptr) { - pre_clips.append(j); - post_clips.append(s); - split_selected = true; - } - } - } - - if (split_selected) { - // relink clips if we split - relink_clips_using_ids(pre_clips, post_clips); - ca->append(new AddClipCommand(olive::ActiveSequence.get(), post_clips)); - } else { - // split a selection if not - split_selected = split_selection(ca); - } - } - - // if nothing was selected or no selections fell within playhead, simply split at playhead - if (!split_selected) { - split_selected = split_all_clips_at_point(ca, olive::ActiveSequence->playhead); - } - - if (split_selected) { - olive::UndoStack.push(ca); - update_ui(true); - } else { - delete ca; + if (sequence_ != nullptr) { + sequence_->AddSelectionsToClipboard(del); } } void Timeline::ripple_delete() { - if (olive::ActiveSequence != nullptr) { - if (olive::ActiveSequence->selections.size() > 0) { - panel_timeline->delete_selection(olive::ActiveSequence->selections, true); - } else if (olive::CurrentConfig.hover_focus && get_focused_panel() == panel_timeline) { - if (panel_timeline->can_ripple_empty_space(panel_timeline->cursor_frame, panel_timeline->cursor_track)) { - panel_timeline->ripple_delete_empty_space(); - } + if (sequence_ != nullptr) { + + QVector selections = sequence_->Selections(); + + if (selections.isEmpty()) { + + sequence_->RippleDeleteEmptySpace(cursor_track, cursor_frame); + + } else if (olive::config.hover_focus && get_focused_panel() == this) { + + ComboAction* ca = new ComboAction(); + sequence_->DeleteAreas(ca, selections, true, true); + olive::undo_stack.push(ca); + } } } -void Timeline::deselect_area(long in, long out, int track) { - int len = olive::ActiveSequence->selections.size(); - for (int i=0;iselections[i]; - if (s.track == track) { - if (s.in >= in && s.out <= out) { - // whole selection is in deselect area - olive::ActiveSequence->selections.removeAt(i); - i--; - len--; - } else if (s.in < in && s.out > out) { - // middle of selection is in deselect area - Selection new_sel; - new_sel.in = out; - new_sel.out = s.out; - new_sel.track = s.track; - olive::ActiveSequence->selections.append(new_sel); +void Timeline::ripple_delete_empty_space() +{ + if (sequence_ != nullptr) { - s.out = in; - } else if (s.in < in && s.out > in) { - // only out point is in deselect area - s.out = in; - } else if (s.in < out && s.out > out) { - // only in point is in deselect area - s.in = out; - } - } } } -bool Timeline::snap_to_point(long point, long* l) { - int limit = get_snap_range(); - if (*l > point-limit-1 && *l < point+limit+1) { - snap_point = point; - *l = point; - snapped = true; - return true; - } - return false; -} - -bool Timeline::snap_to_timeline(long* l, bool use_playhead, bool use_markers, bool use_workarea) { - snapped = false; - if (snapping) { - if (use_playhead && !panel_sequence_viewer->playing) { - // snap to playhead - if (snap_to_point(olive::ActiveSequence->playhead, l)) return true; - } - - // snap to marker - if (use_markers) { - for (int i=0;imarkers.size();i++) { - if (snap_to_point(olive::ActiveSequence->markers.at(i).frame, l)) return true; - } - } - - // snap to in/out - if (use_workarea && olive::ActiveSequence->using_workarea) { - if (snap_to_point(olive::ActiveSequence->workarea_in, l)) return true; - if (snap_to_point(olive::ActiveSequence->workarea_out, l)) return true; - } - - // snap to clip/transition - QVector all_clips = olive::ActiveSequence->GetAllClips(); - for (int i=0;itimeline_in(), l)) { - return true; - } else if (snap_to_point(c->timeline_out(), l)) { - return true; - } else if (c->opening_transition != nullptr - && snap_to_point(c->timeline_in() + c->opening_transition->get_true_length(), l)) { - return true; - } else if (c->closing_transition != nullptr - && snap_to_point(c->timeline_out() - c->closing_transition->get_true_length(), l)) { - return true; - } else { - // try to snap to clip markers - for (int j=0;jget_markers().size();j++) { - if (snap_to_point(c->get_markers().at(j).frame + c->timeline_in() - c->clip_in(), l)) { - return true; - } - } - } - - } - } - - return false; -} - void Timeline::set_marker() { // determine if any clips are selected, and if so add markers to clips rather than the sequence - QVector clips_selected; - bool clip_mode = false; - for (int i=0;iclips.size();i++) { - Clip* c = olive::ActiveSequence->clips.at(i).get(); - if (c != nullptr - && c->IsSelected()) { + QVector selected_clips = sequence_->SelectedClips(); - // only add markers if the playhead is inside the clip - if (olive::ActiveSequence->playhead >= c->timeline_in() - && olive::ActiveSequence->playhead <= c->timeline_out()) { - clips_selected.append(i); + if (selected_clips.isEmpty()) { + + Marker::SetOnSequence(sequence_.get()); + + } else { + + // Remove any clips that don't contain the playhead + for (int i=0;itimeline_out() < sequence_->playhead + || c->timeline_in() > sequence_->playhead) { + selected_clips.removeAt(i); + i--; } - - // we are definitely adding markers to clips though - clip_mode = true; - } + + // Check if we removed them all + if (selected_clips.isEmpty()) { + return; + } + + // If not, let's create markers on them + Marker::SetOnClips(selected_clips); + } - - // if we've selected clips but none of the clips are within the playhead, - // nothing to do here - if (clip_mode && clips_selected.size() == 0) { - return; - } - - // pass off to internal set marker function - set_marker_internal(olive::ActiveSequence.get(), clips_selected); - } void Timeline::delete_inout() { - panel_timeline->delete_in_out_internal(false); + if (sequence_ != nullptr) { + sequence_->DeleteInToOut(false); + } } void Timeline::ripple_delete_inout() { - panel_timeline->delete_in_out_internal(true); + if (sequence_ != nullptr) { + sequence_->DeleteInToOut(true); + } } void Timeline::ripple_to_in_point() { - panel_timeline->edit_to_point_internal(true, true); + if (sequence_ != nullptr) { + sequence_->EditToPoint(true, true); + } } void Timeline::ripple_to_out_point() { - panel_timeline->edit_to_point_internal(false, true); + if (sequence_ != nullptr) { + sequence_->EditToPoint(false, true); + } } void Timeline::edit_to_in_point() { - panel_timeline->edit_to_point_internal(true, false); + if (sequence_ != nullptr) { + sequence_->EditToPoint(true, false); + } } void Timeline::edit_to_out_point() { - panel_timeline->edit_to_point_internal(false, false); -} - -void Timeline::toggle_links() { - LinkCommand* command = new LinkCommand(); - command->s = olive::ActiveSequence.get(); - for (int i=0;iclips.size();i++) { - Clip* c = olive::ActiveSequence->clips.at(i).get(); - if (c != nullptr && c->IsSelected()) { - if (!command->clips.contains(i)) command->clips.append(i); - - if (c->linked.size() > 0) { - command->link = false; // prioritize unlinking - - for (int j=0;jlinked.size();j++) { // add links to the command - if (!command->clips.contains(c->linked.at(j))) command->clips.append(c->linked.at(j)); - } - } - } - } - if (command->clips.size() > 0) { - olive::UndoStack.push(command); - repaint_timeline(); - } else { - delete command; + if (sequence_ != nullptr) { + sequence_->EditToPoint(false, false); } } void Timeline::deselect() { - olive::ActiveSequence->selections.clear(); - repaint_timeline(); + if (sequence_ != nullptr) { + sequence_->ClearSelections(); + repaint_timeline(); + } +} + +void Timeline::split_at_playhead() +{ + if (sequence_ != nullptr) { + sequence_->Split(); + repaint_timeline(); + } } long getFrameFromScreenPoint(double zoom, int x) { @@ -1172,7 +794,7 @@ void Timeline::add_btn_click() { void Timeline::add_menu_item(QAction* action) { creating = true; - creating_object = action->data().toInt(); + creating_object = static_cast(action->data().toInt()); } void Timeline::setScroll(int s) { @@ -1232,13 +854,12 @@ void Timeline::transition_menu_select(QAction* a) { transition_tool_meta = reinterpret_cast(a->data().value()); if (a->objectName() == "v") { - transition_tool_side = -1; + transition_tool_side = Track::kTypeVideo; } else { - transition_tool_side = 1; + transition_tool_side = Track::kTypeAudio; } timeline_area->setCursor(Qt::CrossCursor); - tool = TIMELINE_TOOL_TRANSITION; toolTransitionButton->setChecked(true); } @@ -1247,15 +868,15 @@ void Timeline::resize_move(double z) { } void Timeline::set_sb_max() { - headers->set_scrollbar_max(horizontalScrollBar, olive::ActiveSequence->getEndFrame(), editAreas->width() - getScreenPointFromFrame(zoom, 200)); + headers->set_scrollbar_max(horizontalScrollBar, sequence_->GetEndFrame(), editAreas->width() - getScreenPointFromFrame(zoom, 200)); } void Timeline::UpdateTitle() { QString title = tr("Timeline: "); - if (olive::ActiveSequence == nullptr) { + if (sequence_ == nullptr) { setWindowTitle(title + tr("(none)")); } else { - setWindowTitle(title + olive::ActiveSequence->name); + setWindowTitle(title + sequence_->name); update_ui(false); } } @@ -1280,42 +901,42 @@ void Timeline::setup_ui() { toolArrowButton = new QPushButton(); toolArrowButton->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/arrow.svg"))); toolArrowButton->setCheckable(true); - toolArrowButton->setProperty("tool", TIMELINE_TOOL_POINTER); + toolArrowButton->setProperty("tool", olive::timeline::TIMELINE_TOOL_POINTER); connect(toolArrowButton, SIGNAL(clicked(bool)), this, SLOT(set_tool())); tool_buttons_layout->addWidget(toolArrowButton); toolEditButton = new QPushButton(); toolEditButton->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/beam.svg"))); toolEditButton->setCheckable(true); - toolEditButton->setProperty("tool", TIMELINE_TOOL_EDIT); + toolEditButton->setProperty("tool", olive::timeline::TIMELINE_TOOL_EDIT); connect(toolEditButton, SIGNAL(clicked(bool)), this, SLOT(set_tool())); tool_buttons_layout->addWidget(toolEditButton); toolRippleButton = new QPushButton(); toolRippleButton->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/ripple.svg"))); toolRippleButton->setCheckable(true); - toolRippleButton->setProperty("tool", TIMELINE_TOOL_RIPPLE); + toolRippleButton->setProperty("tool", olive::timeline::TIMELINE_TOOL_RIPPLE); connect(toolRippleButton, SIGNAL(clicked(bool)), this, SLOT(set_tool())); tool_buttons_layout->addWidget(toolRippleButton); toolRazorButton = new QPushButton(); toolRazorButton->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/razor.svg"))); toolRazorButton->setCheckable(true); - toolRazorButton->setProperty("tool", TIMELINE_TOOL_RAZOR); + toolRazorButton->setProperty("tool", olive::timeline::TIMELINE_TOOL_RAZOR); connect(toolRazorButton, SIGNAL(clicked(bool)), this, SLOT(set_tool())); tool_buttons_layout->addWidget(toolRazorButton); toolSlipButton = new QPushButton(); toolSlipButton->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/slip.svg"))); toolSlipButton->setCheckable(true); - toolSlipButton->setProperty("tool", TIMELINE_TOOL_SLIP); + toolSlipButton->setProperty("tool", olive::timeline::TIMELINE_TOOL_SLIP); connect(toolSlipButton, SIGNAL(clicked(bool)), this, SLOT(set_tool())); tool_buttons_layout->addWidget(toolSlipButton); toolSlideButton = new QPushButton(); toolSlideButton->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/slide.svg"))); toolSlideButton->setCheckable(true); - toolSlideButton->setProperty("tool", TIMELINE_TOOL_SLIDE); + toolSlideButton->setProperty("tool", olive::timeline::TIMELINE_TOOL_SLIDE); connect(toolSlideButton, SIGNAL(clicked(bool)), this, SLOT(set_tool())); tool_buttons_layout->addWidget(toolSlideButton); @@ -1323,7 +944,7 @@ void Timeline::setup_ui() { toolHandButton->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/hand.svg"))); toolHandButton->setCheckable(true); - toolHandButton->setProperty("tool", TIMELINE_TOOL_HAND); + toolHandButton->setProperty("tool", olive::timeline::TIMELINE_TOOL_HAND); connect(toolHandButton, SIGNAL(clicked(bool)), this, SLOT(set_tool())); tool_buttons_layout->addWidget(toolHandButton); toolTransitionButton = new QPushButton(); @@ -1384,10 +1005,10 @@ void Timeline::setup_ui() { splitter->setChildrenCollapsible(false); splitter->setOrientation(Qt::Vertical); - video_area = new TimelineArea(); + video_area = new TimelineArea(this); splitter->addWidget(video_area); - audio_area = new TimelineArea(); + audio_area = new TimelineArea(this); splitter->addWidget(audio_area); editAreaLayout->addWidget(splitter); @@ -1413,16 +1034,16 @@ void Timeline::setup_ui() { void Timeline::set_tool() { QPushButton* button = static_cast(sender()); - tool = button->property("tool").toInt(); + olive::timeline::current_tool = static_cast(button->property("tool").toInt()); creating = false; - switch (tool) { - case TIMELINE_TOOL_EDIT: + switch (olive::timeline::current_tool) { + case olive::timeline::TIMELINE_TOOL_EDIT: timeline_area->setCursor(Qt::IBeamCursor); break; - case TIMELINE_TOOL_RAZOR: + case olive::timeline::TIMELINE_TOOL_RAZOR: timeline_area->setCursor(olive::cursor::Razor); break; - case TIMELINE_TOOL_HAND: + case olive::timeline::TIMELINE_TOOL_HAND: timeline_area->setCursor(Qt::OpenHandCursor); break; default: diff --git a/panels/timeline.h b/panels/timeline.h index 82b31f153..72f68feb7 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -26,7 +26,8 @@ #include #include "ui/timelinearea.h" -#include "ui/timelinetools.h" +#include "timeline/timelinetools.h" +#include "timeline/timelinefunctions.h" #include "timeline/selection.h" #include "timeline/clip.h" #include "timeline/mediaimportdata.h" @@ -37,59 +38,44 @@ #include "ui/audiomonitor.h" #include "ui/panel.h" - -int getScreenPointFromFrame(double zoom, long frame); -long getFrameFromScreenPoint(double zoom, int x); -bool selection_contains_transition(const Selection& s, Clip *c, int type); - - class Timeline : public Panel { Q_OBJECT public: explicit Timeline(QWidget *parent = nullptr); + static Timeline* GetTopTimeline(); + static SequencePtr GetTopSequence(); + static void OpenSequence(SequencePtr s); + static void CloseSequence(Sequence* s); + static void CloseAll(); + static bool IsImporting(); + + void SetSequence(SequencePtr sequence); + virtual bool focused() override; void multiply_zoom(double m); void copy(bool del); - void clean_up_selections(QVector& areas); - void deselect_area(long in, long out, int track); - void delete_areas_and_relink(ComboAction *ca, QVector& areas, bool deselect_areas); void update_sequence(); - void edit_to_point_internal(bool in, bool ripple); - void delete_in_out_internal(bool ripple); - - void create_ghosts_from_media(Sequence *seq, long entry_point, QVector &media_list); - void add_clips_from_ghosts(ComboAction *ca, Sequence *s); - int getTimelineScreenPointFromFrame(long frame); long getTimelineFrameFromScreenPoint(int x); int getDisplayScreenPointFromFrame(long frame); long getDisplayFrameFromScreenPoint(int x); - long get_snap_range(); - bool snap_to_point(long point, long* l); - bool snap_to_timeline(long* l, bool use_playhead, bool use_markers, bool use_workarea); void set_marker(); // shared information - int tool; long cursor_frame; - int cursor_track; + Track* cursor_track; double zoom; bool zoom_just_changed; long drag_frame_start; - int drag_track_start; + Track* drag_track_start; void update_effect_controls(); bool showing_all; double old_zoom; - // snapping - bool snapping; - bool snapped; - long snap_point; - // selecting functions bool selecting; int selection_offset; @@ -102,18 +88,16 @@ public: bool moving_init; bool moving_proc; QVector ghosts; - bool video_ghosts; - bool audio_ghosts; bool move_insert; // trimming - int trim_target; + Clip* trim_target; olive::timeline::TrimType trim_type; int transition_select; // splitting bool splitting; - QVector split_tracks; + QVector split_tracks; // importing bool importing; @@ -121,15 +105,15 @@ public: // creating variables bool creating; - int creating_object; + olive::timeline::CreateObjects creating_object; // transition variables bool transition_tool_init; bool transition_tool_proc; - int transition_tool_open_clip; - int transition_tool_close_clip; + Clip* transition_tool_open_clip; + Clip* transition_tool_close_clip; const EffectMeta* transition_tool_meta; - int transition_tool_side; + Track::Type transition_tool_side; // hand tool variables bool hand_moving; @@ -155,7 +139,6 @@ public: QPushButton* snappingButton; void scroll_to_frame(long frame); - void select_from_playhead(); bool can_ripple_empty_space(long frame, int track); @@ -163,11 +146,9 @@ public: protected: virtual void resizeEvent(QResizeEvent *event) override; public slots: - void paste(bool insert = false); void repaint_timeline(); void toggle_show_all(); void deselect(); - void toggle_links(); void split_at_playhead(); void ripple_delete(); void ripple_delete_empty_space(); @@ -184,9 +165,6 @@ public slots: void IncreaseTrackHeight(); void DecreaseTrackHeight(); - void previous_cut(); - void next_cut(); - void add_transition(); void nest(); @@ -194,6 +172,9 @@ public slots: void zoom_in(); void zoom_out(); +signals: + void SequenceChanged(SequencePtr s); + private slots: void snapping_clicked(bool checked); void add_btn_click(); @@ -206,6 +187,8 @@ private slots: void set_tool(); private: + SequencePtr sequence_; + void ChangeTrackHeightUniformly(int diff); void set_zoom_value(double v); void set_tool(int tool); diff --git a/panels/viewer.cpp b/panels/viewer.cpp index 04e9187e8..79ec033bd 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -70,7 +70,8 @@ Viewer::Viewer(QWidget *parent) : created_sequence(false), minimum_zoom(1.0), cue_recording_internal(false), - playback_speed(0) + playback_speed(0), + mode_(kTimelineMode) { setup_ui(); @@ -101,6 +102,16 @@ Viewer::Viewer(QWidget *parent) : update_end_timecode(); } +void Viewer::SetMode(Viewer::Mode mode) +{ + mode_ = mode; +} + +Viewer::Mode Viewer::mode() +{ + return mode_; +} + void Viewer::Retranslate() { /// Viewer panels are retranslated through the MainWindow to differentiate Media and Sequence Viewers // update_window_title(); @@ -116,14 +127,6 @@ bool Viewer::focused() { || go_to_end_frame->hasFocus(); } -bool Viewer::is_main_sequence() { - return main_sequence; -} - -void Viewer::set_main_sequence() { - set_sequence(true, olive::ActiveSequence); -} - void Viewer::reset_all_audio() { // reset all clip audio if (seq != nullptr) { @@ -150,20 +153,24 @@ void Viewer::reset_all_audio() { void Viewer::seek(long p) { pause(); - if (main_sequence) { + + if (mode_ == kTimelineMode) { seq->playhead = p; } else { seq->playhead = qMin(seq->GetEndFrame(), qMax(0L, p)); } + bool update_fx = false; - if (main_sequence) { - panel_timeline->scroll_to_frame(p); + + if (mode_ == kTimelineMode) { + panel_timeline.first()->scroll_to_frame(p); panel_effect_controls->scroll_to_frame(p); - if (olive::CurrentConfig.seek_also_selects) { - panel_timeline->select_from_playhead(); + if (olive::config.seek_also_selects) { + seq->SelectAtPlayhead(); update_fx = true; } } + reset_all_audio(); audio_scrub = true; last_playhead = seq->playhead; @@ -274,11 +281,11 @@ void Viewer::play(bool in_to_out) { uncue_recording(); } - bool seek_to_in = (seq->using_workarea && (olive::CurrentConfig.loop || playing_in_to_out)); + bool seek_to_in = (seq->using_workarea && (olive::config.loop || playing_in_to_out)); if (!is_recording_cued() && playback_speed >= 0 && (playing_in_to_out - || (olive::CurrentConfig.auto_seek_to_beginning && seq->playhead >= sequence_end_frame) + || (olive::config.auto_seek_to_beginning && seq->playhead >= sequence_end_frame) || (seek_to_in && seq->playhead >= seq->workarea_out))) { seek(seek_to_in ? seq->workarea_in : 0); } @@ -359,7 +366,7 @@ void Viewer::pause() { QVector add_clips; add_clips.append(c); - olive::UndoStack.push(new AddClipCommand(seq.get(), add_clips)); // add clip + olive::undo_stack.push(new AddClipCommand(add_clips)); // add clip } @@ -374,7 +381,7 @@ void Viewer::update_playhead_timecode(long p) { } void Viewer::update_end_timecode() { - end_timecode->setText((seq == nullptr) ? frame_to_timecode(0, olive::CurrentConfig.timecode_view, 30) : frame_to_timecode(seq->GetEndFrame(), olive::CurrentConfig.timecode_view, seq->frame_rate)); + end_timecode->setText((seq == nullptr) ? frame_to_timecode(0, olive::config.timecode_view, 30) : frame_to_timecode(seq->GetEndFrame(), olive::config.timecode_view, seq->frame_rate)); } void Viewer::update_header_zoom() { @@ -392,11 +399,10 @@ void Viewer::update_header_zoom() { } void Viewer::update_parents(bool reload_fx) { - if (main_sequence) { + if (mode_ == kTimelineMode) { update_ui(reload_fx); } else { update_viewer(); - panel_timeline->repaint_timeline(); } } @@ -410,7 +416,7 @@ ViewerWidget *Viewer::viewer_widget() } void Viewer::set_marker() { - set_marker_internal(seq.get()); + Marker::SetOnSequence(seq.get()); } void Viewer::resizeEvent(QResizeEvent *e) { @@ -435,7 +441,7 @@ void Viewer::prev_cut() if (seq != nullptr && seq->playhead > 0) { - QVector sequence_clips = olive::ActiveSequence->GetAllClips(); + QVector sequence_clips = seq->GetAllClips(); long p_cut = 0; for (int i=0;iusing_workarea) { - olive::UndoStack.push(new SetTimelineInOutCommand(seq.get(), true, 0, seq->workarea_out)); + olive::undo_stack.push(new SetTimelineInOutCommand(seq.get(), true, 0, seq->workarea_out)); update_parents(); } } @@ -497,7 +503,7 @@ void Viewer::clear_in() { void Viewer::clear_out() { if (seq != nullptr && seq->using_workarea) { - olive::UndoStack.push(new SetTimelineInOutCommand(seq.get(), true, seq->workarea_in, seq->GetEndFrame())); + olive::undo_stack.push(new SetTimelineInOutCommand(seq.get(), true, seq->workarea_in, seq->GetEndFrame())); update_parents(); } } @@ -505,7 +511,7 @@ void Viewer::clear_out() { void Viewer::clear_inout_point() { if (seq != nullptr && seq->using_workarea) { - olive::UndoStack.push(new SetTimelineInOutCommand(seq.get(), false, 0, 0)); + olive::undo_stack.push(new SetTimelineInOutCommand(seq.get(), false, 0, 0)); update_parents(); } } @@ -575,13 +581,13 @@ void Viewer::set_playback_speed(int s) { } long Viewer::get_seq_in() { - return ((olive::CurrentConfig.loop || playing_in_to_out) && seq->using_workarea) + return ((olive::config.loop || playing_in_to_out) && seq->using_workarea) ? seq->workarea_in : 0; } long Viewer::get_seq_out() { - return ((olive::CurrentConfig.loop || playing_in_to_out) && seq->using_workarea && previous_playhead < seq->workarea_out) + return ((olive::config.loop || playing_in_to_out) && seq->using_workarea && previous_playhead < seq->workarea_out) ? seq->workarea_out : seq->GetEndFrame(); } @@ -713,7 +719,6 @@ void Viewer::setup_ui() { } void Viewer::set_media(Media* m) { - main_sequence = false; media = m; SequencePtr new_sequence = nullptr; @@ -737,7 +742,7 @@ void Viewer::set_media(Media* m) { new_sequence->workarea_out = footage->out; } - new_sequence->frame_rate = olive::CurrentConfig.default_sequence_framerate; + new_sequence->frame_rate = olive::config.default_sequence_framerate; if (footage->video_tracks.size() > 0) { const FootageStream& video_stream = footage->video_tracks.at(0); @@ -761,20 +766,19 @@ void Viewer::set_media(Media* m) { c->refresh(); track->AddClip(c); } else { - new_sequence->width = olive::CurrentConfig.default_sequence_width; - new_sequence->height = olive::CurrentConfig.default_sequence_height; + new_sequence->width = olive::config.default_sequence_width; + new_sequence->height = olive::config.default_sequence_height; } if (footage->audio_tracks.size() > 0) { const FootageStream& audio_stream = footage->audio_tracks.at(0); new_sequence->audio_frequency = audio_stream.audio_frequency; - ClipPtr c = std::make_shared(new_sequence.get()); + Track* track = new_sequence->GetTrackList(Track::kTypeAudio)->First(); + ClipPtr c = std::make_shared(track); c->set_media(media, audio_stream.file_index); c->set_timeline_in(0); c->set_timeline_out(footage->get_length_in_frames(new_sequence->frame_rate)); - Track* track = new_sequence->GetTrackList(Track::kTypeAudio)->First(); - c->set_track(track); c->set_clip_in(0); c->refresh(); track->AddClip(c); @@ -786,7 +790,7 @@ void Viewer::set_media(Media* m) { viewer_widget_->frame_update(); } } else { - new_sequence->audio_frequency = olive::CurrentConfig.default_sequence_audio_frequency; + new_sequence->audio_frequency = olive::config.default_sequence_audio_frequency; } new_sequence->audio_layout = AV_CH_LAYOUT_STEREO; @@ -798,7 +802,7 @@ void Viewer::set_media(Media* m) { } } - set_sequence(false, new_sequence); + set_sequence(new_sequence); } void Viewer::update_playhead() { @@ -810,11 +814,11 @@ void Viewer::timer_update() { seq->playhead = qMax(0, qRound(playhead_start + ((QDateTime::currentMSecsSinceEpoch()-start_msecs) * 0.001 * seq->frame_rate * playback_speed))); - if (olive::CurrentConfig.seek_also_selects) { - panel_timeline->select_from_playhead(); + if (olive::config.seek_also_selects) { + seq->SelectAtPlayhead(); } - update_parents(olive::CurrentConfig.seek_also_selects); + update_parents(olive::config.seek_also_selects); if (playing) { if (playback_speed < 0 && seq->playhead == 0) { @@ -825,11 +829,11 @@ void Viewer::timer_update() { } } else if (playback_speed > 0) { long end_frame = seq->GetEndFrame(); - if ((olive::CurrentConfig.auto_seek_to_beginning || previous_playhead < end_frame) && seq->playhead >= end_frame) { + if ((olive::config.auto_seek_to_beginning || previous_playhead < end_frame) && seq->playhead >= end_frame) { pause(); } if (seq->using_workarea && seq->playhead >= seq->workarea_out) { - if (olive::CurrentConfig.loop) { + if (olive::config.loop) { // loop play(); } else if (playing_in_to_out) { @@ -882,7 +886,7 @@ void Viewer::clean_created_seq() { } } -void Viewer::set_sequence(bool main, SequencePtr s) { +void Viewer::set_sequence(SequencePtr s) { pause(); reset_all_audio(); @@ -896,11 +900,7 @@ void Viewer::set_sequence(bool main, SequencePtr s) { clean_created_seq(); - main_sequence = main; - - - - seq = (main) ? olive::ActiveSequence : s; + seq = s; bool null_sequence = (seq == nullptr); diff --git a/panels/viewer.h b/panels/viewer.h index e5659ea4c..80485d26b 100644 --- a/panels/viewer.h +++ b/panels/viewer.h @@ -44,9 +44,16 @@ class Viewer : public Panel public: explicit Viewer(QWidget *parent = nullptr); + enum Mode { + kFootageMode, + kTimelineMode + }; + + void SetMode(Mode mode); + Mode mode(); + virtual bool focused() override; bool is_main_sequence(); - void set_main_sequence(); void set_media(Media *m); void compose(); void set_playpause_icon(bool play); @@ -131,8 +138,7 @@ private slots: private: void update_window_title(); void clean_created_seq(); - void set_sequence(bool main, SequencePtr s); - bool main_sequence; + void set_sequence(SequencePtr s); bool created_sequence; long cached_end_frame; QString panel_name; @@ -169,6 +175,8 @@ private: long previous_playhead; int playback_speed; + + Mode mode_; }; #endif // VIEWER_H diff --git a/project/footage.cpp b/project/footage.cpp index 9e4dc17f2..e1fd0fc5a 100644 --- a/project/footage.cpp +++ b/project/footage.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include namespace OCIO = OCIO_NAMESPACE::v1; @@ -114,7 +115,7 @@ QString Footage::Colorspace() return guess_colorspace; } - return olive::CurrentConfig.ocio_default_input_colorspace; + return olive::config.ocio_default_input_colorspace; } void Footage::SetColorspace(const QString &cs) @@ -154,3 +155,25 @@ FootageStream* Footage::get_stream_from_file_index(bool video, int index) { } return nullptr; } + +QString Footage::get_interlacing_name(int interlacing) { + switch (interlacing) { + case VIDEO_PROGRESSIVE: return QCoreApplication::translate("InterlacingName", "None (Progressive)"); + case VIDEO_TOP_FIELD_FIRST: return QCoreApplication::translate("InterlacingName", "Top Field First"); + case VIDEO_BOTTOM_FIELD_FIRST: return QCoreApplication::translate("InterlacingName", "Bottom Field First"); + default: return QCoreApplication::translate("InterlacingName", "Invalid"); + } +} + +QString Footage::get_channel_layout_name(int channels, uint64_t layout) { + switch (channels) { + case 0: return QCoreApplication::translate("ChannelLayoutName", "Invalid"); + case 1: return QCoreApplication::translate("ChannelLayoutName", "Mono"); + case 2: return QCoreApplication::translate("ChannelLayoutName", "Stereo"); + default: { + char buf[50]; + av_get_channel_layout_string(buf, sizeof(buf), channels, layout); + return QString(buf); + } + } +} diff --git a/project/loadthread.cpp b/project/loadthread.cpp index 20ddc66d6..9f3d135ea 100644 --- a/project/loadthread.cpp +++ b/project/loadthread.cpp @@ -27,6 +27,7 @@ #include "global/config.h" #include "rendering/renderfunctions.h" #include "project/previewgenerator.h" +#include "project/projectfunctions.h" #include "effects/internal/voideffect.h" #include "global/debug.h" #include "effects/effectloaders.h" @@ -82,8 +83,10 @@ void LoadThread::load_effect(QXmlStreamReader& stream, Clip* c) { // Find the clip with the ID referenced in the transition int clip_id = attr.value().toInt(); - for (int i=0;isequence->clips.size();i++) { - Clip* test_clip = c->sequence->clips.at(i).get(); + + QVector sequence_clips = c->track()->sequence()->GetAllClips(); + for (int i=0;iload_id == clip_id) { sharing_clip = test_clip; break; @@ -262,7 +265,7 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) { switch (type) { case MEDIA_TYPE_FOLDER: { - MediaPtr folder = panel_project->create_folder_internal(nullptr); + MediaPtr folder = olive::project::CreateFolder(nullptr); folder->temp_id2 = 0; for (int j=0;j(s.get()); + Track* t; + ClipPtr c = std::make_shared(t); + //ClipPtr c = std::make_shared(s.get()); QColor clip_color; ClipSpeed speed_info = c->speed(); @@ -459,8 +464,6 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) { c->set_timeline_in(attr.value().toLong()); } else if (attr.name() == "out") { c->set_timeline_out(attr.value().toLong()); - } else if (attr.name() == "track") { - c->set_track(attr.value().toInt()); } else if (attr.name() == "r") { clip_color.setRed(attr.value().toInt()); } else if (attr.name() == "g") { @@ -518,7 +521,8 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) { for (int k=0;klinked.append(link_attr.value().toInt()); + // FIXME reimplement this + //c->linked.append(link_attr.value().toInt()); break; } } @@ -546,11 +550,12 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) { } if (cancelled_) return false; - s->clips.append(c); + //s->clips.append(c); } } if (cancelled_) return false; + /* // correct links, clip IDs, transitions for (int i=0;iclips.size();i++) { // correct links @@ -585,6 +590,7 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) { MediaPtr m = panel_project->create_sequence_internal(nullptr, s, false, parent); loaded_sequences.append(m.get()); + */ } break; } @@ -780,11 +786,11 @@ void LoadThread::success_func() { olive::Global->update_project_filename(orig_filename); } else { - panel_project->add_recent_project(filename_); + olive::Global->add_recent_project(filename_); } olive::Global->set_modified(autorecovery_); if (open_seq != nullptr) { - olive::Global->set_sequence(open_seq); + Timeline::OpenSequence(open_seq); } } diff --git a/project/media.cpp b/project/media.cpp index a45560436..a242142c5 100644 --- a/project/media.cpp +++ b/project/media.cpp @@ -39,28 +39,6 @@ extern "C" { #include "global/debug.h" #include "global/timing.h" -QString get_interlacing_name(int interlacing) { - switch (interlacing) { - case VIDEO_PROGRESSIVE: return QCoreApplication::translate("InterlacingName", "None (Progressive)"); - case VIDEO_TOP_FIELD_FIRST: return QCoreApplication::translate("InterlacingName", "Top Field First"); - case VIDEO_BOTTOM_FIELD_FIRST: return QCoreApplication::translate("InterlacingName", "Bottom Field First"); - default: return QCoreApplication::translate("InterlacingName", "Invalid"); - } -} - -QString get_channel_layout_name(int channels, uint64_t layout) { - switch (channels) { - case 0: return QCoreApplication::translate("ChannelLayoutName", "Invalid"); - case 1: return QCoreApplication::translate("ChannelLayoutName", "Mono"); - case 2: return QCoreApplication::translate("ChannelLayoutName", "Stereo"); - default: { - char buf[50]; - av_get_channel_layout_string(buf, sizeof(buf), channels, layout); - return QString(buf); - } - } -} - Media::Media() : root(false), type(-1), @@ -172,7 +150,7 @@ void Media::update_tooltip(const QString& error) { if (i > 0) { tooltip += ", "; } - tooltip += get_interlacing_name(f->video_tracks.at(i).video_interlacing); + tooltip += Footage::get_interlacing_name(f->video_tracks.at(i).video_interlacing); } } @@ -193,7 +171,7 @@ void Media::update_tooltip(const QString& error) { if (i > 0) { tooltip += ", "; } - tooltip += get_channel_layout_name(f->audio_tracks.at(i).audio_channels, f->audio_tracks.at(i).audio_layout); + tooltip += Footage::get_channel_layout_name(f->audio_tracks.at(i).audio_channels, f->audio_tracks.at(i).audio_layout); } // tooltip += "\n"; } @@ -216,7 +194,7 @@ void Media::update_tooltip(const QString& error) { QString::number(s->height), QString::number(s->frame_rate), QString::number(s->audio_frequency), - get_channel_layout_name(av_get_channel_layout_nb_channels(s->audio_layout), s->audio_layout) + Footage::get_channel_layout_name(av_get_channel_layout_nb_channels(s->audio_layout), s->audio_layout) ); } break; @@ -288,7 +266,7 @@ bool Media::setData(int col, const QVariant &value) { if (col == 0) { QString n = value.toString(); if (!n.isEmpty() && get_name() != n) { - olive::UndoStack.push(new MediaRename(this, value.toString())); + olive::undo_stack.push(new MediaRename(this, value.toString())); return true; } } @@ -310,7 +288,7 @@ int Media::columnCount() const { QString Media::GetStringDuration() { if (get_type() == MEDIA_TYPE_SEQUENCE) { Sequence* s = to_sequence().get(); - return frame_to_timecode(s->GetEndFrame(), olive::CurrentConfig.timecode_view, s->frame_rate); + return frame_to_timecode(s->GetEndFrame(), olive::config.timecode_view, s->frame_rate); } if (get_type() == MEDIA_TYPE_FOOTAGE) { Footage* f = to_footage(); @@ -320,7 +298,7 @@ QString Media::GetStringDuration() { r = f->video_tracks.at(0).video_frame_rate * f->speed; long len = f->get_length_in_frames(r); - if (len > 0) return frame_to_timecode(len, olive::CurrentConfig.timecode_view, r); + if (len > 0) return frame_to_timecode(len, olive::config.timecode_view, r); } return QString(); } diff --git a/project/previewgenerator.cpp b/project/previewgenerator.cpp index 035166577..173bc1572 100644 --- a/project/previewgenerator.cpp +++ b/project/previewgenerator.cpp @@ -218,8 +218,9 @@ void PreviewGenerator::finalize_media() { media_->update_tooltip(); } - if (olive::ActiveSequence != nullptr) { - olive::ActiveSequence->RefreshClips(media_); + QVector all_sequences = olive::project_model.GetAllSequences(); + for (int i=0;ito_sequence()->RefreshClipsUsingMedia(media_); } } } @@ -258,8 +259,8 @@ void PreviewGenerator::generate_waveform() { // we only generate previews for video and audio // and only if the thumbnail and waveform sizes are > 0 - if ((fmt_ctx_->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && olive::CurrentConfig.thumbnail_resolution > 0) - || (fmt_ctx_->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && olive::CurrentConfig.waveform_resolution > 0)) { + if ((fmt_ctx_->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && olive::config.thumbnail_resolution > 0) + || (fmt_ctx_->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && olive::config.waveform_resolution > 0)) { AVCodec* codec = avcodec_find_decoder(fmt_ctx_->streams[i]->codecpar->codec_id); if (codec != nullptr) { @@ -332,7 +333,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 = olive::CurrentConfig.thumbnail_resolution; + int dstH = olive::config.thumbnail_resolution; int dstW = qRound(dstH * (float(temp_frame->width)/float(temp_frame->height))); sws_ctx = sws_getContext( @@ -401,7 +402,7 @@ void PreviewGenerator::generate_waveform() { // `config.waveform_resolution` determines how many samples per second are stored in waveform. // `sample_rate` is samples per second, so `interval` is how many samples are averaged in // each "point" of the waveform - int interval = qFloor((temp_frame->sample_rate/olive::CurrentConfig.waveform_resolution)/4)*4; + int interval = qFloor((temp_frame->sample_rate/olive::config.waveform_resolution)/4)*4; // get the amount of bytes in an audio sample int sample_size = av_get_bytes_per_sample(static_cast(swr_frame->format)); diff --git a/project/projectfunctions.cpp b/project/projectfunctions.cpp index 5d9b8c486..9c36836c2 100644 --- a/project/projectfunctions.cpp +++ b/project/projectfunctions.cpp @@ -21,11 +21,11 @@ SequencePtr olive::project::CreateSequenceFromMedia(QVectorname = olive::project_model.GetNextSequenceName(); // Retrieve default Sequence settings from Config - s->width = olive::CurrentConfig.default_sequence_width; - s->height = olive::CurrentConfig.default_sequence_height; - s->frame_rate = olive::CurrentConfig.default_sequence_framerate; - s->audio_frequency = olive::CurrentConfig.default_sequence_audio_frequency; - s->audio_layout = olive::CurrentConfig.default_sequence_audio_channel_layout; + s->width = olive::config.default_sequence_width; + s->height = olive::config.default_sequence_height; + s->frame_rate = olive::config.default_sequence_framerate; + s->audio_frequency = olive::config.default_sequence_audio_frequency; + s->audio_layout = olive::config.default_sequence_audio_channel_layout; bool got_video_values = false; bool got_audio_values = false; diff --git a/project/projectmodel.cpp b/project/projectmodel.cpp index 001a35362..234abf6be 100644 --- a/project/projectmodel.cpp +++ b/project/projectmodel.cpp @@ -20,11 +20,18 @@ #include "projectmodel.h" +#include + #include "panels/panels.h" #include "panels/viewer.h" #include "ui/viewerwidget.h" +#include "ui/mainwindow.h" #include "project/media.h" #include "global/debug.h" +#include "global/config.h" +#include "global/global.h" +#include "projectfunctions.h" +#include "previewgenerator.h" ProjectModel olive::project_model; @@ -297,18 +304,14 @@ MediaPtr ProjectModel::CreateSequence(ComboAction *ca, SequencePtr s, bool open, ca->append(new AddMediaCommand(item, parent)); - if (open) { - ca->append(new ChangeSequenceAction(s)); - } - } else { appendChild(parent, item); - if (open) { - olive::Global->set_sequence(s); - } + } + if (open) { + Timeline::OpenSequence(s); } return item; @@ -404,7 +407,7 @@ void ProjectModel::process_file_list(QStringList& files, bool recursive, MediaPt bool imported = false; // retrieve the array of image formats from the user's configuration - QStringList image_sequence_formats = olive::CurrentConfig.img_seq_formats.split("|"); + QStringList image_sequence_formats = olive::config.img_seq_formats.split("|"); // a cache of image sequence formatted URLS to assist the user in importing image sequences QVector image_sequence_urls; @@ -422,8 +425,8 @@ void ProjectModel::process_file_list(QStringList& files, bool recursive, MediaPt // If this file is a directory, we'll recursively call this function again to process the directory's contents if (QFileInfo(files.at(i)).isDir()) { - QString folder_name = get_file_name_from_path(files.at(i)); - MediaPtr folder = CreateFolder(folder_name); + QString folder_name = QFileInfo(files.at(i)).fileName(); + MediaPtr folder = olive::project::CreateFolder(folder_name); QDir directory(files.at(i)); directory.setFilter(QDir::NoDotAndDotDot | QDir::AllEntries); @@ -452,7 +455,7 @@ void ProjectModel::process_file_list(QStringList& files, bool recursive, MediaPt if (file.endsWith(".ove", Qt::CaseInsensitive)) { // This file is an Olive project file. Ask the user if they really want to import it. - if (QMessageBox::question(this, + if (QMessageBox::question(olive::MainWindow, tr("Import a Project"), tr("\"%1\" is an Olive project file. It will merge with this project. " "Do you wish to continue?").arg(file), @@ -556,7 +559,7 @@ void ProjectModel::process_file_list(QStringList& files, bool recursive, MediaPt image_sequence_urls.append(new_filename); // This does look like an image sequence, let's ask the user if it'll indeed be an image sequence - if (QMessageBox::question(this, + if (QMessageBox::question(olive::MainWindow, tr("Image sequence detected"), tr("The file '%1' appears to be part of an image sequence. " "Would you like to import it as such?").arg(file), @@ -640,7 +643,7 @@ void ProjectModel::process_file_list(QStringList& files, bool recursive, MediaPt } if (create_undo_action) { if (imported) { - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); for (int i=0;i ProjectModel::GetLastImportedMedia() +{ + return last_imported_media; +} diff --git a/project/savethread.cpp b/project/savethread.cpp index 8fcca1753..380f03be1 100644 --- a/project/savethread.cpp +++ b/project/savethread.cpp @@ -9,11 +9,12 @@ #include "global/config.h" #include "projectmodel.h" +/* void RecursiveSave() { } -void Project::save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only, const QModelIndex& parent) { +void save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only, const QModelIndex& parent) { for (int i=0;iadd_recent_project(olive::ActiveProjectFilename); olive::Global->set_modified(false); } } diff --git a/project/sourcescommon.cpp b/project/sourcescommon.cpp index f140cf764..b94daab3d 100644 --- a/project/sourcescommon.cpp +++ b/project/sourcescommon.cpp @@ -68,12 +68,11 @@ void SourcesCommon::create_seq_from_selected() { ComboAction* ca = new ComboAction(); SequencePtr s = olive::project::CreateSequenceFromMedia(media_list); - // add clips to it - panel_timeline->create_ghosts_from_media(s.get(), 0, media_list); - panel_timeline->add_clips_from_ghosts(ca, s.get()); + // add clips to it + s->AddClipsFromGhosts(ca, olive::timeline::CreateGhostsFromMedia(s.get(), 0, media_list)); olive::project_model.CreateSequence(ca, s, true, nullptr); - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); } } @@ -245,14 +244,14 @@ void SourcesCommon::replace_media(MediaPtr item, QString filename) { if (filename.isEmpty()) { filename = QFileDialog::getOpenFileName( - this, + olive::MainWindow, tr("Replace '%1'").arg(item->get_name()), "", tr("All Files") + " (*)"); } if (!filename.isEmpty()) { ReplaceMediaCommand* rmc = new ReplaceMediaCommand(item, filename); - olive::UndoStack.push(rmc); + olive::undo_stack.push(rmc); } } @@ -276,7 +275,7 @@ void SourcesCommon::mouseDoubleClickEvent(const QModelIndexList& selected_items) } else if (selected_items.size() == 1) { Media* media = project_parent->item_to_media(selected_items.at(0)); if (media->get_type() == MEDIA_TYPE_SEQUENCE) { - olive::UndoStack.push(new ChangeSequenceAction(media->to_sequence())); + Timeline::OpenSequence(media->to_sequence()); } else { OpenSelectedMediaInMediaViewer(project_parent->item_to_media(selected_items.at(0))); } @@ -302,7 +301,7 @@ void SourcesCommon::dropEvent(QWidget* parent, && drop_item.isValid() && m->get_type() == MEDIA_TYPE_FOOTAGE && !QFileInfo(paths.at(0)).isDir() - && olive::CurrentConfig.drop_on_media_to_replace + && olive::config.drop_on_media_to_replace && QMessageBox::question( parent, tr("Replace Media"), @@ -320,7 +319,7 @@ void SourcesCommon::dropEvent(QWidget* parent, parent = drop_item.parent(); } } - olive::project_model.process_file_list(paths, false, nullptr, panel_project->item_to_media(parent)); + olive::project_model.process_file_list(paths, false, nullptr, project_parent->item_to_media(parent)); } } event->acceptProposedAction(); @@ -359,7 +358,7 @@ void SourcesCommon::dropEvent(QWidget* parent, MediaMove* mm = new MediaMove(); mm->to = m.get(); mm->items = move_items; - olive::UndoStack.push(mm); + olive::undo_stack.push(mm); } } } @@ -403,7 +402,7 @@ void SourcesCommon::rename_interval() { void SourcesCommon::item_renamed(Media* item) { if (editing_item == item) { MediaRename* mr = new MediaRename(item, "idk"); - olive::UndoStack.push(mr); + olive::undo_stack.push(mr); editing_item = nullptr; } } @@ -447,9 +446,10 @@ void SourcesCommon::clear_proxies_from_selected() { f->proxy_path.clear(); } - if (olive::ActiveSequence != nullptr) { + QVector all_sequences = olive::project_model.GetAllSequences(); + for (int i=0;iClose(); + all_sequences.at(i)->to_sequence()->Close(); } // delete proxies requested to be deleted @@ -457,7 +457,7 @@ void SourcesCommon::clear_proxies_from_selected() { QFile::remove(delete_list.at(i)); } - if (olive::ActiveSequence != nullptr) { + if (panel_sequence_viewer->seq != nullptr) { // update viewer (will re-open active clips with original media) panel_sequence_viewer->viewer_widget()->frame_update(); } diff --git a/rendering/audio.cpp b/rendering/audio.cpp index e535d533a..e5a7c0747 100644 --- a/rendering/audio.cpp +++ b/rendering/audio.cpp @@ -69,7 +69,7 @@ QAudioDeviceInfo get_audio_device(QAudio::Mode mode) { QList devs = QAudioDeviceInfo::availableDevices(mode); // try to retrieve preferred device from config - QString preferred_device = (mode == QAudio::AudioOutput) ? olive::CurrentConfig.preferred_audio_output : olive::CurrentConfig.preferred_audio_input; + QString preferred_device = (mode == QAudio::AudioOutput) ? olive::config.preferred_audio_output : olive::config.preferred_audio_input; if (!preferred_device.isEmpty()) { for (int i=0;iaudio_monitor->set_value(averages); + panel_timeline.first()->audio_monitor->set_value(averages); } memset(audio_ibuffer+offset, 0, actual_write); @@ -324,8 +324,7 @@ void write_wave_trailer(QFile& f) { } bool start_recording() { - if (olive::ActiveSequence == nullptr) { - qCritical() << "No active sequence to record into"; + if (!olive::Global->CheckForActiveSequence(true)) { return false; } @@ -355,8 +354,8 @@ bool start_recording() { } QAudioFormat audio_format = audio_output->format(); - if (olive::CurrentConfig.recording_mode != audio_format.channelCount()) { - audio_format.setChannelCount(olive::CurrentConfig.recording_mode); + if (olive::config.recording_mode != audio_format.channelCount()) { + audio_format.setChannelCount(olive::config.recording_mode); } QAudioDeviceInfo info = get_audio_device(QAudio::AudioInput); diff --git a/rendering/cacher.cpp b/rendering/cacher.cpp index f85cf15a4..8832355c0 100644 --- a/rendering/cacher.cpp +++ b/rendering/cacher.cpp @@ -65,8 +65,8 @@ void apply_audio_effects(Clip* clip, double timecode_start, AVFrame* frame, int } if (clip->opening_transition != nullptr) { if (clip->media() != nullptr && clip->media()->get_type() == MEDIA_TYPE_FOOTAGE) { - double transition_start = (clip->clip_in(true) / clip->sequence->frame_rate); - double transition_end = (clip->clip_in(true) + clip->opening_transition->get_length()) / clip->sequence->frame_rate; + double transition_start = (clip->clip_in(true) / clip->track()->sequence()->frame_rate); + double transition_end = (clip->clip_in(true) + clip->opening_transition->get_length()) / clip->track()->sequence()->frame_rate; if (timecode_end < transition_end) { double adjustment = transition_end - transition_start; double adjusted_range_start = (timecode_start - transition_start) / adjustment; @@ -78,8 +78,8 @@ void apply_audio_effects(Clip* clip, double timecode_start, AVFrame* frame, int if (clip->closing_transition != nullptr) { if (clip->media() != nullptr && clip->media()->get_type() == MEDIA_TYPE_FOOTAGE) { long length_with_transitions = clip->timeline_out(true) - clip->timeline_in(true); - double transition_start = (clip->clip_in(true) + length_with_transitions - clip->closing_transition->get_length()) / clip->sequence->frame_rate; - double transition_end = (clip->clip_in(true) + length_with_transitions) / clip->sequence->frame_rate; + double transition_start = (clip->clip_in(true) + length_with_transitions - clip->closing_transition->get_length()) / clip->track()->sequence()->frame_rate; + double transition_end = (clip->clip_in(true) + length_with_transitions) / clip->track()->sequence()->frame_rate; if (timecode_start > transition_start) { double adjustment = transition_end - transition_start; double adjusted_range_start = (timecode_start - transition_start) / adjustment; @@ -93,7 +93,7 @@ void apply_audio_effects(Clip* clip, double timecode_start, AVFrame* frame, int Clip* next_nest = nests.last(); nests.removeLast(); apply_audio_effects(next_nest, - timecode_start + (double(clip->timeline_in(true)-clip->clip_in(true))/clip->sequence->frame_rate), + timecode_start + (double(clip->timeline_in(true)-clip->clip_in(true))/clip->track()->sequence()->frame_rate), frame, nb_bytes, nests); @@ -122,16 +122,16 @@ void Cacher::CacheAudioWorker() { bool reverse_audio = IsReversed(); long frame_skip = 0; - double last_fr = clip->sequence->frame_rate; + double last_fr = clip->track()->sequence()->frame_rate; if (!nests_.isEmpty()) { for (int i=nests_.size()-1;i>=0;i--) { - timeline_in = rescale_frame_number(timeline_in, last_fr, nests_.at(i)->sequence->frame_rate) + nests_.at(i)->timeline_in(true) - nests_.at(i)->clip_in(true); - timeline_out = rescale_frame_number(timeline_out, last_fr, nests_.at(i)->sequence->frame_rate) + nests_.at(i)->timeline_in(true) - nests_.at(i)->clip_in(true); - target_frame = rescale_frame_number(target_frame, last_fr, nests_.at(i)->sequence->frame_rate) + nests_.at(i)->timeline_in(true) - nests_.at(i)->clip_in(true); + timeline_in = rescale_frame_number(timeline_in, last_fr, nests_.at(i)->track()->sequence()->frame_rate) + nests_.at(i)->timeline_in(true) - nests_.at(i)->clip_in(true); + timeline_out = rescale_frame_number(timeline_out, last_fr, nests_.at(i)->track()->sequence()->frame_rate) + nests_.at(i)->timeline_in(true) - nests_.at(i)->clip_in(true); + target_frame = rescale_frame_number(target_frame, last_fr, nests_.at(i)->track()->sequence()->frame_rate) + nests_.at(i)->timeline_in(true) - nests_.at(i)->clip_in(true); timeline_out = qMin(timeline_out, nests_.at(i)->timeline_out(true)); - frame_skip = rescale_frame_number(frame_skip, last_fr, nests_.at(i)->sequence->frame_rate); + frame_skip = rescale_frame_number(frame_skip, last_fr, nests_.at(i)->track()->sequence()->frame_rate); long validator = nests_.at(i)->timeline_in(true) - timeline_in; if (validator > 0) { @@ -139,12 +139,13 @@ void Cacher::CacheAudioWorker() { //timeline_in = nests_.at(i)->timeline_in(true); } - last_fr = nests_.at(i)->sequence->frame_rate; + last_fr = nests_.at(i)->track()->sequence()->frame_rate; } } if (temp_reverse) { - long seq_end = olive::ActiveSequence->GetEndFrame(); + // FIXME breakable? + long seq_end = Timeline::GetTopSequence()->GetEndFrame(); timeline_in = seq_end - timeline_in; timeline_out = seq_end - timeline_out; target_frame = seq_end - target_frame; @@ -394,7 +395,7 @@ void Cacher::CacheAudioWorker() { // apply any audio effects to the data if (nb_bytes == INT_MAX) nb_bytes = frame->nb_samples * av_get_bytes_per_sample(static_cast(frame->format)) * frame->channels; if (new_frame) { - apply_audio_effects(clip, bytes_to_seconds(audio_buffer_write, 2, current_audio_freq()) + audio_ibuffer_timecode + ((double)clip->clip_in(true)/clip->sequence->frame_rate) - ((double)timeline_in/last_fr), frame, nb_bytes, nests_); + apply_audio_effects(clip, bytes_to_seconds(audio_buffer_write, 2, current_audio_freq()) + audio_ibuffer_timecode + ((double)clip->clip_in(true)/clip->track()->sequence()->frame_rate) - ((double)timeline_in/last_fr), frame, nb_bytes, nests_); } } @@ -402,7 +403,7 @@ void Cacher::CacheAudioWorker() { if (frame->nb_samples == 0) { break; } else { - qint64 buffer_timeline_out = get_buffer_offset_from_frame(clip->sequence->frame_rate, timeline_out); + qint64 buffer_timeline_out = get_buffer_offset_from_frame(clip->track()->sequence()->frame_rate, timeline_out); audio_write_lock.lock(); @@ -597,15 +598,15 @@ void Cacher::CacheVideoWorker() { // For reversed playback, we flip the queue stats as "upcoming" frames are going to be played before the "previous" // frames now if (reversed) { - previous_queue_type = olive::CurrentConfig.upcoming_queue_type; - previous_queue_size = olive::CurrentConfig.upcoming_queue_size; - upcoming_queue_type = olive::CurrentConfig.previous_queue_type; - upcoming_queue_size = olive::CurrentConfig.previous_queue_size; + previous_queue_type = olive::config.upcoming_queue_type; + previous_queue_size = olive::config.upcoming_queue_size; + upcoming_queue_type = olive::config.previous_queue_type; + upcoming_queue_size = olive::config.previous_queue_size; } else { - previous_queue_type = olive::CurrentConfig.previous_queue_type; - previous_queue_size = olive::CurrentConfig.previous_queue_size; - upcoming_queue_type = olive::CurrentConfig.upcoming_queue_type; - upcoming_queue_size = olive::CurrentConfig.upcoming_queue_size; + previous_queue_type = olive::config.previous_queue_type; + previous_queue_size = olive::config.previous_queue_size; + upcoming_queue_type = olive::config.upcoming_queue_type; + upcoming_queue_size = olive::config.upcoming_queue_size; } // Determine "previous" queue statistics @@ -794,7 +795,7 @@ void Cacher::CacheVideoWorker() { void Cacher::Reset() { // if we seek to a whole other place in the timeline, we'll need to reset the cache with new values if (clip->media() == nullptr) { - if (clip->track() >= 0) { + if (clip->type() == Track::kTypeAudio) { // a null-media audio clip is usually an auto-generated sound clip such as Tone or Noise reached_end = false; audio_target_frame = playhead_; @@ -860,7 +861,7 @@ Cacher::Cacher(Clip* c) : void Cacher::OpenWorker() { // set some defaults for the audio cacher - if (clip->track() >= 0) { + if (clip->type() == Track::kTypeAudio) { audio_reset_ = false; frame_sample_index_ = -1; audio_buffer_write = 0; @@ -868,10 +869,10 @@ void Cacher::OpenWorker() { reached_end = false; if (clip->media() == nullptr) { - if (clip->track() >= 0) { + if (clip->type() == Track::kTypeAudio) { frame_ = av_frame_alloc(); frame_->format = kDestSampleFmt; - frame_->channel_layout = clip->sequence->audio_layout; + frame_->channel_layout = clip->track()->sequence()->audio_layout; frame_->channels = av_get_channel_layout_nb_channels(frame_->channel_layout); frame_->sample_rate = current_audio_freq(); frame_->nb_samples = 2048; @@ -889,7 +890,7 @@ void Cacher::OpenWorker() { QByteArray ba; // do we have a proxy? - if ((!olive::Global->is_exporting() || !olive::CurrentConfig.dont_use_proxies_on_export) + if ((!olive::Global->is_exporting() || !olive::config.dont_use_proxies_on_export) && m->proxy && !m->proxy_path.isEmpty() && QFileInfo::exists(m->proxy_path)) { @@ -1029,8 +1030,8 @@ void Cacher::OpenWorker() { reverse_frame->format = kDestSampleFmt; reverse_frame->nb_samples = current_audio_freq()*10; - reverse_frame->channel_layout = clip->sequence->audio_layout; - reverse_frame->channels = av_get_channel_layout_nb_channels(clip->sequence->audio_layout); + reverse_frame->channel_layout = clip->track()->sequence()->audio_layout; + reverse_frame->channels = av_get_channel_layout_nb_channels(clip->track()->sequence()->audio_layout); av_frame_get_buffer(reverse_frame, 0); queue_.append(reverse_frame); @@ -1116,7 +1117,7 @@ void Cacher::OpenWorker() { } void Cacher::CacheWorker() { - if (clip->track() < 0) { + if (clip->type() == Track::kTypeVideo) { // clip is a video track, start caching video CacheVideoWorker(); } else { @@ -1207,7 +1208,7 @@ void Cacher::Open() caching_ = true; queued_ = false; - start((clip->track() < 0) ? QThread::HighPriority : QThread::TimeCriticalPriority); + start((clip->type() == Track::kTypeVideo) ? QThread::HighPriority : QThread::TimeCriticalPriority); } void Cacher::Cache(long playhead, bool scrubbing, QVector& nests, int playback_speed) diff --git a/rendering/exportthread.cpp b/rendering/exportthread.cpp index 30079f737..9bb58ed51 100644 --- a/rendering/exportthread.cpp +++ b/rendering/exportthread.cpp @@ -34,7 +34,6 @@ extern "C" { #include #include "global/global.h" -#include "timeline/sequence.h" #include "panels/panels.h" #include "ui/viewerwidget.h" #include "rendering/renderthread.h" @@ -192,16 +191,16 @@ bool ExportThread::SetupVideo() { video_frame = av_frame_alloc(); av_frame_make_writable(video_frame); video_frame->format = AV_PIX_FMT_RGBA; - video_frame->width = olive::ActiveSequence->width; - video_frame->height = olive::ActiveSequence->height; + video_frame->width = params_.sequence->width; + video_frame->height = params_.sequence->height; av_frame_get_buffer(video_frame, 0); av_init_packet(&video_pkt); // Set up conversion context sws_ctx = sws_getContext( - olive::ActiveSequence->width, - olive::ActiveSequence->height, + params_.sequence->width, + params_.sequence->height, AV_PIX_FMT_RGBA, params_.video_width, params_.video_height, @@ -288,7 +287,7 @@ bool ExportThread::SetupAudio() { acodec_ctx->channel_layout, acodec_ctx->sample_fmt, acodec_ctx->sample_rate, - olive::ActiveSequence->audio_layout, + params_.sequence->audio_layout, AV_SAMPLE_FMT_S16, acodec_ctx->sample_rate, 0, @@ -417,7 +416,7 @@ void ExportThread::Export() mutex.lock(); // Loop from now (set to the beginning frame earlier) to the end of the frame - while (olive::ActiveSequence->playhead <= params_.end_frame && !interrupt_) { + while (params_.sequence->playhead <= params_.end_frame && !interrupt_) { // Start timing how long this frame will take frame_start_time = QDateTime::currentMSecsSinceEpoch(); @@ -426,14 +425,14 @@ void ExportThread::Export() if (params_.audio_enabled) { waiting_for_audio_ = true; SetAudioWakeObject(this); - olive::rendering::compose_audio(nullptr, olive::ActiveSequence.get(), 1, true); + olive::rendering::compose_audio(nullptr, params_.sequence, 1, true); } // If we're exporting video, trigger a render on the RenderThread if (params_.video_enabled) { do { // TODO optimize by rendering the next frame while encoding the last - renderer->start_render(nullptr, olive::ActiveSequence.get(), 1, nullptr, video_frame->data[0], video_frame->linesize[0]/4); + renderer->start_render(nullptr, params_.sequence, 1, nullptr, video_frame->data[0], video_frame->linesize[0]/4); // Wait for RenderThread to return waitCond.wait(&mutex); @@ -452,7 +451,7 @@ void ExportThread::Export() } // Get the current sequence playhead in seconds (used for timestamp calculations later on) - double timecode_secs = double(olive::ActiveSequence->playhead - params_.start_frame) / olive::ActiveSequence->frame_rate; + double timecode_secs = double(params_.sequence->playhead - params_.start_frame) / params_.sequence->frame_rate; // If we're exporting video, construct an AVFrame in the destination codec's pixel format to convert the raw RGBA // OpenGL buffer to @@ -538,15 +537,15 @@ void ExportThread::Export() // Generating encoding statistics (e.g. the time it took to encode this frame/estimated remaining time) frame_time = (QDateTime::currentMSecsSinceEpoch()-frame_start_time); total_time += frame_time; - remaining_frames = (params_.end_frame - olive::ActiveSequence->playhead); + remaining_frames = (params_.end_frame - params_.sequence->playhead); avg_time = (total_time/frame_count); eta = (remaining_frames*avg_time); // Emit a signal for the percent of the sequence that's been encoded so far - emit ProgressChanged(qRound((double(olive::ActiveSequence->playhead - params_.start_frame) / double(params_.end_frame - params_.start_frame)) * 100.0), eta); + emit ProgressChanged(qRound((double(params_.sequence->playhead - params_.start_frame) / double(params_.end_frame - params_.start_frame)) * 100.0), eta); // Increment sequence playhead - olive::ActiveSequence->playhead++; + params_.sequence->playhead++; // Increment frame count (used for generating encoding statistics above) frame_count++; diff --git a/rendering/exportthread.h b/rendering/exportthread.h index 7c52e84f0..6180ec4e6 100644 --- a/rendering/exportthread.h +++ b/rendering/exportthread.h @@ -21,11 +21,17 @@ #ifndef EXPORTTHREAD_H #define EXPORTTHREAD_H +extern "C" { +#include +} + #include #include #include #include +#include "timeline/sequence.h" + struct AVFormatContext; struct AVCodecContext; struct AVFrame; @@ -35,19 +41,19 @@ struct AVCodec; struct SwsContext; struct SwrContext; -extern "C" { -#include -} - -#define COMPRESSION_TYPE_CBR 0 -#define COMPRESSION_TYPE_CFR 1 -#define COMPRESSION_TYPE_TARGETSIZE 2 -#define COMPRESSION_TYPE_TARGETBR 3 +enum CompressionType { + COMPRESSION_TYPE_CBR, + COMPRESSION_TYPE_CFR, + COMPRESSION_TYPE_TARGETSIZE, + COMPRESSION_TYPE_TARGETBR +}; // structs that store parameters passed from the export dialogs to this thread struct ExportParams { + // export parameters + Sequence* sequence; QString filename; bool video_enabled; int video_codec; diff --git a/rendering/framebufferobject.cpp b/rendering/framebufferobject.cpp index 876b01f08..153c6f7eb 100644 --- a/rendering/framebufferobject.cpp +++ b/rendering/framebufferobject.cpp @@ -68,8 +68,8 @@ void FramebufferObject::Create(QOpenGLContext *ctx, int width, int height) // allocate storage for texture const olive::PixelFormatInfo& bit_depth = olive::pixel_formats.at(olive::Global->is_exporting() ? - olive::CurrentConfig.export_bit_depth : - olive::CurrentConfig.playback_bit_depth); + olive::config.export_bit_depth : + olive::config.playback_bit_depth); ctx->functions()->glTexImage2D( GL_TEXTURE_2D, diff --git a/rendering/renderfunctions.cpp b/rendering/renderfunctions.cpp index 8a8fe5a63..719554479 100644 --- a/rendering/renderfunctions.cpp +++ b/rendering/renderfunctions.cpp @@ -187,7 +187,7 @@ void process_effect(QOpenGLContext* ctx, if (e->Flags() & Effect::CoordsFlag) { e->process_coords(timecode, coords, data); } - bool can_process_shaders = ((e->Flags() & Effect::ShaderFlag) && olive::CurrentRuntimeConfig.shaders_are_enabled); + bool can_process_shaders = ((e->Flags() & Effect::ShaderFlag) && olive::runtime_config.shaders_are_enabled); if (can_process_shaders || (e->Flags() & Effect::SuperimposeFlag)) { if (!e->is_open()) { @@ -227,7 +227,7 @@ void process_effect(QOpenGLContext* ctx, } GLuint olive::rendering::compose_sequence(ComposeSequenceParams ¶ms) { - GLuint final_fbo = params.video ? params.main_buffer->buffer() : 0; + GLuint final_fbo = params.type == Track::kTypeVideo ? params.main_buffer->buffer() : 0; Sequence* s = params.seq; long playhead = s->playhead; @@ -237,10 +237,10 @@ GLuint olive::rendering::compose_sequence(ComposeSequenceParams ¶ms) { for (int i=0;imedia()->to_sequence().get(); playhead += params.nests.at(i)->clip_in(true) - params.nests.at(i)->timeline_in(true); - playhead = rescale_frame_number(playhead, params.nests.at(i)->sequence->frame_rate, s->frame_rate); + playhead = rescale_frame_number(playhead, params.nests.at(i)->track()->sequence()->frame_rate, s->frame_rate); } - if (params.video && !params.nests.last()->fbo.isEmpty()) { + if (params.type == Track::kTypeVideo && !params.nests.last()->fbo.isEmpty()) { params.nests.last()->fbo.at(0).BindBuffer(); params.ctx->functions()->glClear(GL_COLOR_BUFFER_BIT); final_fbo = params.nests.last()->fbo.at(0).buffer(); @@ -253,14 +253,15 @@ GLuint olive::rendering::compose_sequence(ComposeSequenceParams ¶ms) { QVector current_clips; // loop through clips, find currently active, and sort by track - for (int i=0;iclips.size();i++) { + QVector sequence_clips = s->GetAllClips(); + for (int i=0;iclips.at(i).get(); + Clip* c = sequence_clips.at(i); if (c != nullptr) { // if clip is video and we're processing video - if ((c->track() < 0) == params.video) { + if (c->type() == params.type) { bool clip_is_active = false; @@ -269,7 +270,7 @@ GLuint olive::rendering::compose_sequence(ComposeSequenceParams ¶ms) { Footage* m = c->media()->to_footage(); // does the clip have a valid media source? - if (!m->invalid && !(c->track() >= 0 && !is_audio_device_set())) { + if (!m->invalid && !(c->type() == Track::kTypeAudio && !is_audio_device_set())) { // is the media process and ready? if (m->ready) { @@ -286,7 +287,7 @@ GLuint olive::rendering::compose_sequence(ComposeSequenceParams ¶ms) { clip_is_active = true; // increment audio track count - if (c->track() >= 0) audio_track_count++; + if (c->type() == Track::kTypeAudio) audio_track_count++; } else if (c->IsOpen()) { @@ -320,7 +321,7 @@ GLuint olive::rendering::compose_sequence(ComposeSequenceParams ¶ms) { // track sorting is only necessary for video clips // audio clips are mixed equally, so we skip sorting for those - if (params.video) { + if (params.type == Track::kTypeVideo) { // insertion sort by track for (int j=0;jfunctions()->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); @@ -444,7 +445,7 @@ GLuint olive::rendering::compose_sequence(ComposeSequenceParams ¶ms) { } else if (c->media()->get_type() == MEDIA_TYPE_FOOTAGE) { // Convert frame from source to linear colorspace - if (olive::CurrentConfig.enable_color_management) + if (olive::config.enable_color_management) { // Convert texture to sequence's internal format @@ -794,7 +795,7 @@ void olive::rendering::compose_audio(Viewer* viewer, Sequence* seq, int playback params.viewer = viewer; params.ctx = nullptr; params.seq = seq; - params.video = false; + params.type = Track::kTypeAudio; params.gizmos = nullptr; params.wait_for_mutexes = wait_for_mutexes; params.playback_speed = playback_speed; diff --git a/rendering/renderfunctions.h b/rendering/renderfunctions.h index 228608762..e38ee8bb6 100644 --- a/rendering/renderfunctions.h +++ b/rendering/renderfunctions.h @@ -80,9 +80,9 @@ struct ComposeSequenceParams { /** * @brief Set compose mode to video or audio * - * **TRUE** if this function should render video, **FALSE** if this function should render audio. + * Accepts Track::kTypeVideo to render video, Track::kTypeAudio if this function should render audio. */ - bool video; + Track::Type type; /** * @brief Set to the Effect whose gizmos were chosen to be drawn on screen diff --git a/rendering/renderthread.cpp b/rendering/renderthread.cpp index 352224d36..c92b323bd 100644 --- a/rendering/renderthread.cpp +++ b/rendering/renderthread.cpp @@ -116,7 +116,7 @@ void RenderThread::run() { } // If there's no OpenColorIO shader or the configuration has changed, (re-)create it now - if (olive::CurrentConfig.enable_color_management && ocio_shader == nullptr) { + if (olive::config.enable_color_management && ocio_shader == nullptr) { destroy_ocio(); set_up_ocio(); @@ -155,12 +155,12 @@ void RenderThread::set_up_ocio() OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig(); // Get current OCIO display from Config (or defaults if there is no setting) - QString display = olive::CurrentConfig.ocio_display; + QString display = olive::config.ocio_display; if (display.isEmpty()) { display = config->getDefaultDisplay(); } - QString view = olive::CurrentConfig.ocio_view; + QString view = olive::config.ocio_view; if (view.isEmpty()) { view = config->getDefaultView(display.toUtf8()); } @@ -171,8 +171,8 @@ void RenderThread::set_up_ocio() transform->setDisplay(display.toUtf8()); transform->setView(view.toUtf8()); - if (!olive::CurrentConfig.ocio_look.isEmpty()) { - transform->setLooksOverride(olive::CurrentConfig.ocio_look.toUtf8()); + if (!olive::config.ocio_look.isEmpty()) { + transform->setLooksOverride(olive::config.ocio_look.toUtf8()); transform->setLooksOverrideEnabled(true); } @@ -206,7 +206,7 @@ void RenderThread::paint() { params.viewer = nullptr; params.ctx = ctx; params.seq = seq; - params.video = true; + params.type = Track::kTypeVideo; params.texture_failed = false; params.wait_for_mutexes = true; params.playback_speed = playback_speed_; @@ -244,7 +244,7 @@ void RenderThread::paint() { // Blit the composite buffer to one of the front buffers // If we're color managing, conver the linear composited frame to display color space - if (olive::CurrentConfig.enable_color_management && ocio_shader != nullptr) { + if (olive::config.enable_color_management && ocio_shader != nullptr) { olive::rendering::OCIOBlit(ocio_shader.get(), ocio_lut_texture, diff --git a/timeline/clip.cpp b/timeline/clip.cpp index 426502b65..e1d212058 100644 --- a/timeline/clip.cpp +++ b/timeline/clip.cpp @@ -32,8 +32,8 @@ #include "timeline/sequence.h" #include "panels/timeline.h" #include "project/media.h" -#include "project/clipboard.h" #include "undo/undo.h" +#include "global/clipboard.h" #include "global/debug.h" #include "global/timing.h" @@ -46,7 +46,7 @@ Clip::Clip(Track *s) : timeline_out_(0), media_(nullptr), reverse_(false), - autoscale_(olive::CurrentConfig.autoscale_by_default), + autoscale_(olive::config.autoscale_by_default), opening_transition(nullptr), closing_transition(nullptr), undeletable(false), @@ -110,6 +110,11 @@ bool Clip::IsTransitionSelected(TransitionType type) } } +Selection Clip::ToSelection() +{ + return Selection(timeline_in(), timeline_out(), track()); +} + Track::Type Clip::type() { return track()->type(); @@ -158,6 +163,11 @@ void Clip::set_media(Media *m, int s) media_stream_ = s; } +void Clip::Move(ComboAction *ca, long iin, long iout, long iclip_in, Track *itrack, bool verify_transitions, bool relative) +{ + track()->sequence()->MoveClip(this, ca, iin, iout, iclip_in, itrack, verify_transitions, relative); +} + bool Clip::enabled() { return enabled_; @@ -168,39 +178,6 @@ void Clip::set_enabled(bool e) enabled_ = e; } -void Clip::move(ComboAction* ca, long iin, long iout, long iclip_in, int itrack, bool verify_transitions, bool relative) -{ - ca->append(new MoveClipAction(this, iin, iout, iclip_in, itrack, relative)); - - if (verify_transitions) { - - // if this is a shared transition, and the corresponding clip will be moved away somehow - if (opening_transition != nullptr - && opening_transition->secondary_clip != nullptr - && opening_transition->secondary_clip->timeline_out() != iin) { - // separate transition - ca->append(new SetPointer(reinterpret_cast(&opening_transition->secondary_clip), nullptr)); - ca->append(new AddTransitionCommand(nullptr, - opening_transition->secondary_clip, - opening_transition, - nullptr, - 0)); - } - - if (closing_transition != nullptr - && closing_transition->secondary_clip != nullptr - && closing_transition->parent_clip->timeline_in() != iout) { - // separate transition - ca->append(new SetPointer(reinterpret_cast(&closing_transition->secondary_clip), nullptr)); - ca->append(new AddTransitionCommand(nullptr, - this, - closing_transition, - nullptr, - 0)); - } - } -} - void Clip::reset_audio() { if (UsesCacher()) { cacher.ResetAudio(); @@ -260,6 +237,9 @@ Clip::~Clip() { void Clip::Save(QXmlStreamWriter &stream) { + stream.writeStartElement("clip"); + stream.writeAttribute("id", QString::number(load_id)); + stream.writeAttribute("enabled", QString::number(enabled())); stream.writeAttribute("name", name()); stream.writeAttribute("clipin", QString::number(clip_in())); @@ -312,21 +292,17 @@ void Clip::Save(QXmlStreamWriter &stream) if (transition != nullptr) { stream.writeStartElement((t == kTransitionOpening) ? "opening" : "closing"); - // check if this is a shared transition and the transition has already been saved - int transition_cache_index = transition_save_cache.indexOf(transition); - - if (transition_cache_index > -1) { + // check if this is a shared transition + if (this == transition->secondary_clip) { // if so, just save a reference to the other clip stream.writeAttribute("shared", - QString::number(transition_clip_save_cache.at(transition_cache_index))); + QString::number(transition->parent_clip->load_id)); } else { // otherwise save the whole transition transition->save(stream); - transition_save_cache.append(transition); - transition_clip_save_cache.append(j); } - stream.writeEndElement(); // opening + stream.writeEndElement(); // opening/closing } } @@ -336,7 +312,7 @@ void Clip::Save(QXmlStreamWriter &stream) stream.writeEndElement(); // effect } - + stream.writeEndElement(); // clip } long Clip::clip_in(bool with_transition) { @@ -441,6 +417,15 @@ Track *Clip::track() void Clip::set_track(Track *t) { + // Ensure this clip has already been added to this track + bool found = false; + for (int i=0;iClipCount();i++) { + if (t->GetClip(i).get() == this) { + found = true; + break; + } + } + track_ = t; } @@ -510,13 +495,13 @@ int Clip::media_width() { } int Clip::media_height() { - if (media_ == nullptr && sequence != nullptr) return sequence->height; + if (media_ == nullptr && track() != nullptr) return track()->sequence()->height; switch (media_->get_type()) { case MEDIA_TYPE_FOOTAGE: { const FootageStream* ms = media_stream(); if (ms != nullptr) return ms->video_height; - if (sequence != nullptr) return sequence->height; + if (track() != nullptr) return track()->sequence()->height; } break; case MEDIA_TYPE_SEQUENCE: @@ -530,11 +515,12 @@ int Clip::media_height() { void Clip::refactor_frame_rate(ComboAction* ca, double multiplier, bool change_timeline_points) { if (change_timeline_points) { - this->move(ca, - qRound(double(timeline_in_) * multiplier), - qRound(double(timeline_out_) * multiplier), - qRound(double(clip_in_) * multiplier), - track_); + track()->sequence()->MoveClip(this, + ca, + qRound(double(timeline_in_) * multiplier), + qRound(double(timeline_out_) * multiplier), + qRound(double(clip_in_) * multiplier), + track_); } // move keyframes @@ -645,79 +631,79 @@ bool Clip::Retrieve() //if (frame->pts != texture_timestamp) { - bool allocate_data = false; + bool allocate_data = false; - QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions(); + QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions(); - // check if the opengl texture exists yet, create it if not - if (texture == 0) { + // check if the opengl texture exists yet, create it if not + if (texture == 0) { - // create texture object - f->glGenTextures(1, &texture); + // create texture object + f->glGenTextures(1, &texture); - f->glBindTexture(GL_TEXTURE_2D, texture); + f->glBindTexture(GL_TEXTURE_2D, texture); - // set texture filtering to bilinear - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + // set texture filtering to bilinear + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // set texture wrapping to clamp - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + // set texture wrapping to clamp + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - // queue an allocation ahead - allocate_data = true; + // queue an allocation ahead + allocate_data = true; - } else { + } else { - f->glBindTexture(GL_TEXTURE_2D, texture); + f->glBindTexture(GL_TEXTURE_2D, texture); - } + } - int video_width = cacher.media_width(); - int video_height = cacher.media_height(); + int video_width = cacher.media_width(); + int video_height = cacher.media_height(); - const olive::PixelFormatInfo& pix_fmt_info = olive::pixel_formats.at(cacher.media_pixel_format()); + const olive::PixelFormatInfo& pix_fmt_info = olive::pixel_formats.at(cacher.media_pixel_format()); - f->glPixelStorei(GL_UNPACK_ROW_LENGTH, frame->linesize[0]/pix_fmt_info.bytes_per_pixel); + f->glPixelStorei(GL_UNPACK_ROW_LENGTH, frame->linesize[0]/pix_fmt_info.bytes_per_pixel); - if (allocate_data) { + if (allocate_data) { - // the raw frame size may differ from the one we're using (e.g. a lower resolution proxy), so we make sure - // the texture is using the correct dimensions, but then treat it as if it's the original resolution in the - // composition - f->glTexImage2D( - GL_TEXTURE_2D, - 0, - pix_fmt_info.internal_format, - video_width, - video_height, - 0, - pix_fmt_info.pixel_format, - pix_fmt_info.pixel_type, - frame->data[0] - ); + // the raw frame size may differ from the one we're using (e.g. a lower resolution proxy), so we make sure + // the texture is using the correct dimensions, but then treat it as if it's the original resolution in the + // composition + f->glTexImage2D( + GL_TEXTURE_2D, + 0, + pix_fmt_info.internal_format, + video_width, + video_height, + 0, + pix_fmt_info.pixel_format, + pix_fmt_info.pixel_type, + frame->data[0] + ); - } else { + } else { - f->glTexSubImage2D(GL_TEXTURE_2D, - 0, - 0, - 0, - video_width, - video_height, - pix_fmt_info.pixel_format, - pix_fmt_info.pixel_type, - frame->data[0] - ); + f->glTexSubImage2D(GL_TEXTURE_2D, + 0, + 0, + 0, + video_width, + video_height, + pix_fmt_info.pixel_format, + pix_fmt_info.pixel_type, + frame->data[0] + ); - } + } - f->glBindTexture(GL_TEXTURE_2D, 0); + f->glBindTexture(GL_TEXTURE_2D, 0); - f->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + f->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - texture_timestamp = frame->pts; + texture_timestamp = frame->pts; //} diff --git a/timeline/clip.h b/timeline/clip.h index 69bd75e67..9df7ec244 100644 --- a/timeline/clip.h +++ b/timeline/clip.h @@ -59,6 +59,8 @@ public: bool IsSelected(bool containing = true); bool IsTransitionSelected(TransitionType type); + Selection ToSelection(); + Track::Type type(); const QColor& color(); @@ -74,17 +76,17 @@ public: long media_length(); void set_media(Media* m, int s); - bool enabled(); - void set_enabled(bool e); - - void move(ComboAction* ca, + void Move(ComboAction* ca, long iin, long iout, long iclip_in, - int itrack, + Track *itrack, bool verify_transitions = true, bool relative = false); + bool enabled(); + void set_enabled(bool e); + long clip_in(bool with_transition = false); void set_clip_in(long c); diff --git a/timeline/ghost.cpp b/timeline/ghost.cpp new file mode 100644 index 000000000..2e9780709 --- /dev/null +++ b/timeline/ghost.cpp @@ -0,0 +1,6 @@ +#include "ghost.h" + +Selection Ghost::ToSelection() const +{ + return Selection(in, out, track); +} diff --git a/timeline/ghost.h b/timeline/ghost.h index cf89b6412..e0da417d5 100644 --- a/timeline/ghost.h +++ b/timeline/ghost.h @@ -2,11 +2,22 @@ #define GHOST_H #include "effects/transition.h" -#include "timelinefunctions.h" #include "track.h" +namespace olive { +namespace timeline { + +enum TrimType { + TRIM_NONE, + TRIM_IN, + TRIM_OUT +}; + +} +} + struct Ghost { - int clip; + Clip* clip; long in; long out; Track* track; @@ -28,6 +39,8 @@ struct Ghost { // transition trimming TransitionPtr transition; + + Selection ToSelection() const; }; #endif // GHOST_H diff --git a/timeline/marker.cpp b/timeline/marker.cpp index 18fa068b9..f4043da2c 100644 --- a/timeline/marker.cpp +++ b/timeline/marker.cpp @@ -49,22 +49,24 @@ void Marker::Draw(QPainter &p, int x, int y, int bottom, bool selected) { p.drawPolygon(points, 5); } -void set_marker_internal(Sequence* seq, const QVector& clips) { - // if clips is empty, the marker is being added to the sequence +void Marker::SetOnClips(const QVector &clips) +{ + // Don't bother if there are no clips + if (clips.isEmpty()) { + return; + } // add_marker is used to determine whether we're adding a marker, depending on whether the user input a marker name // however if (config.set_name_with_marker) is true, we don't need a marker name so we just add - bool add_marker = !olive::CurrentConfig.set_name_with_marker; + bool add_marker = !olive::config.set_name_with_marker; QString marker_name; - // if (config.set_name_with_marker) is false (set above), ask for a marker name + // if Config::set_name_with_marker is true (set above), ask for a marker name if (!add_marker) { QInputDialog d(olive::MainWindow); d.setWindowTitle(QCoreApplication::translate("Marker", "Set Marker")); - d.setLabelText(clips.size() > 0 - ? QCoreApplication::translate("Marker", "Set clip marker name:") - : QCoreApplication::translate("Marker", "Set sequence marker name:")); + d.setLabelText(QCoreApplication::translate("Marker", "Set clip marker name:")); d.setInputMode(QInputDialog::TextInput); add_marker = (d.exec() == QDialog::Accepted); marker_name = d.textValue(); @@ -75,43 +77,16 @@ void set_marker_internal(Sequence* seq, const QVector& clips) { ComboAction* ca = new ComboAction(); - if (clips.size() > 0) { - - // add a marker action for each clip - foreach (int i, clips) { - ClipPtr c = seq->clips.at(i); - ca->append(new AddMarkerAction(&c->get_markers(), - seq->playhead - c->timeline_in() + c->clip_in(), - marker_name)); - } - - } else { - - // if no clips are selected, we're adding a marker to the sequence - - // kind of hacky, we get the correct marker structure from the viewer panel object that the sequence is attached to - if (seq == panel_footage_viewer->seq.get()) { - - // get correct marker reference from footage viewer - ca->append(new AddMarkerAction(panel_footage_viewer->marker_ref, seq->playhead, marker_name)); - - } else if (seq == panel_sequence_viewer->seq.get()) { - - // get correct marker reference from sequence viewer - ca->append(new AddMarkerAction(panel_sequence_viewer->marker_ref, seq->playhead, marker_name)); - - } else { - - // fallback to using markers from sequence provided - ca->append(new AddMarkerAction(&seq->markers, seq->playhead, marker_name)); - - } - + // add a marker action for each clip + foreach (Clip* c, clips) { + ca->append(new AddMarkerAction(&c->get_markers(), + c->track()->sequence()->playhead - c->timeline_in() + c->clip_in(), + marker_name)); } // push action - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); // redraw UI for new markers update_ui(false); @@ -120,11 +95,65 @@ void set_marker_internal(Sequence* seq, const QVector& clips) { } } -void set_marker_internal(Sequence *seq) { - // create empty clip array - QVector clips; +void Marker::SetOnSequence(Sequence *seq) { + + // Don't bother if there is no sequence + if (seq == nullptr) { + return; + } + + // add_marker is used to determine whether we're adding a marker, depending on whether the user input a marker name + // however if (config.set_name_with_marker) is true, we don't need a marker name so we just add + bool add_marker = !olive::config.set_name_with_marker; + + QString marker_name; + + // if Config::set_name_with_marker is true (set above), ask for a marker name + if (!add_marker) { + QInputDialog d(olive::MainWindow); + d.setWindowTitle(QCoreApplication::translate("Marker", "Set Marker")); + d.setLabelText(QCoreApplication::translate("Marker", "Set sequence marker name:")); + d.setInputMode(QInputDialog::TextInput); + add_marker = (d.exec() == QDialog::Accepted); + marker_name = d.textValue(); + } + + // if we've decided to add a marker + if (add_marker) { + + ComboAction* ca = new ComboAction(); + + // FIXME kind of hacky, we get the correct marker structure from the viewer panel object that the sequence is + // attached to, as the viewers will give us the footage marker set if its footage rather than the sequence marker + // set + + if (seq == panel_footage_viewer->seq.get()) { + + // get correct marker reference from footage viewer + ca->append(new AddMarkerAction(panel_footage_viewer->marker_ref, seq->playhead, marker_name)); + + } else if (seq == panel_sequence_viewer->seq.get()) { + + // get correct marker reference from sequence viewer + ca->append(new AddMarkerAction(panel_sequence_viewer->marker_ref, seq->playhead, marker_name)); + + } else { + + // fallback to using markers from sequence provided + ca->append(new AddMarkerAction(&seq->markers, seq->playhead, marker_name)); + + } + + + // push action + olive::undo_stack.push(ca); + + // redraw UI for new markers + update_ui(false); + panel_footage_viewer->update_viewer(); + + } - set_marker_internal(seq, clips); } void Marker::Save(QXmlStreamWriter &stream) const diff --git a/timeline/marker.h b/timeline/marker.h index 9e88bf598..7d8c9ad7a 100644 --- a/timeline/marker.h +++ b/timeline/marker.h @@ -28,8 +28,8 @@ #include #include +class Clip; class Sequence; -using SequencePtr = std::shared_ptr; struct Marker { long frame; @@ -37,9 +37,10 @@ struct Marker { void Save(QXmlStreamWriter& stream) const; static void Draw(QPainter& p, int x, int y, int bottom, bool selected); + + + static void SetOnClips(const QVector& clips); + static void SetOnSequence(Sequence* seq); }; -void set_marker_internal(Sequence *seq, const QVector& clips); -void set_marker_internal(Sequence* seq); - #endif // MARKER_H diff --git a/timeline/selection.cpp b/timeline/selection.cpp index 96c059613..f7c71649a 100644 --- a/timeline/selection.cpp +++ b/timeline/selection.cpp @@ -1,12 +1,16 @@ #include "selection.h" +#include "effects/transition.h" +#include "timeline/clip.h" + +Selection::Selection() +{ +} + Selection::Selection(long in, long out, Track *track) : in_(in), out_(out), - track_(track), - old_in_(in), - old_out_(out), - old_track_(track) + track_(track) { } @@ -35,7 +39,22 @@ void Selection::set_out(long out) out_ = out; } -void Selection::Tidy(QVector selections) +bool Selection::ContainsTransition(Clip* c, int type) const +{ + if (type == kTransitionOpening) { + return c->opening_transition != nullptr + && out_ == c->timeline_in() + c->opening_transition->get_true_length() + && ((c->opening_transition->secondary_clip == nullptr && in_ == c->timeline_in()) + || (c->opening_transition->secondary_clip != nullptr && in_ == c->timeline_in() - c->opening_transition->get_true_length())); + } else { + return c->closing_transition != nullptr + && in_ == c->timeline_out() - c->closing_transition->get_true_length() + && ((c->closing_transition->secondary_clip == nullptr && out_ == c->timeline_out()) + || (c->closing_transition->secondary_clip != nullptr && out_ == c->timeline_out() + c->closing_transition->get_true_length())); + } +} + +void Selection::Tidy(QVector& selections) { for (int i=0;i selections) } else if (s.in() >= ss.in() && s.out() <= ss.out()) { remove = true; } else if (s.in() <= ss.out() && s.out() > ss.out()) { - ss.out = s.out(); + ss.set_out(s.out()); remove = true; } else if (s.out() >= ss.in() && s.in() < ss.in()) { - ss.in = s.in(); + ss.set_in(s.in()); remove = true; } if (remove) { diff --git a/timeline/selection.h b/timeline/selection.h index 6b76e311d..bdf045eac 100644 --- a/timeline/selection.h +++ b/timeline/selection.h @@ -23,10 +23,12 @@ #include +class Clip; class Track; class Selection { public: + Selection(); Selection(long in, long out, Track* track); long in() const; @@ -36,7 +38,9 @@ public: void set_in(long in); void set_out(long out); - static void Tidy(QVector selections); + bool ContainsTransition(Clip* c, int type) const; + + static void Tidy(QVector &selections); private: long in_; diff --git a/timeline/sequence.cpp b/timeline/sequence.cpp index c79900ddb..93ab5bf2d 100644 --- a/timeline/sequence.cpp +++ b/timeline/sequence.cpp @@ -22,8 +22,10 @@ #include +#include "timelinefunctions.h" #include "panels/panels.h" -#include "project/clipboard.h" +#include "global/clipboard.h" +#include "global/config.h" #include "global/debug.h" Sequence::Sequence() : @@ -77,7 +79,7 @@ void Sequence::Save(QXmlStreamWriter &stream) stream.writeAttribute("framerate", QString::number(frame_rate, 'f', 10)); stream.writeAttribute("afreq", QString::number(audio_frequency)); stream.writeAttribute("alayout", QString::number(audio_layout)); - if (this == olive::ActiveSequence.get()) { + if (this == Timeline::GetTopSequence().get()) { stream.writeAttribute("open", "1"); } stream.writeAttribute("workarea", QString::number(using_workarea)); @@ -170,13 +172,303 @@ QVector Sequence::SelectedClips(bool containing) for (int j=0;jTrackCount();j++) { Track* t = tl->TrackAt(j); - selected_clips.append(t->GetAllClips()); + selected_clips.append(t->GetSelectedClips(containing)); } } return selected_clips; } +void Sequence::AddClipsFromGhosts(ComboAction* ca, const QVector& ghosts) +{ + // add clips + long earliest_point = LONG_MAX; + QVector added_clips; + for (int i=0;i(g.track); + c->set_media(g.media, g.media_stream); + c->set_timeline_in(g.in); + c->set_timeline_out(g.out); + c->set_clip_in(g.clip_in); + c->set_track(g.track); + if (c->media()->get_type() == MEDIA_TYPE_FOOTAGE) { + Footage* m = c->media()->to_footage(); + if (m->video_tracks.size() == 0) { + // audio only (greenish) + c->set_color(128, 192, 128); + } else if (m->audio_tracks.size() == 0) { + // video only (orangeish) + c->set_color(192, 160, 128); + } else { + // video and audio (blueish) + c->set_color(128, 128, 192); + } + c->set_name(m->name); + } else if (c->media()->get_type() == MEDIA_TYPE_SEQUENCE) { + // sequence (red?ish?) + c->set_color(192, 128, 128); + + c->set_name(c->media()->to_sequence()->name); + } + c->refresh(); + added_clips.append(c); + + } + ca->append(new AddClipCommand(added_clips)); + + // link clips from the same media + for (int i=0;imedia() == cc->media()) { + c->linked.append(cc.get()); + } + } + + if (olive::config.add_default_effects_to_clips) { + if (c->type() == Track::kTypeVideo) { + // add default video effects + c->effects.append(Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_TRANSFORM, EFFECT_TYPE_EFFECT))); + } else if (c->type() == Track::kTypeAudio) { + // add default audio effects + c->effects.append(Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_VOLUME, EFFECT_TYPE_EFFECT))); + c->effects.append(Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_PAN, EFFECT_TYPE_EFFECT))); + } + } + } + + if (olive::config.enable_seek_to_import) { + panel_sequence_viewer->seek(earliest_point); + } + + olive::timeline::snapped = false; +} + +void Sequence::MoveClip(Clip *c, ComboAction *ca, long iin, long iout, long iclip_in, Track *itrack, bool verify_transitions, bool relative) +{ + ClipPtr clip_ptr = c->track()->GetClipObjectFromRawPtr(c); + + ca->append(new MoveClipAction(clip_ptr, iin, iout, iclip_in, itrack, relative)); + + if (verify_transitions) { + + // if this is a shared transition, and the corresponding clip will be moved away somehow + if (c->opening_transition != nullptr + && c->opening_transition->secondary_clip != nullptr + && c->opening_transition->secondary_clip->timeline_out() != iin) { + // separate transition + ca->append(new SetPointer(reinterpret_cast(&c->opening_transition->secondary_clip), nullptr)); + ca->append(new AddTransitionCommand(nullptr, + c->opening_transition->secondary_clip, + c->opening_transition, + nullptr, + 0)); + } + + if (c->closing_transition != nullptr + && c->closing_transition->secondary_clip != nullptr + && c->closing_transition->parent_clip->timeline_in() != iout) { + // separate transition + ca->append(new SetPointer(reinterpret_cast(&c->closing_transition->secondary_clip), nullptr)); + ca->append(new AddTransitionCommand(nullptr, + c, + c->closing_transition, + nullptr, + 0)); + } + } +} + +void Sequence::EditToPoint(bool in, bool ripple) +{ + QVector all_clips = GetAllClips(); + + if (all_clips.size() > 0) { + long sequence_end = 0; + + bool playhead_falls_on_in = false; + bool playhead_falls_on_out = false; + long next_cut = LONG_MAX; + long prev_cut = 0; + + // find closest in point to playhead + for (int i=0;itimeline_out(), sequence_end); + + if (c->timeline_in() == playhead) + playhead_falls_on_in = true; + + if (c->timeline_out() == playhead) + playhead_falls_on_out = true; + + if (c->timeline_in() > playhead) + next_cut = qMin(c->timeline_in(), next_cut); + + if (c->timeline_out() > playhead) + next_cut = qMin(c->timeline_out(), next_cut); + + if (c->timeline_in() < playhead) + prev_cut = qMax(c->timeline_in(), prev_cut); + + if (c->timeline_out() < playhead) + prev_cut = qMax(c->timeline_out(), prev_cut); + + } + + next_cut = qMin(sequence_end, next_cut); + + QVector areas; + ComboAction* ca = new ComboAction(); + bool push_undo = true; + long seek = playhead; + + if ((in && (playhead_falls_on_out || (playhead_falls_on_in && playhead == 0))) + || (!in && (playhead_falls_on_in || (playhead_falls_on_out && playhead == sequence_end)))) { // one frame mode + if (ripple) { + // set up deletion areas based on track count + long in_point = playhead; + if (!in) { + in_point--; + seek--; + } + + if (in_point >= 0) { + + for (int i=0;iTrackCount();j++) { + areas.append(Selection(in_point, in_point+1, tl->TrackAt(j))); + } + + } + + // trim and move clips around the in point + DeleteAreas(ca, areas, true); + + if (ripple) { + Ripple(ca, in_point, -1); + } + } else { + push_undo = false; + } + } else { + push_undo = false; + } + } else { + // set up deletion areas based on track count + + long area_in, area_out; + + if (in) { + seek = prev_cut; + area_in = prev_cut; + area_out = playhead; + } else { + area_in = playhead; + area_out = next_cut; + } + + if (area_in == area_out) { + + push_undo = false; + + } else { + + for (int i=0;iTrackCount();j++) { + areas.append(Selection(area_in, area_out, tl->TrackAt(j))); + } + + } + + // trim and move clips around the in point + DeleteAreas(ca, areas, true); + if (ripple) { + Ripple(ca, area_in, area_in - area_out); + } + } + } + + if (push_undo) { + olive::undo_stack.push(ca); + + update_ui(true); + + if (seek != playhead && ripple) { + panel_sequence_viewer->seek(seek); + } + } else { + delete ca; + } + } else { + panel_sequence_viewer->seek(0); + } +} + +bool Sequence::SnapPoint(long *l, double zoom, bool use_playhead, bool use_markers, bool use_workarea) +{ + olive::timeline::snapped = false; + if (olive::timeline::snapping) { + if (use_playhead && !panel_sequence_viewer->playing) { + // snap to playhead + if (olive::timeline::SnapToPoint(playhead, l, zoom)) return true; + } + + // snap to marker + if (use_markers) { + for (int i=0;i all_clips = GetAllClips(); + for (int i=0;itimeline_in(), l, zoom)) { + return true; + } else if (olive::timeline::SnapToPoint(c->timeline_out(), l, zoom)) { + return true; + } else if (c->opening_transition != nullptr + && olive::timeline::SnapToPoint(c->timeline_in() + c->opening_transition->get_true_length(), l, zoom)) { + return true; + } else if (c->closing_transition != nullptr + && olive::timeline::SnapToPoint(c->timeline_out() - c->closing_transition->get_true_length(), l, zoom)) { + return true; + } else { + // try to snap to clip markers + for (int j=0;jget_markers().size();j++) { + if (olive::timeline::SnapToPoint(c->get_markers().at(j).frame + c->timeline_in() - c->clip_in(), l, zoom)) { + return true; + } + } + } + + } + } + + return false; +} + void Sequence::DeleteInToOut(bool ripple) { if (using_workarea) { @@ -198,13 +490,45 @@ void Sequence::DeleteInToOut(bool ripple) if (ripple) Ripple(ca, workarea_in, workarea_in - workarea_out); - ca->append(new SetTimelineInOutCommand(olive::ActiveSequence.get(), false, 0, 0)); - olive::UndoStack.push(ca); + ca->append(new SetTimelineInOutCommand(this, false, 0, 0)); + olive::undo_stack.push(ca); update_ui(true); } } -void Sequence::Ripple(ComboAction *ca, long point, long length, const QVector &ignore) +void Sequence::DeleteClipsUsingMedia(const QVector& media) +{ + QVector all_clips = GetAllClips(); + + ComboAction* ca = new ComboAction(); + bool deleted = false; + + for (int j=0;jmedia() == media.at(j)) { + ca->append(new DeleteClipAction(c)); + deleted = true; + } + } + } + + if (deleted) { + olive::undo_stack.push(ca); + update_ui(true); + } else { + delete ca; + } +} + +void Sequence::Ripple(ComboAction *ca, long point, long length, const QVector &ignore) { ca->append(new RippleAction(this, point, length, ignore)); } @@ -222,14 +546,95 @@ void Sequence::ChangeTrackHeightsRelatively(int diff) } } -void Sequence::DeleteAreas(ComboAction* ca, QVector areas, bool deselect_areas) +void Sequence::ToggleLinksOnSelected() +{ + QVector selected_clips = SelectedClips(); + + bool link = true; + QVector link_clips; + + for (int i=0;ilinked.size() > 0) { + link = false; // prioritize unlinking + + for (int j=0;jlinked.size();j++) { // add links to the command + if (!link_clips.contains(c->linked.at(j))) { + link_clips.append(c->linked.at(j)); + } + } + } + } + + if (!link_clips.isEmpty()) { + olive::undo_stack.push(new LinkCommand(link_clips, link)); + } +} + +void Sequence::Split() +{ + ComboAction* ca = new ComboAction(); + bool split_selected = false; + + QVector selected_clips = SelectedClips(true); + if (selected_clips.size() > 0) { + // see if whole clips are selected + QVector pre_clips; + QVector post_clips; + + for (int i=0;iappend(new AddClipCommand(post_clips)); + + } else { + + // split a selection if not + // FIXME reimplement split selection + //split_selected = split_selection(ca); + + } + } + + // if nothing was selected or no selections fell within playhead, simply split at playhead + if (!split_selected) { + split_selected = SplitAllClipsAtPoint(ca, playhead); + } + + if (split_selected) { + olive::undo_stack.push(ca); + update_ui(true); + } else { + delete ca; + } +} + +void Sequence::DeleteAreas(ComboAction* ca, QVector areas, bool deselect_areas, bool ripple) { Selection::Tidy(areas); panel_graph_editor->set_row(nullptr); panel_effect_controls->Clear(true); - QVector pre_clips; + QVector pre_clips; QVector post_clips; QVector all_clips = GetAllClips(); @@ -239,10 +644,10 @@ void Sequence::DeleteAreas(ComboAction* ca, QVector areas, bool desel for (int j=0;jtrack() == s.track() && !c->undeletable) { - if (selection_contains_transition(s, c, kTransitionOpening)) { + if (s.ContainsTransition(c, kTransitionOpening)) { // delete opening transition ca->append(new DeleteTransitionCommand(c->opening_transition)); - } else if (selection_contains_transition(s, c, kTransitionClosing)) { + } else if (s.ContainsTransition(c, kTransitionClosing)) { // delete closing transition ca->append(new DeleteTransitionCommand(c->closing_transition)); } else if (c->timeline_in() >= s.in() && c->timeline_out() <= s.out()) { @@ -254,28 +659,30 @@ void Sequence::DeleteAreas(ComboAction* ca, QVector areas, bool desel // duplicate clip ClipPtr post = SplitClip(ca, true, c, s.in(), s.out()); - pre_clips.append(j); + pre_clips.append(c); post_clips.append(post); } else if (c->timeline_in() < s.in() && c->timeline_out() > s.in()) { // only out point is in deletion area - c->move(ca, c->timeline_in(), s.in(), c->clip_in(), c->track()); + MoveClip(c, ca, c->timeline_in(), s.in(), c->clip_in(), c->track()); if (c->closing_transition != nullptr) { if (s.in() < c->timeline_out() - c->closing_transition->get_true_length()) { ca->append(new DeleteTransitionCommand(c->closing_transition)); } else { - ca->append(new ModifyTransitionCommand(c->closing_transition, c->closing_transition->get_true_length() - (c->timeline_out() - s.in))); + ca->append(new ModifyTransitionCommand(c->closing_transition, + c->closing_transition->get_true_length() - (c->timeline_out() - s.in()))); } } } else if (c->timeline_in() < s.out() && c->timeline_out() > s.out()) { // only in point is in deletion area - c->move(ca, s.out(), c->timeline_out(), c->clip_in() + (s.out() - c->timeline_in()), c->track()); + MoveClip(c, ca, s.out(), c->timeline_out(), c->clip_in() + (s.out() - c->timeline_in()), c->track()); if (c->opening_transition != nullptr) { if (s.out() > c->timeline_in() + c->opening_transition->get_true_length()) { ca->append(new DeleteTransitionCommand(c->opening_transition)); } else { - ca->append(new ModifyTransitionCommand(c->opening_transition, c->opening_transition->get_true_length() - (s.out - c->timeline_in()))); + ca->append(new ModifyTransitionCommand(c->opening_transition, + c->opening_transition->get_true_length() - (s.out() - c->timeline_in()))); } } } @@ -288,12 +695,16 @@ void Sequence::DeleteAreas(ComboAction* ca, QVector areas, bool desel QVector area_copy = areas; for (int i=0;iDeselectArea(s.in(), s.out()); } } - relink_clips_using_ids(pre_clips, post_clips); - ca->append(new AddClipCommand(olive::ActiveSequence.get(), post_clips)); + if (ripple) { + + } + + olive::timeline::RelinkClips(pre_clips, post_clips); + ca->append(new AddClipCommand(post_clips)); } bool Sequence::SplitAllClipsAtPoint(ComboAction *ca, long point) @@ -314,10 +725,12 @@ bool Sequence::SplitAllClipsAtPoint(ComboAction *ca, long point) return split; } -void Sequence::SplitClipAtPositions(ComboAction *ca, Clip* clip, QVector positions, bool relink) +bool Sequence::SplitClipAtPositions(ComboAction *ca, Clip* clip, QVector positions, bool relink) { // Add the clip and each of its links to the pre_splits array + bool split_occurred = false; + QVector pre_splits; pre_splits.append(clip); @@ -346,15 +759,102 @@ void Sequence::SplitClipAtPositions(ComboAction *ca, Clip* clip, QVector p for (int j=0;jset_timeline_out(positions.at(i+1)); + if (post_splits[i][j] != nullptr) { + split_occurred = true; + + if (i + 1 < positions.size()) { + post_splits[i][j]->set_timeline_out(positions.at(i+1)); + } } } } for (int i=0;iappend(new AddClipCommand(olive::ActiveSequence.get(), post_splits[i])); + ca->append(new AddClipCommand(post_splits[i])); + } + + return split_occurred; +} + +void Sequence::RippleDeleteEmptySpace(Track* track, long point) +{ + QVector track_clips = track->GetAllClips(); + + long ripple_start = LONG_MAX; + long ripple_end = LONG_MAX; + + for (int i=0;itimeline_in() <= point && c->timeline_out() >= point) { + // This point is not actually empty, so there's nothing to do here + return; + } + + if (c->timeline_out() < point) { + + ripple_start = qMin(c->timeline_out(), ripple_start); + + } else if (c->timeline_in() > point) { + + ripple_end = qMin(c->timeline_in(), ripple_end); + + } + } + + // We now know the maximum ripple we could do to clear this empty space, but we need to ensure it won't cause + // overlaps of clips in other tracks + + for (int i=0;iTrackCount();j++) { + Track* t = tl->TrackAt(j); + + // We've already tested `track`, so we don't need to test it again + if (t != track) { + + long first_in_point_after_point = LONG_MAX; + long out_point_just_before_first_in_point = LONG_MIN; + + QVector track_clips = t->GetAllClips(); + + // Find the in point of the clip directly after the point + for (int k=0;ktimeline_in() > point) { + first_in_point_after_point = qMin(first_in_point_after_point, c->timeline_in()); + } + } + + // Ensure we found a valid in point before proceeding + if (first_in_point_after_point != LONG_MAX) { + + // Find the out point of the clip directly before the clip found above + for (int k=0;ktimeline_out() < first_in_point_after_point) { + out_point_just_before_first_in_point = qMax(out_point_just_before_first_in_point, c->timeline_out()); + } + } + + long gap_between_clips = first_in_point_after_point - out_point_just_before_first_in_point; + + if (gap_between_clips > (ripple_end - ripple_start)) { + ripple_end = ripple_start + gap_between_clips; + } + } + } + } + } + + if (ripple_start != ripple_end) { + ComboAction* ca = new ComboAction(); + Ripple(ca, ripple_start, ripple_start - ripple_end); + olive::undo_stack.push(ca); } } @@ -383,7 +883,7 @@ Effect *Sequence::GetSelectedGizmo() for (int i=0;iIsActiveAt(playhead) - && IsClipSelected(c, true)) { + && c->IsSelected()) { // This clip is selected and currently active - we'll use this for gizmos if (!c->effects.isEmpty()) { @@ -516,7 +1016,7 @@ void Sequence::AddSelectionsToClipboard(bool delete_originals) if (delete_originals) { ComboAction* ca = new ComboAction(); DeleteAreas(ca, selections, true); - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); } } @@ -537,6 +1037,24 @@ QVector Sequence::Selections() return selections; } +void Sequence::SetSelections(const QVector &selections) +{ + ClearSelections(); + + for (int i=0;iSelectArea(s.in(), s.out()); + } +} + +void Sequence::TidySelections() +{ + QVector selections = Selections(); + Selection::Tidy(selections); + SetSelections(selections); +} + ClipPtr Sequence::SplitClip(ComboAction *ca, bool transitions, Clip* pre, long frame) { return SplitClip(ca, transitions, pre, frame, frame); @@ -558,7 +1076,7 @@ ClipPtr Sequence::SplitClip(ComboAction *ca, bool transitions, Clip* pre, long f post->set_timeline_in(post_in); post->set_clip_in(pre->clip_in() + (post->timeline_in() - pre->timeline_in())); - pre->move(ca, pre->timeline_in(), frame, pre->clip_in(), pre->track(), false); + MoveClip(pre, ca, pre->timeline_in(), frame, pre->clip_in(), pre->track(), false); if (transitions) { @@ -616,5 +1134,28 @@ ClipPtr Sequence::SplitClip(ComboAction *ca, bool transitions, Clip* pre, long f return nullptr; } -// static variable for the currently active sequence -SequencePtr olive::ActiveSequence = nullptr; +bool Sequence::SplitSelection(ComboAction *ca, QVector selections) +{ + QVector all_clips = GetAllClips(); + + for (int i=0;i points; + + for (int j=0;jtrack()) { + if (c->timeline_in() < s.in() && c->timeline_out() > s.in()) { + points.append(s.in()); + } + if (c->timeline_in() < s.out() && c->timeline_out() > s.out()) { + points.append(s.out()); + } + } + } + + + } +} diff --git a/timeline/sequence.h b/timeline/sequence.h index 9ec11fc38..3edf773fd 100644 --- a/timeline/sequence.h +++ b/timeline/sequence.h @@ -28,6 +28,7 @@ #include "marker.h" #include "selection.h" #include "tracklist.h" +#include "ghost.h" class Sequence : public QObject { Q_OBJECT @@ -63,17 +64,37 @@ public: void RefreshClipsUsingMedia(Media* m = nullptr); QVector SelectedClips(bool containing = true); - //QVector SelectedClipIndexes(); - void DeleteAreas(ComboAction* ca, QVector areas, bool deselect_areas); + void AddClipsFromGhosts(ComboAction *ca, const QVector &ghosts); + + void MoveClip(Clip* c, + ComboAction* ca, + long iin, + long iout, + long iclip_in, + Track *itrack, + bool verify_transitions = true, + bool relative = false); + + void EditToPoint(bool in, bool ripple); + + bool SnapPoint(long* l, double zoom, bool use_playhead, bool use_markers, bool use_workarea); + + void DeleteAreas(ComboAction* ca, QVector areas, bool deselect_areas = false, bool ripple = false); void DeleteInToOut(bool ripple); + void DeleteClipsUsingMedia(const QVector &media); - void Ripple(ComboAction *ca, long point, long length, const QVector& ignore = QVector()); + void Ripple(ComboAction *ca, long point, long length, const QVector &ignore = QVector()); void ChangeTrackHeightsRelatively(int diff); + void ToggleLinksOnSelected(); + + void Split(); bool SplitAllClipsAtPoint(ComboAction *ca, long point); - void SplitClipAtPositions(ComboAction* ca, Clip *clip, QVector positions, bool relink = true); + bool SplitClipAtPositions(ComboAction* ca, Clip *clip, QVector positions, bool relink = true); + + void RippleDeleteEmptySpace(Track *track, long point); Effect* GetSelectedGizmo(); @@ -85,6 +106,8 @@ public: void ClearSelections(); void AddSelectionsToClipboard(bool delete_originals); QVector Selections(); + void SetSelections(const QVector& selections); + void TidySelections(); long playhead; @@ -102,13 +125,9 @@ private: ClipPtr SplitClip(ComboAction* ca, bool transitions, Clip *clip, long frame); ClipPtr SplitClip(ComboAction* ca, bool transitions, Clip *clip, long frame, long post_in); + bool SplitSelection(ComboAction* ca, QVector selections); }; using SequencePtr = std::shared_ptr; -// static variable for the currently active sequence -namespace olive { - extern SequencePtr ActiveSequence; -} - #endif // SEQUENCE_H diff --git a/timeline/timelinefunctions.cpp b/timeline/timelinefunctions.cpp index b70e6c08c..3e776b78b 100644 --- a/timeline/timelinefunctions.cpp +++ b/timeline/timelinefunctions.cpp @@ -1,6 +1,14 @@ #include "timelinefunctions.h" +#include "global/math.h" +#include "global/config.h" +#include "global/timing.h" +#include "sequence.h" +// snapping +bool olive::timeline::snapping = true; +bool olive::timeline::snapped = false; +long olive::timeline::snap_point = 0; void olive::timeline::RelinkClips(QVector &pre_clips, QVector &post_clips) { @@ -28,3 +36,137 @@ void olive::timeline::RelinkClips(QVector &pre_clips, QVector & } } } + +bool olive::timeline::SnapToPoint(long point, long* l, double zoom) { + long limit = getFrameFromScreenPoint(zoom, 10); // FIXME magic number 10 used for on screen pixel threshold to snap to + if (*l > point-limit-1 && *l < point+limit+1) { + olive::timeline::snap_point = point; + *l = point; + olive::timeline::snapped = true; + return true; + } + return false; +} + + +QVector olive::timeline::CreateGhostsFromMedia(Sequence *seq, + long entry_point, + QVector &media_list) +{ + QVector ghosts; + + for (int i=0;iget_type()) { + case MEDIA_TYPE_FOOTAGE: + m = medium->to_footage(); + can_import = m->ready; + if (m->using_inout) { + double source_fr = 30; + if (m->video_tracks.size() > 0 && !qIsNull(m->video_tracks.at(0).video_frame_rate)) { + source_fr = m->video_tracks.at(0).video_frame_rate * m->speed; + } + default_clip_in = rescale_frame_number(m->in, source_fr, seq->frame_rate); + default_clip_out = rescale_frame_number(m->out, source_fr, seq->frame_rate); + } + break; + case MEDIA_TYPE_SEQUENCE: + s = medium->to_sequence().get(); + sequence_length = s->GetEndFrame(); + if (seq != nullptr) sequence_length = rescale_frame_number(sequence_length, s->frame_rate, seq->frame_rate); + can_import = (s != seq && sequence_length != 0); + if (s->using_workarea) { + default_clip_in = rescale_frame_number(s->workarea_in, s->frame_rate, seq->frame_rate); + default_clip_out = rescale_frame_number(s->workarea_out, s->frame_rate, seq->frame_rate); + } + break; + default: + can_import = false; + } + + if (can_import) { + Ghost g; + g.clip = nullptr; + g.trim_type = olive::timeline::TRIM_NONE; + g.old_clip_in = g.clip_in = default_clip_in; + g.media = medium; + g.in = entry_point; + g.transition = nullptr; + + switch (medium->get_type()) { + case MEDIA_TYPE_FOOTAGE: + // is video source a still image? + if (m->video_tracks.size() > 0 && m->video_tracks.at(0).infinite_length && m->audio_tracks.size() == 0) { + g.out = g.in + 100; + } else { + long length = m->get_length_in_frames(seq->frame_rate); + g.out = entry_point + length - default_clip_in; + if (m->using_inout) { + g.out -= (length - default_clip_out); + } + } + + if (import_data.type() == olive::timeline::kImportAudioOnly + || import_data.type() == olive::timeline::kImportBoth) { + for (int j=0;jaudio_tracks.size();j++) { + if (m->audio_tracks.at(j).enabled) { + g.track = seq->GetTrackList(Track::kTypeAudio)->First() + j; + g.media_stream = m->audio_tracks.at(j).file_index; + ghosts.append(g); + } + } + } + + if (import_data.type() == olive::timeline::kImportVideoOnly + || import_data.type() == olive::timeline::kImportBoth) { + for (int j=0;jvideo_tracks.size();j++) { + if (m->video_tracks.at(j).enabled) { + g.track = seq->GetTrackList(Track::kTypeVideo)->First() + j; + g.media_stream = m->video_tracks.at(j).file_index; + ghosts.append(g); + } + } + } + break; + case MEDIA_TYPE_SEQUENCE: + g.out = entry_point + sequence_length - default_clip_in; + + if (s->using_workarea) { + g.out -= (sequence_length - default_clip_out); + } + + if (import_data.type() == olive::timeline::kImportVideoOnly + || import_data.type() == olive::timeline::kImportBoth) { + g.track = seq->GetTrackList(Track::kTypeVideo)->First(); + ghosts.append(g); + } + + if (import_data.type() == olive::timeline::kImportAudioOnly + || import_data.type() == olive::timeline::kImportBoth) { + g.track = seq->GetTrackList(Track::kTypeAudio)->First(); + ghosts.append(g); + } + + break; + } + entry_point = g.out; + } + } + for (int i=0;i #include "timeline/clip.h" +#include "timeline/mediaimportdata.h" +#include "ghost.h" namespace olive { namespace timeline { @@ -17,12 +19,6 @@ enum CreateObjects { ADD_OBJ_AUDIO }; -enum TrimType { - TRIM_NONE, - TRIM_IN, - TRIM_OUT -}; - enum Alignment { kAlignmentTop, kAlignmentBottom, @@ -31,6 +27,15 @@ enum Alignment { void RelinkClips(QVector& pre_clips, QVector &post_clips); +bool SnapToPoint(long point, long* l, double zoom); + +QVector CreateGhostsFromMedia(Sequence *seq, long entry_point, QVector &media_list); + +// snapping +extern bool snapping; +extern bool snapped; +extern long snap_point; + } } diff --git a/timeline/timelinetools.cpp b/timeline/timelinetools.cpp new file mode 100644 index 000000000..fe3eea243 --- /dev/null +++ b/timeline/timelinetools.cpp @@ -0,0 +1,3 @@ +#include "timelinetools.h" + +olive::timeline::Tool olive::timeline::current_tool = olive::timeline::TIMELINE_TOOL_POINTER; diff --git a/ui/timelinetools.h b/timeline/timelinetools.h similarity index 89% rename from ui/timelinetools.h rename to timeline/timelinetools.h index b13f4764d..4fbe6f704 100644 --- a/ui/timelinetools.h +++ b/timeline/timelinetools.h @@ -21,7 +21,10 @@ #ifndef TIMELINETOOLS_H #define TIMELINETOOLS_H -enum TimelineTool { +namespace olive { +namespace timeline { + +enum Tool { TIMELINE_TOOL_POINTER, TIMELINE_TOOL_EDIT, TIMELINE_TOOL_RAZOR, @@ -36,4 +39,9 @@ enum TimelineTool { TIMELINE_TOOL_COUNT }; +extern Tool current_tool; + +} +} + #endif // TIMELINETOOLS_H diff --git a/timeline/track.cpp b/timeline/track.cpp index 48d174c15..4ae915c16 100644 --- a/timeline/track.cpp +++ b/timeline/track.cpp @@ -50,12 +50,8 @@ void Track::Save(QXmlStreamWriter &stream) for (int j=0;jload_id)); - c->Save(stream); - stream.writeEndElement(); // clip } stream.writeEndElement(); // track @@ -78,6 +74,10 @@ void Track::set_height(int h) void Track::AddClip(ClipPtr clip) { + if (clips_.contains(clip)) { + return; + } + clips_.append(clip); if (clip->track() != nullptr) { clip->track()->RemoveClip(clip.get()); @@ -85,6 +85,16 @@ void Track::AddClip(ClipPtr clip) clip->set_track(this); } +int Track::ClipCount() +{ + return clips_.size(); +} + +ClipPtr Track::GetClip(int i) +{ + return clips_.at(i); +} + void Track::RemoveClip(int i) { clips_.removeAt(i); @@ -145,6 +155,19 @@ ClipPtr Track::GetClipObjectFromRawPtr(Clip *c) Q_ASSERT(false); } +Clip *Track::GetClipFromPoint(long point) +{ + for (int i=0;itimeline_in() <= point && c->timeline_out() > point) { + return c; + } + } + + return nullptr; +} + int Track::Index() { return parent_->IndexOfTrack(this); @@ -209,6 +232,11 @@ bool Track::IsTransitionSelected(Transition *t) return false; } +void Track::SelectArea(long in, long out) +{ + selections_.append(Selection(in, out, this)); +} + void Track::SelectClip(Clip* c) { selections_.append(Selection(c->timeline_in(), c->timeline_out(), this)); diff --git a/timeline/track.h b/timeline/track.h index 168a69a91..b21b67c7d 100644 --- a/timeline/track.h +++ b/timeline/track.h @@ -61,6 +61,7 @@ public: QVector GetAllClips(); QVector GetSelectedClips(bool containing); ClipPtr GetClipObjectFromRawPtr(Clip* c); + Clip* GetClipFromPoint(long point); int Index(); @@ -71,6 +72,7 @@ public: void DeleteArea(ComboAction *ca, const Selection& s); void DeleteArea(ComboAction *ca, long in, long out); + void SelectArea(long in, long out); void SelectClip(Clip *c); void SelectAll(); void SelectAtPoint(long point); diff --git a/timeline/tracklist.cpp b/timeline/tracklist.cpp index 8215121a0..b1a76ac84 100644 --- a/timeline/tracklist.cpp +++ b/timeline/tracklist.cpp @@ -82,7 +82,17 @@ QVector TrackList::tracks() return tracks_; } +Track::Type TrackList::type() +{ + return type_; +} + Sequence *TrackList::GetParent() { return static_cast(parent()); } + +void TrackList::ResizeTrackArray(int i) +{ + tracks_.resize(i); +} diff --git a/timeline/tracklist.h b/timeline/tracklist.h index 558114e30..5b7ca2dec 100644 --- a/timeline/tracklist.h +++ b/timeline/tracklist.h @@ -20,6 +20,8 @@ public: Track* TrackAt(int i); QVector tracks(); + Track::Type type(); + Sequence* GetParent(); private: diff --git a/ui/audiomonitor.cpp b/ui/audiomonitor.cpp index f40042ba7..d69277587 100644 --- a/ui/audiomonitor.cpp +++ b/ui/audiomonitor.cpp @@ -68,7 +68,7 @@ void AudioMonitor::resizeEvent(QResizeEvent *e) { } void AudioMonitor::paintEvent(QPaintEvent *) { - if (olive::ActiveSequence != nullptr && values.size() > 0) { + if (values.size() > 0) { QPainter p(this); int channel_x = AUDIO_MONITOR_GAP; int channel_count = values.size(); diff --git a/ui/focusfilter.cpp b/ui/focusfilter.cpp index 18b6a1c5e..4092bc6c7 100644 --- a/ui/focusfilter.cpp +++ b/ui/focusfilter.cpp @@ -100,7 +100,7 @@ void FocusFilter::set_viewer_fullscreen() { } void FocusFilter::set_marker() { - if (olive::ActiveSequence != nullptr) { + if (Timeline::GetTopSequence() != nullptr) { QDockWidget* focused_panel = get_focused_panel(); if (focused_panel == panel_footage_viewer) { @@ -108,7 +108,7 @@ void FocusFilter::set_marker() { } else if (focused_panel == panel_sequence_viewer) { panel_sequence_viewer->set_marker(); } else { - panel_timeline->set_marker(); + panel_timeline.first()->set_marker(); } } } @@ -190,28 +190,31 @@ void FocusFilter::clear_inout() { } void FocusFilter::delete_function() { - if (panel_timeline->headers->hasFocus()) { - panel_timeline->headers->delete_markers(); + if (panel_timeline.first()->headers->hasFocus()) { + panel_timeline.first()->headers->delete_markers(); } else if (panel_footage_viewer->headers->hasFocus()) { panel_footage_viewer->headers->delete_markers(); } else if (panel_sequence_viewer->headers->hasFocus()) { panel_sequence_viewer->headers->delete_markers(); - } else if (panel_effect_controls->is_focused()) { + } else if (panel_effect_controls->focused()) { panel_effect_controls->DeleteSelectedEffects(); - } else if (panel_project->is_focused()) { - panel_project->delete_selected_media(); - } else if (panel_effect_controls->keyframe_focus()) { + } else if (panel_project.first()->focused()) { + panel_project.first()->delete_selected_media(); + } else if (panel_effect_controls->focused()) { panel_effect_controls->delete_selected_keyframes(); - } else if (panel_graph_editor->view_is_focused()) { + } else if (panel_graph_editor->focused()) { panel_graph_editor->delete_selected_keys(); } else { - panel_timeline->delete_selection(olive::ActiveSequence->selections, false); + Sequence* top_sequence = Timeline::GetTopSequence().get(); + ComboAction* ca = new ComboAction(); + top_sequence->DeleteAreas(ca, top_sequence->Selections(), true); + olive::undo_stack.push(ca); } } void FocusFilter::duplicate() { - if (panel_project->is_focused()) { - panel_project->duplicate_selected(); + if (panel_project.first()->focused()) { + panel_project.first()->duplicate_selected(); } } @@ -220,7 +223,7 @@ void FocusFilter::select_all() { if (focused_panel == panel_graph_editor) { panel_graph_editor->select_all(); } else { - panel_timeline->select_all(); + panel_timeline.first()->select_all(); } } @@ -233,7 +236,7 @@ void FocusFilter::zoom_in() { } else if (focused_panel == panel_sequence_viewer) { panel_sequence_viewer->set_zoom(true); } else { - panel_timeline->zoom_in(); + panel_timeline.first()->zoom_in(); } } @@ -246,28 +249,28 @@ void FocusFilter::zoom_out() { } else if (focused_panel == panel_sequence_viewer) { panel_sequence_viewer->set_zoom(false); } else { - panel_timeline->zoom_out(); + panel_timeline.first()->zoom_out(); } } void FocusFilter::cut() { - if (olive::ActiveSequence != nullptr) { + if (Timeline::GetTopSequence() != nullptr) { QDockWidget* focused_panel = get_focused_panel(); if (panel_effect_controls == focused_panel) { panel_effect_controls->copy(true); } else { - panel_timeline->copy(true); + panel_timeline.first()->copy(true); } } } void FocusFilter::copy() { - if (olive::ActiveSequence != nullptr) { + if (Timeline::GetTopSequence() != nullptr) { QDockWidget* focused_panel = get_focused_panel(); if (panel_effect_controls == focused_panel) { panel_effect_controls->copy(false); } else { - panel_timeline->copy(false); + panel_timeline.first()->copy(false); } } } diff --git a/ui/graphview.cpp b/ui/graphview.cpp index 8f77b43ba..5885d7f76 100644 --- a/ui/graphview.cpp +++ b/ui/graphview.cpp @@ -470,7 +470,7 @@ void GraphView::mousePressEvent(QMouseEvent *event) { void GraphView::mouseMoveEvent(QMouseEvent *event) { if (!mousedown || !click_add) unsetCursor(); if (mousedown) { - if (event->buttons() & Qt::MiddleButton || panel_timeline->tool == TIMELINE_TOOL_HAND) { + if (event->buttons() & Qt::MiddleButton || olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_HAND) { set_scroll_x(x_scroll + start_x - event->pos().x()); set_scroll_y(y_scroll + event->pos().y() - start_y); start_x = event->pos().x(); @@ -701,7 +701,7 @@ void GraphView::mouseMoveEvent(QMouseEvent *event) { void GraphView::mouseReleaseEvent(QMouseEvent *) { if (click_add_proc) { - olive::UndoStack.push(new KeyframeAdd(click_add_field, click_add_key)); + olive::undo_stack.push(new KeyframeAdd(click_add_field, click_add_key)); } else if (moved_keys && selected_keys.size() > 0) { ComboAction* ca = new ComboAction(); switch (current_handle) { @@ -723,7 +723,7 @@ void GraphView::mouseReleaseEvent(QMouseEvent *) { } break; } - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); } moved_keys = false; mousedown = false; @@ -757,7 +757,7 @@ void GraphView::wheelEvent(QWheelEvent *event) { double new_x_zoom = x_zoom; double new_y_zoom = y_zoom; - if (ctrl != olive::CurrentConfig.scroll_zooms) { + if (ctrl != olive::config.scroll_zooms) { zooming = true; } @@ -849,7 +849,7 @@ void GraphView::set_selected_keyframe_type(int type) { EffectKeyframe& key = row->Field(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)]; ca->append(new SetInt(&key.type, type)); } - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); update_ui(false); } } diff --git a/ui/keyframeview.cpp b/ui/keyframeview.cpp index 409294548..e1926c394 100644 --- a/ui/keyframeview.cpp +++ b/ui/keyframeview.cpp @@ -42,6 +42,7 @@ #include "effects/keyframe.h" #include "ui/graphview.h" #include "ui/menu.h" +#include "global/math.h" KeyframeView::KeyframeView(QWidget *parent) : QWidget(parent), @@ -95,7 +96,7 @@ void KeyframeView::menu_set_key_type(QAction* a) { EffectField* f = selected_fields.at(i); ca->append(new SetInt(&f->keyframes[selected_keyframes.at(i)].type, a->data().toInt())); } - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); update_ui(false); } } @@ -172,8 +173,9 @@ void KeyframeView::paintEvent(QPaintEvent*) { panel_effect_controls->horizontalScrollBar->setMaximum(qMax(max_width - width(), 0)); header->set_visible_in(visible_in); - int playhead_x = getScreenPointFromFrame(panel_effect_controls->zoom, olive::ActiveSequence->playhead-visible_in) - x_scroll; - if (dragging && panel_timeline->snapped) { + int playhead_x = getScreenPointFromFrame(panel_effect_controls->zoom, + open_effects_.first()->GetEffect()->parent_clip->track()->sequence()->playhead-visible_in) - x_scroll; + if (dragging && olive::timeline::snapped) { p.setPen(Qt::white); } else { p.setPen(Qt::red); @@ -234,7 +236,7 @@ void KeyframeView::mousePressEvent(QMouseEvent *event) { rect_select_w = 0; rect_select_h = 0; - if (panel_timeline->tool == TIMELINE_TOOL_HAND || event->buttons() & Qt::MiddleButton) { + if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_HAND || event->buttons() & Qt::MiddleButton) { scroll_drag = true; return; } @@ -323,7 +325,7 @@ void KeyframeView::mousePressEvent(QMouseEvent *event) { } void KeyframeView::mouseMoveEvent(QMouseEvent* event) { - if (panel_timeline->tool == TIMELINE_TOOL_HAND) { + if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_HAND) { setCursor(Qt::OpenHandCursor); } else { unsetCursor(); @@ -376,14 +378,14 @@ void KeyframeView::mouseMoveEvent(QMouseEvent* event) { long frame_diff = current_frame - drag_frame_start; // snapping to playhead - panel_timeline->snapped = false; - if (panel_timeline->snapping) { + olive::timeline::snapped = false; + if (olive::timeline::snapping) { for (int i=0;iGetParentRow()->GetParentEffect()->parent_clip; long key_time = old_key_vals.at(i) + frame_diff - c->clip_in() + c->timeline_in(); long key_eval = key_time; - if (panel_timeline->snap_to_point(olive::ActiveSequence->playhead, &key_eval)) { + if (olive::timeline::SnapToPoint(c->track()->sequence()->playhead, &key_eval, header->get_zoom())) { frame_diff += (key_eval - key_time); break; } @@ -398,10 +400,10 @@ void KeyframeView::mouseMoveEvent(QMouseEvent* event) { while (!keyframeIsSelected(field, j) && field->keyframes.at(j).time == eval_key + frame_diff) { if (last_frame_diff > frame_diff) { frame_diff++; - panel_timeline->snapped = false; + olive::timeline::snapped = false; } else { frame_diff--; - panel_timeline->snapped = false; + olive::timeline::snapped = false; } } } @@ -432,13 +434,13 @@ void KeyframeView::mouseReleaseEvent(QMouseEvent*) { selected_fields.at(i)->keyframes.at(selected_keyframes.at(i)).time )); } - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); } select_rect = false; dragging = false; mousedown = false; scroll_drag = false; - panel_timeline->snapped = false; + olive::timeline::snapped = false; update_ui(false); } diff --git a/ui/labelslider.cpp b/ui/labelslider.cpp index 77043a8b3..9aa622a28 100644 --- a/ui/labelslider.cpp +++ b/ui/labelslider.cpp @@ -94,7 +94,7 @@ QString LabelSlider::ValueToString() { } else { switch (display_type) { case FrameNumber: - return frame_to_timecode(long(v), olive::CurrentConfig.timecode_view, frame_rate); + return frame_to_timecode(long(v), olive::config.timecode_view, frame_rate); case Percent: return QString::number((v*100), 'f', decimal_places).append("%"); case Decibel: @@ -311,7 +311,7 @@ void LabelSlider::ShowDialog() if (s.isEmpty()) return; // parse string timecode to a frame number - d = timecode_to_frame(s, olive::CurrentConfig.timecode_view, frame_rate); + d = timecode_to_frame(s, olive::config.timecode_view, frame_rate); } else { diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index 17e55c257..b0fb78497 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -152,27 +152,27 @@ void MainWindow::setup_layout(bool reset) { tabifyDockWidget(panel_footage_viewer, panel_effect_controls); panel_footage_viewer->raise(); addDockWidget(Qt::TopDockWidgetArea, panel_sequence_viewer); - addDockWidget(Qt::BottomDockWidgetArea, panel_timeline); + addDockWidget(Qt::BottomDockWidgetArea, panel_timeline.first()); panel_project.first()->show(); panel_effect_controls->show(); panel_footage_viewer->show(); panel_sequence_viewer->show(); - panel_timeline->show(); + panel_timeline.first()->show(); panel_graph_editor->hide(); panel_project.first()->setFloating(false); panel_effect_controls->setFloating(false); panel_footage_viewer->setFloating(false); panel_sequence_viewer->setFloating(false); - panel_timeline->setFloating(false); + panel_timeline.first()->setFloating(false); panel_graph_editor->setFloating(true); resizeDocks({panel_project.first(), panel_footage_viewer, panel_sequence_viewer}, {width()/3, width()/3, width()/3}, Qt::Horizontal); - resizeDocks({panel_project.first(), panel_timeline}, + resizeDocks({panel_project.first(), panel_timeline.first()}, {height()/2, height()/2}, Qt::Vertical); } @@ -251,7 +251,7 @@ MainWindow::MainWindow(QWidget *parent) : config_dir.mkpath("."); QString config_fn = config_dir.filePath("config.xml"); if (QFileInfo::exists(config_fn)) { - olive::CurrentConfig.load(config_fn); + olive::config.load(config_fn); } } @@ -260,9 +260,9 @@ MainWindow::MainWindow(QWidget *parent) : olive::icon::Initialize(); // Load OpenColorIO configuration if set - if (olive::CurrentConfig.enable_color_management && !olive::CurrentConfig.ocio_config_path.isEmpty()) { + if (olive::config.enable_color_management && !olive::config.ocio_config_path.isEmpty()) { try { - OCIO::SetCurrentConfig(OCIO::Config::CreateFromFile(olive::CurrentConfig.ocio_config_path.toUtf8())); + OCIO::SetCurrentConfig(OCIO::Config::CreateFromFile(olive::config.ocio_config_path.toUtf8())); } catch (OCIO::Exception& e) { QMessageBox::critical(this, tr("OpenColorIO Config Error"), @@ -397,8 +397,8 @@ void MainWindow::Restyle() qApp->setStyle(QStyleFactory::create("Fusion")); // Set up whether to load custom CSS or default CSS+palette - if (!olive::CurrentConfig.css_path.isEmpty() - && load_css_from_file(olive::CurrentConfig.css_path)) { + if (!olive::config.css_path.isEmpty() + && load_css_from_file(olive::config.css_path)) { qApp->setPalette(qApp->style()->standardPalette()); @@ -407,7 +407,7 @@ void MainWindow::Restyle() // set default palette QPalette palette; - if (olive::CurrentConfig.style == olive::styling::kOliveDefaultLight) { + if (olive::config.style == olive::styling::kOliveDefaultLight) { palette.setColor(QPalette::Window, QColor(208, 208, 208)); palette.setColor(QPalette::WindowText, Qt::black); @@ -480,14 +480,14 @@ void MainWindow::Restyle() } void MainWindow::editMenu_About_To_Be_Shown() { - undo_action->setEnabled(olive::UndoStack.canUndo()); - redo_action->setEnabled(olive::UndoStack.canRedo()); + undo_action->setEnabled(olive::undo_stack.canUndo()); + redo_action->setEnabled(olive::undo_stack.canRedo()); } void MainWindow::setup_menus() { QMenuBar* menuBar = new QMenuBar(this); - if (olive::CurrentConfig.use_native_menu_styling) { + if (olive::config.use_native_menu_styling) { OliveGlobal::SetNativeStyling(menuBar); } @@ -538,7 +538,7 @@ void MainWindow::setup_menus() { edit_menu->addSeparator(); select_all_action = MenuHelper::create_menu_action(edit_menu, "selectall", &olive::FocusFilter, SLOT(select_all()), QKeySequence("Ctrl+A")); - deselect_all_action = MenuHelper::create_menu_action(edit_menu, "deselectall", panel_timeline, SLOT(deselect()), QKeySequence("Ctrl+Shift+A")); + deselect_all_action = MenuHelper::create_menu_action(edit_menu, "deselectall", panel_timeline.first(), SLOT(deselect()), QKeySequence("Ctrl+Shift+A")); edit_menu->addSeparator(); @@ -546,16 +546,16 @@ void MainWindow::setup_menus() { edit_menu->addSeparator(); - ripple_to_in_point_ = MenuHelper::create_menu_action(edit_menu, "rippletoin", panel_timeline, SLOT(ripple_to_in_point()), QKeySequence("Q")); - ripple_to_out_point_ = MenuHelper::create_menu_action(edit_menu, "rippletoout", panel_timeline, SLOT(ripple_to_out_point()), QKeySequence("W")); - edit_to_in_point_ = MenuHelper::create_menu_action(edit_menu, "edittoin", panel_timeline, SLOT(edit_to_in_point()), QKeySequence("Ctrl+Alt+Q")); - edit_to_out_point_ = MenuHelper::create_menu_action(edit_menu, "edittoout", panel_timeline, SLOT(edit_to_out_point()), QKeySequence("Ctrl+Alt+W")); + ripple_to_in_point_ = MenuHelper::create_menu_action(edit_menu, "rippletoin", panel_timeline.first(), SLOT(ripple_to_in_point()), QKeySequence("Q")); + ripple_to_out_point_ = MenuHelper::create_menu_action(edit_menu, "rippletoout", panel_timeline.first(), SLOT(ripple_to_out_point()), QKeySequence("W")); + edit_to_in_point_ = MenuHelper::create_menu_action(edit_menu, "edittoin", panel_timeline.first(), SLOT(edit_to_in_point()), QKeySequence("Ctrl+Alt+Q")); + edit_to_out_point_ = MenuHelper::create_menu_action(edit_menu, "edittoout", panel_timeline.first(), SLOT(edit_to_out_point()), QKeySequence("Ctrl+Alt+W")); edit_menu->addSeparator(); olive::MenuHelper.make_inout_menu(edit_menu); - delete_inout_point_ = MenuHelper::create_menu_action(edit_menu, "deleteinout", panel_timeline, SLOT(delete_inout()), QKeySequence(";")); - ripple_delete_inout_point_ = MenuHelper::create_menu_action(edit_menu, "rippledeleteinout", panel_timeline, SLOT(ripple_delete_inout()), QKeySequence("'")); + delete_inout_point_ = MenuHelper::create_menu_action(edit_menu, "deleteinout", panel_timeline.first(), SLOT(delete_inout()), QKeySequence(";")); + ripple_delete_inout_point_ = MenuHelper::create_menu_action(edit_menu, "rippledeleteinout", panel_timeline.first(), SLOT(ripple_delete_inout()), QKeySequence("'")); edit_menu->addSeparator(); @@ -567,21 +567,17 @@ void MainWindow::setup_menus() { zoom_in_ = MenuHelper::create_menu_action(view_menu, "zoomin", &olive::FocusFilter, SLOT(zoom_in()), QKeySequence("=")); zoom_out_ = MenuHelper::create_menu_action(view_menu, "zoomout", &olive::FocusFilter, SLOT(zoom_out()), QKeySequence("-")); - increase_track_height_ = MenuHelper::create_menu_action(view_menu, "vzoomin", panel_timeline, SLOT(IncreaseTrackHeight()), QKeySequence("Ctrl+=")); - decrease_track_height_ = MenuHelper::create_menu_action(view_menu, "vzoomout", panel_timeline, SLOT(DecreaseTrackHeight()), QKeySequence("Ctrl+-")); + increase_track_height_ = MenuHelper::create_menu_action(view_menu, "vzoomin", panel_timeline.first(), SLOT(IncreaseTrackHeight()), QKeySequence("Ctrl+=")); + decrease_track_height_ = MenuHelper::create_menu_action(view_menu, "vzoomout", panel_timeline.first(), SLOT(DecreaseTrackHeight()), QKeySequence("Ctrl+-")); - show_all = MenuHelper::create_menu_action(view_menu, "showall", panel_timeline, SLOT(toggle_show_all()), QKeySequence("\\")); + show_all = MenuHelper::create_menu_action(view_menu, "showall", panel_timeline.first(), SLOT(toggle_show_all()), QKeySequence("\\")); show_all->setCheckable(true); view_menu->addSeparator(); - track_lines = MenuHelper::create_menu_action(view_menu, "tracklines", &olive::MenuHelper, SLOT(toggle_bool_action())); - track_lines->setCheckable(true); - track_lines->setData(reinterpret_cast(&olive::CurrentConfig.show_track_lines)); - rectified_waveforms = MenuHelper::create_menu_action(view_menu, "rectifiedwaveforms", &olive::MenuHelper, SLOT(toggle_bool_action())); rectified_waveforms->setCheckable(true); - rectified_waveforms->setData(reinterpret_cast(&olive::CurrentConfig.rectified_waveforms)); + rectified_waveforms->setData(reinterpret_cast(&olive::config.rectified_waveforms)); view_menu->addSeparator(); @@ -658,8 +654,8 @@ void MainWindow::setup_menus() { playback_menu->addSeparator(); - go_to_prev_cut_ = MenuHelper::create_menu_action(playback_menu, "prevcut", panel_timeline, SLOT(previous_cut()), QKeySequence("Up")); - go_to_next_cut_ = MenuHelper::create_menu_action(playback_menu, "nextcut", panel_timeline, SLOT(next_cut()), QKeySequence("Down")); + go_to_prev_cut_ = MenuHelper::create_menu_action(playback_menu, "prevcut", panel_project.first(), SLOT(previous_cut()), QKeySequence("Up")); + go_to_next_cut_ = MenuHelper::create_menu_action(playback_menu, "nextcut", panel_project.first(), SLOT(next_cut()), QKeySequence("Down")); playback_menu->addSeparator(); @@ -676,7 +672,7 @@ void MainWindow::setup_menus() { loop_action_ = MenuHelper::create_menu_action(playback_menu, "loop", &olive::MenuHelper, SLOT(toggle_bool_action())); loop_action_->setCheckable(true); - loop_action_->setData(reinterpret_cast(&olive::CurrentConfig.loop)); + loop_action_->setData(reinterpret_cast(&olive::config.loop)); // INITIALIZE WINDOW MENU @@ -692,7 +688,7 @@ void MainWindow::setup_menus() { window_timeline_action = MenuHelper::create_menu_action(window_menu, "paneltimeline", this, SLOT(toggle_panel_visibility())); window_timeline_action->setCheckable(true); - window_timeline_action->setData(reinterpret_cast(panel_timeline)); + window_timeline_action->setData(reinterpret_cast(panel_timeline.first())); window_graph_editor_action = MenuHelper::create_menu_action(window_menu, "panelgrapheditor", this, SLOT(toggle_panel_visibility())); window_graph_editor_action->setCheckable(true); @@ -726,49 +722,49 @@ void MainWindow::setup_menus() { pointer_tool_action = MenuHelper::create_menu_action(tools_menu, "pointertool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("V")); pointer_tool_action->setCheckable(true); - pointer_tool_action->setData(reinterpret_cast(panel_timeline->toolArrowButton)); + pointer_tool_action->setData(reinterpret_cast(panel_timeline.first()->toolArrowButton)); tools_group->addAction(pointer_tool_action); edit_tool_action = MenuHelper::create_menu_action(tools_menu, "edittool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("X")); edit_tool_action->setCheckable(true); - edit_tool_action->setData(reinterpret_cast(panel_timeline->toolEditButton)); + edit_tool_action->setData(reinterpret_cast(panel_timeline.first()->toolEditButton)); tools_group->addAction(edit_tool_action); ripple_tool_action = MenuHelper::create_menu_action(tools_menu, "rippletool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("B")); ripple_tool_action->setCheckable(true); - ripple_tool_action->setData(reinterpret_cast(panel_timeline->toolRippleButton)); + ripple_tool_action->setData(reinterpret_cast(panel_timeline.first()->toolRippleButton)); tools_group->addAction(ripple_tool_action); razor_tool_action = MenuHelper::create_menu_action(tools_menu, "razortool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("C")); razor_tool_action->setCheckable(true); - razor_tool_action->setData(reinterpret_cast(panel_timeline->toolRazorButton)); + razor_tool_action->setData(reinterpret_cast(panel_timeline.first()->toolRazorButton)); tools_group->addAction(razor_tool_action); slip_tool_action = MenuHelper::create_menu_action(tools_menu, "sliptool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("Y")); slip_tool_action->setCheckable(true); - slip_tool_action->setData(reinterpret_cast(panel_timeline->toolSlipButton)); + slip_tool_action->setData(reinterpret_cast(panel_timeline.first()->toolSlipButton)); tools_group->addAction(slip_tool_action); slide_tool_action = MenuHelper::create_menu_action(tools_menu, "slidetool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("U")); slide_tool_action->setCheckable(true); - slide_tool_action->setData(reinterpret_cast(panel_timeline->toolSlideButton)); + slide_tool_action->setData(reinterpret_cast(panel_timeline.first()->toolSlideButton)); tools_group->addAction(slide_tool_action); hand_tool_action = MenuHelper::create_menu_action(tools_menu, "handtool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("H")); hand_tool_action->setCheckable(true); - hand_tool_action->setData(reinterpret_cast(panel_timeline->toolHandButton)); + hand_tool_action->setData(reinterpret_cast(panel_timeline.first()->toolHandButton)); tools_group->addAction(hand_tool_action); transition_tool_action = MenuHelper::create_menu_action(tools_menu, "transitiontool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("T")); transition_tool_action->setCheckable(true); - transition_tool_action->setData(reinterpret_cast(panel_timeline->toolTransitionButton)); + transition_tool_action->setData(reinterpret_cast(panel_timeline.first()->toolTransitionButton)); tools_group->addAction(transition_tool_action); tools_menu->addSeparator(); snap_toggle = MenuHelper::create_menu_action(tools_menu, "snapping", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("S")); snap_toggle->setCheckable(true); - snap_toggle->setData(reinterpret_cast(panel_timeline->snappingButton)); + snap_toggle->setData(reinterpret_cast(panel_timeline.first()->snappingButton)); tools_menu->addSeparator(); @@ -850,7 +846,6 @@ void MainWindow::Retranslate() increase_track_height_->setText(tr("Increase Track Height")); decrease_track_height_->setText(tr("Decrease Track Height")); show_all->setText(tr("Toggle Show All")); - track_lines->setText(tr("Track Lines")); rectified_waveforms->setText(tr("Rectified Waveforms")); frames_action->setText(tr("Frames")); drop_frame_action->setText(tr("Drop Frame")); @@ -955,14 +950,10 @@ void MainWindow::closeEvent(QCloseEvent *e) { panel_graph_editor->set_row(nullptr); panel_effect_controls->Clear(true); - olive::Global->set_sequence(nullptr); - panel_footage_viewer->viewer_widget()->close_window(); panel_sequence_viewer->viewer_widget()->close_window(); - panel_footage_viewer->set_main_sequence(); - - olive::UndoStack.clear(); + olive::undo_stack.clear(); QString data_dir = get_data_path(); QString config_path = get_config_path(); @@ -980,7 +971,7 @@ void MainWindow::closeEvent(QCloseEvent *e) { QString config_fn = config_dir.filePath("config.xml"); // save settings - olive::CurrentConfig.save(config_fn); + olive::config.save(config_fn); // save panel layout QFile panel_config(get_config_dir().filePath("layout")); @@ -1123,32 +1114,30 @@ void MainWindow::playbackMenu_About_To_Be_Shown() { } void MainWindow::viewMenu_About_To_Be_Shown() { - olive::MenuHelper.set_bool_action_checked(track_lines); - olive::MenuHelper.set_bool_action_checked(rectified_waveforms); - olive::MenuHelper.set_int_action_checked(frames_action, olive::CurrentConfig.timecode_view); - olive::MenuHelper.set_int_action_checked(drop_frame_action, olive::CurrentConfig.timecode_view); - olive::MenuHelper.set_int_action_checked(nondrop_frame_action, olive::CurrentConfig.timecode_view); - olive::MenuHelper.set_int_action_checked(milliseconds_action, olive::CurrentConfig.timecode_view); + olive::MenuHelper.set_int_action_checked(frames_action, olive::config.timecode_view); + olive::MenuHelper.set_int_action_checked(drop_frame_action, olive::config.timecode_view); + olive::MenuHelper.set_int_action_checked(nondrop_frame_action, olive::config.timecode_view); + olive::MenuHelper.set_int_action_checked(milliseconds_action, olive::config.timecode_view); - title_safe_off->setChecked(!olive::CurrentConfig.show_title_safe_area); - title_safe_default->setChecked(olive::CurrentConfig.show_title_safe_area - && !olive::CurrentConfig.use_custom_title_safe_ratio); - title_safe_43->setChecked(olive::CurrentConfig.show_title_safe_area - && olive::CurrentConfig.use_custom_title_safe_ratio - && qFuzzyCompare(olive::CurrentConfig.custom_title_safe_ratio, title_safe_43->data().toDouble())); - title_safe_169->setChecked(olive::CurrentConfig.show_title_safe_area - && olive::CurrentConfig.use_custom_title_safe_ratio - && qFuzzyCompare(olive::CurrentConfig.custom_title_safe_ratio, title_safe_169->data().toDouble())); - title_safe_custom->setChecked(olive::CurrentConfig.show_title_safe_area - && olive::CurrentConfig.use_custom_title_safe_ratio + title_safe_off->setChecked(!olive::config.show_title_safe_area); + title_safe_default->setChecked(olive::config.show_title_safe_area + && !olive::config.use_custom_title_safe_ratio); + title_safe_43->setChecked(olive::config.show_title_safe_area + && olive::config.use_custom_title_safe_ratio + && qFuzzyCompare(olive::config.custom_title_safe_ratio, title_safe_43->data().toDouble())); + title_safe_169->setChecked(olive::config.show_title_safe_area + && olive::config.use_custom_title_safe_ratio + && qFuzzyCompare(olive::config.custom_title_safe_ratio, title_safe_169->data().toDouble())); + title_safe_custom->setChecked(olive::config.show_title_safe_area + && olive::config.use_custom_title_safe_ratio && !title_safe_43->isChecked() && !title_safe_169->isChecked()); full_screen->setChecked(windowState() == Qt::WindowFullScreen); - show_all->setChecked(panel_timeline->showing_all); + show_all->setChecked(panel_timeline.first()->showing_all); } void MainWindow::toolMenu_About_To_Be_Shown() { @@ -1162,9 +1151,9 @@ void MainWindow::toolMenu_About_To_Be_Shown() { olive::MenuHelper.set_button_action_checked(transition_tool_action); olive::MenuHelper.set_button_action_checked(snap_toggle); - olive::MenuHelper.set_int_action_checked(no_autoscroll, olive::CurrentConfig.autoscroll); - olive::MenuHelper.set_int_action_checked(page_autoscroll, olive::CurrentConfig.autoscroll); - olive::MenuHelper.set_int_action_checked(smooth_autoscroll, olive::CurrentConfig.autoscroll); + olive::MenuHelper.set_int_action_checked(no_autoscroll, olive::config.autoscroll); + olive::MenuHelper.set_int_action_checked(page_autoscroll, olive::config.autoscroll); + olive::MenuHelper.set_int_action_checked(smooth_autoscroll, olive::config.autoscroll); } void MainWindow::toggle_panel_visibility() { diff --git a/ui/mainwindow.h b/ui/mainwindow.h index 7ffd76a32..264e83868 100644 --- a/ui/mainwindow.h +++ b/ui/mainwindow.h @@ -263,7 +263,6 @@ private: QAction* zoom_out_; QAction* increase_track_height_; QAction* decrease_track_height_; - QAction* track_lines; QAction* frames_action; QAction* drop_frame_action; QAction* nondrop_frame_action; diff --git a/ui/menu.cpp b/ui/menu.cpp index a5c877a9a..a77652794 100644 --- a/ui/menu.cpp +++ b/ui/menu.cpp @@ -26,7 +26,7 @@ Menu::Menu(QWidget *parent) : QMenu(parent) { - if (olive::CurrentConfig.use_native_menu_styling) { + if (olive::config.use_native_menu_styling) { OliveGlobal::SetNativeStyling(this); } } @@ -34,7 +34,7 @@ Menu::Menu(QWidget *parent) : Menu::Menu(const QString &title, QWidget *parent) : QMenu(title, parent) { - if (olive::CurrentConfig.use_native_menu_styling) { + if (olive::config.use_native_menu_styling) { OliveGlobal::SetNativeStyling(this); } } diff --git a/ui/menuhelper.cpp b/ui/menuhelper.cpp index 0e0f448f0..e4a38c280 100644 --- a/ui/menuhelper.cpp +++ b/ui/menuhelper.cpp @@ -26,7 +26,7 @@ #include #include "global/config.h" -#include "project/clipboard.h" +#include "global/clipboard.h" #include "ui/mainwindow.h" #include "global/global.h" #include "panels/panels.h" @@ -39,10 +39,10 @@ void MenuHelper::InitializeSharedMenus() new_project_ = create_menu_action(nullptr, "newproj", olive::Global.get(), SLOT(new_project()), QKeySequence("Ctrl+N")); new_project_->setParent(this); - new_sequence_ = create_menu_action(nullptr, "newseq", panel_project, SLOT(new_sequence()), QKeySequence("Ctrl+Shift+N")); + new_sequence_ = create_menu_action(nullptr, "newseq", olive::Global.get(), SLOT(open_new_sequence_dialog()), QKeySequence("Ctrl+Shift+N")); new_sequence_->setParent(this); - new_folder_ = create_menu_action(nullptr, "newfolder", panel_project, SLOT(new_folder())); + new_folder_ = create_menu_action(nullptr, "newfolder", panel_project.first(), SLOT(new_folder())); new_folder_->setParent(this); set_in_point_ = create_menu_action(nullptr, "setinpoint", &olive::FocusFilter, SLOT(set_in_point()), QKeySequence("I")); @@ -60,16 +60,16 @@ void MenuHelper::InitializeSharedMenus() clear_inout_point = create_menu_action(nullptr, "clearinout", &olive::FocusFilter, SLOT(clear_inout()), QKeySequence("G")); clear_inout_point->setParent(this); - add_default_transition_ = create_menu_action(nullptr, "deftransition", panel_timeline, SLOT(add_transition()), QKeySequence("Ctrl+Shift+D")); + add_default_transition_ = create_menu_action(nullptr, "deftransition", panel_timeline.first(), SLOT(add_transition()), QKeySequence("Ctrl+Shift+D")); add_default_transition_->setParent(this); - link_unlink_ = create_menu_action(nullptr, "linkunlink", panel_timeline, SLOT(toggle_links()), QKeySequence("Ctrl+L")); + link_unlink_ = create_menu_action(nullptr, "linkunlink", panel_timeline.first(), SLOT(toggle_links()), QKeySequence("Ctrl+L")); link_unlink_->setParent(this); - enable_disable_ = create_menu_action(nullptr, "enabledisable", panel_timeline, SLOT(toggle_enable_on_selected_clips()), QKeySequence("Shift+E")); + enable_disable_ = create_menu_action(nullptr, "enabledisable", panel_timeline.first(), SLOT(toggle_enable_on_selected_clips()), QKeySequence("Shift+E")); enable_disable_->setParent(this); - nest_ = create_menu_action(nullptr, "nest", panel_timeline, SLOT(nest())); + nest_ = create_menu_action(nullptr, "nest", panel_timeline.first(), SLOT(nest())); nest_->setParent(this); cut_ = create_menu_action(nullptr, "cut", &olive::FocusFilter, SLOT(cut()), QKeySequence("Ctrl+X")); @@ -90,10 +90,10 @@ void MenuHelper::InitializeSharedMenus() delete_ = create_menu_action(nullptr, "delete", &olive::FocusFilter, SLOT(delete_function()), QKeySequence("Del")); delete_->setParent(this); - ripple_delete_ = create_menu_action(nullptr, "rippledelete", panel_timeline, SLOT(ripple_delete()), QKeySequence("Shift+Del")); + ripple_delete_ = create_menu_action(nullptr, "rippledelete", panel_timeline.first(), SLOT(ripple_delete()), QKeySequence("Shift+Del")); ripple_delete_->setParent(this); - split_ = create_menu_action(nullptr, "split", panel_timeline, SLOT(split_at_playhead()), QKeySequence("Ctrl+K")); + split_ = create_menu_action(nullptr, "split", panel_timeline.first(), SLOT(split_at_playhead()), QKeySequence("Ctrl+K")); split_->setParent(this); Retranslate(); @@ -193,23 +193,23 @@ void MenuHelper::set_titlesafe_from_menu() { if (qIsNaN(tsa)) { // disable title safe area - olive::CurrentConfig.show_title_safe_area = false; + olive::config.show_title_safe_area = false; } else { // using title safe area - olive::CurrentConfig.show_title_safe_area = true; + olive::config.show_title_safe_area = true; // are we using the default area aspect ratio, or a specific one if (qIsNull(tsa)) { // default title safe area - olive::CurrentConfig.use_custom_title_safe_ratio = false; + olive::config.use_custom_title_safe_ratio = false; } else { // using a specific aspect ratio - olive::CurrentConfig.use_custom_title_safe_ratio = true; + olive::config.use_custom_title_safe_ratio = true; if (tsa < 0.0) { @@ -229,13 +229,13 @@ void MenuHelper::set_titlesafe_from_menu() { if (!input.isEmpty()) { QStringList inputList = input.split(':'); - olive::CurrentConfig.custom_title_safe_ratio = inputList.at(0).toDouble()/inputList.at(1).toDouble(); + olive::config.custom_title_safe_ratio = inputList.at(0).toDouble()/inputList.at(1).toDouble(); } } else { // specified tsa is a specific custom aspect ratio - olive::CurrentConfig.custom_title_safe_ratio = tsa; + olive::config.custom_title_safe_ratio = tsa; } } @@ -247,7 +247,7 @@ void MenuHelper::set_titlesafe_from_menu() { void MenuHelper::set_autoscroll() { QAction* action = static_cast(sender()); - olive::CurrentConfig.autoscroll = action->data().toInt(); + olive::config.autoscroll = action->data().toInt(); } void MenuHelper::menu_click_button() { @@ -256,7 +256,7 @@ void MenuHelper::menu_click_button() { void MenuHelper::set_timecode_view() { QAction* action = static_cast(sender()); - olive::CurrentConfig.timecode_view = action->data().toInt(); + olive::config.timecode_view = action->data().toInt(); update_ui(false); } @@ -267,8 +267,8 @@ void MenuHelper::open_recent_from_menu() { void MenuHelper::create_effect_paste_action(QMenu *menu) { - QAction* paste_action = menu->addAction(tr("&Paste"), panel_timeline, SLOT(paste(bool))); - paste_action->setEnabled(clipboard.size() > 0 && clipboard_type == CLIPBOARD_TYPE_EFFECT); + QAction* paste_action = menu->addAction(tr("&Paste"), olive::Global.get(), SLOT(paste(bool))); + paste_action->setEnabled(olive::clipboard.Count() > 0 && olive::clipboard.type() == Clipboard::CLIPBOARD_TYPE_EFFECT); } Menu* MenuHelper::create_submenu(QMenuBar* parent, diff --git a/ui/scrollarea.cpp b/ui/scrollarea.cpp deleted file mode 100644 index 579f3fb5f..000000000 --- a/ui/scrollarea.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#include "scrollarea.h" - -#include -#include - -#include "global/config.h" -#include "panels/panels.h" -#include "panels/timeline.h" - -ScrollArea::ScrollArea(QWidget* parent) : QScrollArea(parent) {} - -void ScrollArea::wheelEvent(QWheelEvent *e) { - if (olive::CurrentConfig.scroll_zooms) { - e->ignore(); - - if (e->angleDelta().y() > 0) { - panel_timeline->zoom_in(); - } else if (e->angleDelta().y() < 0) { - panel_timeline->zoom_out(); - } - } else { - QScrollArea::wheelEvent(e); - } -} diff --git a/ui/scrollarea.h b/ui/scrollarea.h deleted file mode 100644 index 1c2ee5082..000000000 --- a/ui/scrollarea.h +++ /dev/null @@ -1,33 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#ifndef SCROLLAREA_H -#define SCROLLAREA_H - -#include - -class ScrollArea : public QScrollArea -{ -public: - ScrollArea(QWidget* parent = 0); - void wheelEvent(QWheelEvent *); -}; - -#endif // SCROLLAREA_H diff --git a/ui/styling.cpp b/ui/styling.cpp index bf1ae3d2b..5d8dfd08f 100644 --- a/ui/styling.cpp +++ b/ui/styling.cpp @@ -24,7 +24,7 @@ bool olive::styling::UseDarkIcons() { - return olive::CurrentConfig.style == kOliveDefaultLight || olive::CurrentConfig.style == kNativeDarkIcons; + return olive::config.style == kOliveDefaultLight || olive::config.style == kNativeDarkIcons; } QColor olive::styling::GetIconColor() @@ -40,5 +40,5 @@ QColor olive::styling::GetIconColor() bool olive::styling::UseNativeUI() { - return olive::CurrentConfig.style == kNativeLightIcons || olive::CurrentConfig.style == kNativeDarkIcons; + return olive::config.style == kNativeLightIcons || olive::config.style == kNativeDarkIcons; } diff --git a/ui/timelinearea.cpp b/ui/timelinearea.cpp index 7f290b425..69f5c3bd1 100644 --- a/ui/timelinearea.cpp +++ b/ui/timelinearea.cpp @@ -1,6 +1,7 @@ #include "timelinearea.h" -TimelineArea::TimelineArea() : +TimelineArea::TimelineArea(Timeline* timeline) : + timeline_(timeline), track_list_(nullptr), alignment_(olive::timeline::kAlignmentTop) { @@ -8,21 +9,24 @@ TimelineArea::TimelineArea() : // LABELS QWidget* label_container = new QWidget(); - QVBoxLayout* label_container_layout = new QVBoxLayout(label_container); + label_container_layout_ = new QVBoxLayout(label_container); layout->addWidget(label_container); // VIEW - view_ = new TimelineView(); + view_ = new TimelineView(timeline_); layout->addWidget(view_); // SCROLLBAR QScrollBar* scrollbar = new QScrollBar(Qt::Vertical); layout->addWidget(scrollbar); + + view_->scrollBar = scrollbar; } void TimelineArea::SetAlignment(olive::timeline::Alignment alignment) { alignment_ = alignment; + view_->SetAlignment(alignment); } void TimelineArea::SetTrackList(Sequence *sequence, Track::Type track_list) @@ -37,7 +41,7 @@ void TimelineArea::SetTrackList(Sequence *sequence, Track::Type track_list) } - + view_->SetTrackList(track_list_); } void TimelineArea::RefreshLabels() @@ -48,7 +52,7 @@ void TimelineArea::RefreshLabels() labels_.resize(track_list_->TrackCount()); for (int i=0;iTrackAt(i)); + labels_[i]->SetTrack(track_list_->TrackAt(i)); } } diff --git a/ui/timelinearea.h b/ui/timelinearea.h index dd8fe0ccc..08f90304c 100644 --- a/ui/timelinearea.h +++ b/ui/timelinearea.h @@ -12,17 +12,19 @@ class TimelineArea : public QWidget { Q_OBJECT public: - TimelineArea(); + TimelineArea(Timeline *timeline); void SetAlignment(olive::timeline::Alignment alignment); void SetTrackList(Sequence* sequence, Track::Type track_list); public slots: void RefreshLabels(); private: + Timeline* timeline_; TrackList* track_list_; TimelineView* view_; - QVector labels_; + QVector labels_; olive::timeline::Alignment alignment_; + QVBoxLayout* label_container_layout_; }; #endif // TIMELINEAREA_H diff --git a/ui/timelineheader.cpp b/ui/timelineheader.cpp index 59f6d3919..996f6e6a5 100644 --- a/ui/timelineheader.cpp +++ b/ui/timelineheader.cpp @@ -28,6 +28,7 @@ #include "mainwindow.h" #include "panels/panels.h" +#include "global/math.h" #include "timeline/sequence.h" #include "undo/undo.h" #include "project/media.h" @@ -93,7 +94,7 @@ int TimelineHeader::getHeaderScreenPointFromFrame(long frame) { void TimelineHeader::set_playhead(int mouse_x) { long frame = getHeaderFrameFromScreenPoint(mouse_x); - if (snapping) panel_timeline->snap_to_timeline(&frame, false, true, true); + if (snapping) viewer->seq->SnapPoint(&frame, zoom, false, true, true); if (frame != viewer->seq->playhead) { viewer->seek(frame); } @@ -113,10 +114,10 @@ void TimelineHeader::set_in_point(long new_in) { if (new_out == new_in) { new_in--; } else if (new_out < new_in) { - new_out = viewer->seq->getEndFrame(); + new_out = viewer->seq->GetEndFrame(); } - olive::UndoStack.push(new SetTimelineInOutCommand(viewer->seq.get(), true, new_in, new_out)); + olive::undo_stack.push(new SetTimelineInOutCommand(viewer->seq.get(), true, new_in, new_out)); update_parents(); } @@ -128,7 +129,7 @@ void TimelineHeader::set_out_point(long new_out) { new_in = 0; } - olive::UndoStack.push(new SetTimelineInOutCommand(viewer->seq.get(), true, new_in, new_out)); + olive::undo_stack.push(new SetTimelineInOutCommand(viewer->seq.get(), true, new_in, new_out)); update_parents(); } @@ -149,7 +150,7 @@ void TimelineHeader::show_text(bool enable) { void TimelineHeader::mousePressEvent(QMouseEvent* event) { if (viewer->seq != nullptr && event->buttons() & Qt::LeftButton) { if (resizing_workarea) { - sequence_end = viewer->seq->getEndFrame(); + sequence_end = viewer->seq->GetEndFrame(); } else { /*int QPoint start(in_x, height()+2); @@ -215,7 +216,7 @@ void TimelineHeader::mouseMoveEvent(QMouseEvent* event) { if (dragging) { if (resizing_workarea) { long frame = getHeaderFrameFromScreenPoint(event->pos().x()); - if (snapping) panel_timeline->snap_to_timeline(&frame, true, true, false); + if (snapping) viewer->seq->SnapPoint(&frame, zoom, true, true, false); if (resizing_workarea_in) { temp_workarea_in = qMax(qMin(temp_workarea_out-1, frame), 0L); @@ -230,7 +231,7 @@ void TimelineHeader::mouseMoveEvent(QMouseEvent* event) { // snap markers for (int i=0;isnap_to_timeline(&fm, true, false, true)) { + if (snapping && viewer->seq->SnapPoint(&fm, zoom, true, false, true)) { frame_movement = fm - selected_marker_original_times.at(i); break; } @@ -281,7 +282,7 @@ void TimelineHeader::mouseReleaseEvent(QMouseEvent*) { if (viewer->seq != nullptr) { dragging = false; if (resizing_workarea) { - olive::UndoStack.push(new SetTimelineInOutCommand(viewer->seq.get(), true, temp_workarea_in, temp_workarea_out)); + olive::undo_stack.push(new SetTimelineInOutCommand(viewer->seq.get(), true, temp_workarea_in, temp_workarea_out)); } else if (dragging_markers && selected_markers.size() > 0) { bool moved = false; ComboAction* ca = new ComboAction(); @@ -293,7 +294,7 @@ void TimelineHeader::mouseReleaseEvent(QMouseEvent*) { } } if (moved) { - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); } else { delete ca; } @@ -302,7 +303,7 @@ void TimelineHeader::mouseReleaseEvent(QMouseEvent*) { resizing_workarea = false; dragging = false; dragging_markers = false; - panel_timeline->snapped = false; + olive::timeline::snapped = false; update_parents(); } } @@ -331,7 +332,7 @@ void TimelineHeader::delete_markers() { // Send command to delete selected markers DeleteMarkerAction* dma = new DeleteMarkerAction(viewer->marker_ref); dma->markers.append(selected_markers); - olive::UndoStack.push(dma); + olive::undo_stack.push(dma); // remove any indices for the selected markers that no longer exist for (int i=0;i lastTextBoundary) { - timecode = frame_to_timecode(frame + in_visible, olive::CurrentConfig.timecode_view, viewer->seq->frame_rate); + timecode = frame_to_timecode(frame + in_visible, olive::config.timecode_view, viewer->seq->frame_rate); fullTextWidth = fm.width(timecode); textWidth = fullTextWidth>>1; text_x = lineX; // centers the text to that point on the timeline, LEFT aligns it if not - if (olive::CurrentConfig.center_timeline_timecodes) { + if (olive::config.center_timeline_timecodes) { text_x -= textWidth; } else { text_x += TEXT_PADDING_FROM_LINE; @@ -415,7 +416,7 @@ void TimelineHeader::paintEvent(QPaintEvent*) { // draw line markers p.setPen(Qt::gray); - p.drawLine(lineX, (!olive::CurrentConfig.center_timeline_timecodes && draw_text) ? 0 : yoff, lineX, height()); + p.drawLine(lineX, (!olive::config.center_timeline_timecodes && draw_text) ? 0 : yoff, lineX, height()); // draw sub-line markers for (int j=1;jsetCheckable(true); - center_timecodes->setChecked(olive::CurrentConfig.center_timeline_timecodes); - center_timecodes->setData(reinterpret_cast(&olive::CurrentConfig.center_timeline_timecodes)); + center_timecodes->setChecked(olive::config.center_timeline_timecodes); + center_timecodes->setData(reinterpret_cast(&olive::config.center_timeline_timecodes)); menu.exec(mapToGlobal(pos)); } diff --git a/ui/timelinelabel.h b/ui/timelinelabel.h index 448f5d955..6ca1d983f 100644 --- a/ui/timelinelabel.h +++ b/ui/timelinelabel.h @@ -2,6 +2,7 @@ #define TIMELINELABEL_H #include +#include #include "timeline/track.h" @@ -20,4 +21,6 @@ private: Track* track_; }; +using TimelineLabelPtr = std::shared_ptr; + #endif // TIMELINELABEL_H diff --git a/ui/timelineview.cpp b/ui/timelineview.cpp index f9e8cd484..bdf705443 100644 --- a/ui/timelineview.cpp +++ b/ui/timelineview.cpp @@ -59,17 +59,20 @@ #include "effects/effect.h" #include "effects/internal/solideffect.h" #include "timeline/track.h" +#include "global/math.h" +#include "project/projectfunctions.h" #define MAX_TEXT_WIDTH 20 #define TRANSITION_BETWEEN_RANGE 40 -TimelineView::TimelineView(QWidget *parent) : QWidget(parent) { - selection_command = nullptr; - self_created_sequence = nullptr; - scroll = 0; - - bottom_align = false; - track_resizing = false; +TimelineView::TimelineView(Timeline *parent) : + timeline_(parent), + self_created_sequence(nullptr), + track_list_(nullptr), + scroll(0), + alignment_(olive::timeline::kAlignmentTop), + track_resizing(false) +{ setMouseTracking(true); setFocusPolicy(Qt::ClickFocus); @@ -83,11 +86,23 @@ TimelineView::TimelineView(QWidget *parent) : QWidget(parent) { connect(&tooltip_timer, SIGNAL(timeout()), this, SLOT(tooltip_timer_timeout())); } +void TimelineView::SetAlignment(olive::timeline::Alignment alignment) +{ + alignment_ = alignment; +} + +void TimelineView::SetTrackList(TrackList *tl) +{ + track_list_ = tl; + + update(); +} + void TimelineView::show_context_menu(const QPoint& pos) { - if (olive::ActiveSequence != nullptr) { + if (sequence() != nullptr) { // hack because sometimes right clicking doesn't trigger mouse release event - panel_timeline->rect_select_init = false; - panel_timeline->rect_select_proc = false; + ParentTimeline()->rect_select_init = false; + ParentTimeline()->rect_select_proc = false; Menu menu(this); @@ -95,12 +110,12 @@ void TimelineView::show_context_menu(const QPoint& pos) { QAction* redoAction = menu.addAction(tr("&Redo")); connect(undoAction, SIGNAL(triggered(bool)), olive::Global.get(), SLOT(undo())); connect(redoAction, SIGNAL(triggered(bool)), olive::Global.get(), SLOT(redo())); - undoAction->setEnabled(olive::UndoStack.canUndo()); - redoAction->setEnabled(olive::UndoStack.canRedo()); + undoAction->setEnabled(olive::undo_stack.canUndo()); + redoAction->setEnabled(olive::undo_stack.canRedo()); menu.addSeparator(); // collect all the selected clips - QVector selected_clips = olive::ActiveSequence->SelectedClips(); + QVector selected_clips = sequence()->SelectedClips(); olive::MenuHelper.make_edit_functions_menu(&menu, !selected_clips.isEmpty()); @@ -108,12 +123,13 @@ void TimelineView::show_context_menu(const QPoint& pos) { // no clips are selected // determine if we can perform a ripple empty space - panel_timeline->cursor_frame = panel_timeline->getTimelineFrameFromScreenPoint(pos.x()); - panel_timeline->cursor_track = getTrackFromScreenPoint(pos.y()); + ParentTimeline()->cursor_frame = ParentTimeline()->getTimelineFrameFromScreenPoint(pos.x()); + ParentTimeline()->cursor_track = getTrackFromScreenPoint(pos.y()); - if (panel_timeline->can_ripple_empty_space(panel_timeline->cursor_frame, panel_timeline->cursor_track)) { + // check if the space the cursor is currently at is empty + if (ParentTimeline()->cursor_track->GetClipFromPoint(ParentTimeline()->cursor_frame) == nullptr) { QAction* ripple_delete_action = menu.addAction(tr("R&ipple Delete Empty Space")); - connect(ripple_delete_action, SIGNAL(triggered(bool)), panel_timeline, SLOT(ripple_delete_empty_space())); + connect(ripple_delete_action, SIGNAL(triggered(bool)), ParentTimeline(), SLOT(ripple_delete_empty_space())); } QAction* seq_settings = menu.addAction(tr("Sequence Settings")); @@ -171,7 +187,7 @@ void TimelineView::show_context_menu(const QPoint& pos) { } void TimelineView::toggle_autoscale() { - QVector selected_clips = olive::ActiveSequence->SelectedClips(); + QVector selected_clips = sequence()->SelectedClips(); if (!selected_clips.isEmpty()) { SetClipProperty* action = new SetClipProperty(kSetClipPropertyAutoscale); @@ -181,7 +197,7 @@ void TimelineView::toggle_autoscale() { action->AddSetting(c, !c->autoscaled()); } - olive::UndoStack.push(action); + olive::undo_stack.push(action); } } @@ -190,9 +206,9 @@ void TimelineView::tooltip_timer_timeout() { QToolTip::showText(QCursor::pos(), tr("%1\nStart: %2\nEnd: %3\nDuration: %4").arg( tooltip_clip->name(), - frame_to_timecode(tooltip_clip->timeline_in(), olive::CurrentConfig.timecode_view, olive::ActiveSequence->frame_rate), - frame_to_timecode(tooltip_clip->timeline_out(), olive::CurrentConfig.timecode_view, olive::ActiveSequence->frame_rate), - frame_to_timecode(tooltip_clip->length(), olive::CurrentConfig.timecode_view, olive::ActiveSequence->frame_rate) + frame_to_timecode(tooltip_clip->timeline_in(), olive::config.timecode_view, sequence()->frame_rate), + frame_to_timecode(tooltip_clip->timeline_out(), olive::config.timecode_view, sequence()->frame_rate), + frame_to_timecode(tooltip_clip->length(), olive::config.timecode_view, sequence()->frame_rate) )); } @@ -203,7 +219,7 @@ void TimelineView::open_sequence_properties() { QVector sequence_items = olive::project_model.GetAllSequences(); for (int i=0;ito_sequence() == olive::ActiveSequence) { + if (sequence_items.at(i)->to_sequence().get() == sequence()) { NewSequenceDialog nsd(this, sequence_items.at(i)); nsd.exec(); return; @@ -216,7 +232,7 @@ void TimelineView::open_sequence_properties() { void TimelineView::show_clip_properties() { // get list of selected clips - QVector selected_clips = olive::ActiveSequence->SelectedClips(); + QVector selected_clips = sequence()->SelectedClips(); // if clips are selected, open the clip properties dialog if (!selected_clips.isEmpty()) { @@ -225,15 +241,11 @@ void TimelineView::show_clip_properties() } } -bool same_sign(int a, int b) { - return (a < 0) == (b < 0); -} - void TimelineView::dragEnterEvent(QDragEnterEvent *event) { bool import_init = false; QVector media_list; - panel_timeline->importing_files = false; + ParentTimeline()->importing_files = false; for (int i=0;iIsProjectWidget(event->source())) { @@ -252,16 +264,16 @@ void TimelineView::dragEnterEvent(QDragEnterEvent *event) { } if (event->source() == panel_footage_viewer) { - if (panel_footage_viewer->seq != olive::ActiveSequence) { // don't allow nesting the same sequence + if (panel_footage_viewer->seq.get() != sequence()) { // don't allow nesting the same sequence media_list.append(olive::timeline::MediaImportData(panel_footage_viewer->media, - static_cast(event->mimeData()->text().toInt()))); + static_cast(event->mimeData()->text().toInt()))); import_init = true; } } - if (olive::CurrentConfig.enable_drag_files_to_timeline && event->mimeData()->hasUrls()) { + if (olive::config.enable_drag_files_to_timeline && event->mimeData()->hasUrls()) { QList urls = event->mimeData()->urls(); if (!urls.isEmpty()) { QStringList file_list; @@ -270,10 +282,11 @@ void TimelineView::dragEnterEvent(QDragEnterEvent *event) { file_list.append(urls.at(i).toLocalFile()); } - panel_project->process_file_list(file_list); + olive::project_model.process_file_list(file_list); - for (int i=0;ilast_imported_media.size();i++) { - Footage* f = panel_project->last_imported_media.at(i)->to_footage(); + QVector last_imported_media = olive::project_model.GetLastImportedMedia(); + for (int i=0;ito_footage(); // waits for media to have a duration // TODO would be much nicer if this was multithreaded @@ -281,15 +294,15 @@ void TimelineView::dragEnterEvent(QDragEnterEvent *event) { f->ready_lock.unlock(); if (f->ready) { - media_list.append(panel_project->last_imported_media.at(i)); + media_list.append(last_imported_media.at(i)); } } if (media_list.isEmpty()) { - olive::UndoStack.undo(); + olive::undo_stack.undo(); } else { import_init = true; - panel_timeline->importing_files = true; + ParentTimeline()->importing_files = true; } } } @@ -298,35 +311,35 @@ void TimelineView::dragEnterEvent(QDragEnterEvent *event) { event->acceptProposedAction(); long entry_point; - Sequence* seq = olive::ActiveSequence.get(); + Sequence* seq = sequence(); if (seq == nullptr) { // if no sequence, we're going to create a new one using the clips as a reference entry_point = 0; - self_created_sequence = create_sequence_from_media(media_list); + self_created_sequence = olive::project::CreateSequenceFromMedia(media_list); seq = self_created_sequence.get(); } else { - entry_point = panel_timeline->getTimelineFrameFromScreenPoint(event->pos().x()); - panel_timeline->drag_frame_start = entry_point + getFrameFromScreenPoint(panel_timeline->zoom, 50); - panel_timeline->drag_track_start = (bottom_align) ? -1 : 0; + entry_point = ParentTimeline()->getTimelineFrameFromScreenPoint(event->pos().x()); + ParentTimeline()->drag_frame_start = entry_point + getFrameFromScreenPoint(ParentTimeline()->zoom, 50); + ParentTimeline()->drag_track_start = track_list_->First(); } - panel_timeline->create_ghosts_from_media(seq, entry_point, media_list); + ParentTimeline()->ghosts = olive::timeline::CreateGhostsFromMedia(seq, entry_point, media_list); - panel_timeline->importing = true; + ParentTimeline()->importing = true; } } void TimelineView::dragMoveEvent(QDragMoveEvent *event) { - if (panel_timeline->importing) { + if (ParentTimeline()->importing) { event->acceptProposedAction(); - if (olive::ActiveSequence != nullptr) { + if (sequence() != nullptr) { QPoint pos = event->pos(); - panel_timeline->scroll_to_frame(panel_timeline->getTimelineFrameFromScreenPoint(event->pos().x())); + ParentTimeline()->scroll_to_frame(ParentTimeline()->getTimelineFrameFromScreenPoint(event->pos().x())); update_ghosts(pos, event->keyboardModifiers() & Qt::ShiftModifier); - panel_timeline->move_insert = ((event->keyboardModifiers() & Qt::ControlModifier) && (panel_timeline->tool == TIMELINE_TOOL_POINTER || panel_timeline->importing)); + ParentTimeline()->move_insert = ((event->keyboardModifiers() & Qt::ControlModifier) && (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_POINTER || ParentTimeline()->importing)); update_ui(false); } } @@ -344,11 +357,11 @@ void TimelineView::wheelEvent(QWheelEvent *event) { // "Scroll Zooms" false + Control down: zooming // "Scroll Zooms" true + Control up : zooming // "Scroll Zooms" true + Control down: not zooming - bool zooming = (olive::CurrentConfig.scroll_zooms != ctrl); + bool zooming = (olive::config.scroll_zooms != ctrl); // Allow shift for axis swap, but don't swap on zoom... Unless // we need to override Qt's axis swap via Alt - bool swap_hv = ((shift != olive::CurrentConfig.invert_timeline_scroll_axes) & + bool swap_hv = ((shift != olive::config.invert_timeline_scroll_axes) & !zooming) | (alt & !shift & zooming); int delta_h = swap_hv ? event->angleDelta().y() : event->angleDelta().x(); @@ -371,7 +384,7 @@ void TimelineView::wheelEvent(QWheelEvent *event) { zoom_ratio = 1.0 / zoom_ratio; } - panel_timeline->multiply_zoom(zoom_ratio); + ParentTimeline()->multiply_zoom(zoom_ratio); } } else { @@ -380,7 +393,7 @@ void TimelineView::wheelEvent(QWheelEvent *event) { // widget's scrollbar for vertical scrolling. QScrollBar* bar_v = scrollBar; - QScrollBar* bar_h = panel_timeline->horizontalScrollBar; + QScrollBar* bar_h = ParentTimeline()->horizontalScrollBar; // Match the wheel events to the size of a step as per // https://doc.qt.io/qt-5/qwheelevent.html#angleDelta @@ -397,13 +410,13 @@ void TimelineView::wheelEvent(QWheelEvent *event) { void TimelineView::dragLeaveEvent(QDragLeaveEvent* event) { event->accept(); - if (panel_timeline->importing) { - if (panel_timeline->importing_files) { - olive::UndoStack.undo(); + if (ParentTimeline()->importing) { + if (ParentTimeline()->importing_files) { + olive::undo_stack.undo(); } - panel_timeline->importing_files = false; - panel_timeline->ghosts.clear(); - panel_timeline->importing = false; + ParentTimeline()->importing_files = false; + ParentTimeline()->ghosts.clear(); + ParentTimeline()->importing = false; update_ui(false); } if (self_created_sequence != nullptr) { @@ -412,21 +425,16 @@ void TimelineView::dragLeaveEvent(QDragLeaveEvent* event) { } } -void delete_area_under_ghosts(ComboAction* ca) { +void TimelineView::delete_area_under_ghosts(ComboAction* ca, Sequence* s) { // delete areas before adding QVector delete_areas; - for (int i=0;ighosts.size();i++) { - const Ghost& g = panel_timeline->ghosts.at(i); - Selection sel; - sel.in = g.in; - sel.out = g.out; - sel.track = g.track; - delete_areas.append(sel); + for (int i=0;ighosts.size();i++) { + delete_areas.append(ParentTimeline()->ghosts.at(i).ToSelection()); } - panel_timeline->delete_areas_and_relink(ca, delete_areas, false); + s->DeleteAreas(ca, delete_areas, false); } -void insert_clips(ComboAction* ca) { +void TimelineView::insert_clips(ComboAction* ca, Sequence* s) { bool ripple_old_point = true; long earliest_old_point = LONG_MAX; @@ -435,16 +443,16 @@ void insert_clips(ComboAction* ca) { long earliest_new_point = LONG_MAX; long latest_new_point = LONG_MIN; - QVector ignore_clips; - for (int i=0;ighosts.size();i++) { - const Ghost& g = panel_timeline->ghosts.at(i); + QVector ignore_clips; + for (int i=0;ighosts.size();i++) { + const Ghost& g = ParentTimeline()->ghosts.at(i); earliest_old_point = qMin(earliest_old_point, g.old_in); latest_old_point = qMax(latest_old_point, g.old_out); earliest_new_point = qMin(earliest_new_point, g.in); latest_new_point = qMax(latest_new_point, g.out); - if (g.clip >= 0) { + if (g.clip != nullptr) { ignore_clips.append(g.clip); } else { // don't try to close old gap if importing @@ -452,79 +460,81 @@ void insert_clips(ComboAction* ca) { } } - for (int i=0;iclips.size();i++) { - ClipPtr c = olive::ActiveSequence->clips.at(i); - if (c != nullptr) { - // don't split any clips that are moving - bool found = false; - for (int j=0;jghosts.size();j++) { - if (panel_timeline->ghosts.at(j).clip == i) { - found = true; - break; - } + QVector sequence_clips = sequence()->GetAllClips(); + for (int i=0;ighosts.size();j++) { + if (ParentTimeline()->ghosts.at(j).clip == c) { + found = true; + break; + } + } + if (!found) { + if (c->timeline_in() < earliest_new_point && c->timeline_out() > earliest_new_point) { + sequence()->SplitClipAtPositions(ca, c, {earliest_new_point}, true); } - if (!found) { - if (c->timeline_in() < earliest_new_point && c->timeline_out() > earliest_new_point) { - panel_timeline->split_clip_and_relink(ca, i, earliest_new_point, true); - } - // determine if we should close the gap the old clips left behind - if (ripple_old_point - && !((c->timeline_in() < earliest_old_point && c->timeline_out() <= earliest_old_point) || (c->timeline_in() >= latest_old_point && c->timeline_out() > latest_old_point)) - && !ignore_clips.contains(i)) { - ripple_old_point = false; - } + // determine if we should close the gap the old clips left behind + if (ripple_old_point + && !((c->timeline_in() < earliest_old_point && c->timeline_out() <= earliest_old_point) || (c->timeline_in() >= latest_old_point && c->timeline_out() > latest_old_point)) + && !ignore_clips.contains(c)) { + ripple_old_point = false; } } } long ripple_length = (latest_new_point - earliest_new_point); - ripple_clips(ca, olive::ActiveSequence.get(), earliest_new_point, ripple_length, ignore_clips); + sequence()->Ripple(ca, earliest_new_point, ripple_length, ignore_clips); if (ripple_old_point) { // works for moving later clips earlier but not earlier to later long second_ripple_length = (earliest_old_point - latest_old_point); - ripple_clips(ca, olive::ActiveSequence.get(), latest_old_point, second_ripple_length, ignore_clips); + sequence()->Ripple(ca, latest_old_point, second_ripple_length, ignore_clips); if (earliest_old_point < earliest_new_point) { - for (int i=0;ighosts.size();i++) { - Ghost& g = panel_timeline->ghosts[i]; + for (int i=0;ighosts.size();i++) { + Ghost& g = ParentTimeline()->ghosts[i]; g.in += second_ripple_length; g.out += second_ripple_length; } - for (int i=0;iselections.size();i++) { - Selection& s = olive::ActiveSequence->selections[i]; - s.in += second_ripple_length; - s.out += second_ripple_length; + + QVector sequence_selections = sequence()->Selections(); + for (int i=0;iSetSelections(sequence_selections); } } } void TimelineView::dropEvent(QDropEvent* event) { - if (panel_timeline->importing && panel_timeline->ghosts.size() > 0) { + if (ParentTimeline()->importing && ParentTimeline()->ghosts.size() > 0) { event->acceptProposedAction(); ComboAction* ca = new ComboAction(); - Sequence* s = olive::ActiveSequence.get(); + Sequence* s = sequence(); // if we're dropping into nothing, create a new sequences based on the clip being dragged if (s == nullptr) { s = self_created_sequence.get(); - panel_project->create_sequence_internal(ca, self_created_sequence, true, nullptr); + olive::project_model.CreateSequence(ca, self_created_sequence, true, nullptr); self_created_sequence = nullptr; } else if (event->keyboardModifiers() & Qt::ControlModifier) { - insert_clips(ca); + insert_clips(ca, s); } else { - delete_area_under_ghosts(ca); + delete_area_under_ghosts(ca, s); } - panel_timeline->add_clips_from_ghosts(ca, s); + s->AddClipsFromGhosts(ca, ParentTimeline()->ghosts); - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); setFocus(); @@ -533,64 +543,71 @@ void TimelineView::dropEvent(QDropEvent* event) { } void TimelineView::mouseDoubleClickEvent(QMouseEvent *event) { - if (olive::ActiveSequence != nullptr) { - if (panel_timeline->tool == TIMELINE_TOOL_EDIT) { - int clip_index = getClipIndexFromCoords(panel_timeline->cursor_frame, panel_timeline->cursor_track); - if (clip_index >= 0) { - ClipPtr clip = olive::ActiveSequence->clips.at(clip_index); - if (!(event->modifiers() & Qt::ShiftModifier)) olive::ActiveSequence->selections.clear(); - Selection s; - s.in = clip->timeline_in(); - s.out = clip->timeline_out(); - s.track = clip->track(); - olive::ActiveSequence->selections.append(s); + if (sequence() != nullptr) { + if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_EDIT) { + Clip* clip = GetClipAtCursor(); + if (clip != nullptr) { + if (!(event->modifiers() & Qt::ShiftModifier)) { + sequence()->ClearSelections(); + } + clip->track()->SelectClip(clip); update_ui(false); } - } else if (panel_timeline->tool == TIMELINE_TOOL_POINTER) { - int clip_index = getClipIndexFromCoords(panel_timeline->cursor_frame, panel_timeline->cursor_track); - if (clip_index >= 0) { - ClipPtr c = olive::ActiveSequence->clips.at(clip_index); + } else if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_POINTER) { + Clip* c = GetClipAtCursor(); + if (c != nullptr) { if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_SEQUENCE) { - olive::Global->set_sequence(c->media()->to_sequence()); + Timeline::OpenSequence(c->media()->to_sequence()); } } } } } -bool current_tool_shows_cursor() { - return (panel_timeline->tool == TIMELINE_TOOL_EDIT || panel_timeline->tool == TIMELINE_TOOL_RAZOR || panel_timeline->creating); +bool TimelineView::current_tool_shows_cursor() { + return (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_EDIT + || olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_RAZOR + || ParentTimeline()->creating); +} + +Clip *TimelineView::GetClipAtCursor() +{ + if (ParentTimeline()->cursor_track == nullptr) { + return nullptr; + } + + return ParentTimeline()->cursor_track->GetClipFromPoint(ParentTimeline()->cursor_frame); } void TimelineView::mousePressEvent(QMouseEvent *event) { - if (olive::ActiveSequence != nullptr) { + if (sequence() != nullptr) { - int effective_tool = panel_timeline->tool; + int effective_tool = olive::timeline::current_tool; // some user actions will override which tool we'll be using if (event->button() == Qt::MiddleButton) { - effective_tool = TIMELINE_TOOL_HAND; - panel_timeline->creating = false; + effective_tool = olive::timeline::TIMELINE_TOOL_HAND; + ParentTimeline()->creating = false; } else if (event->button() == Qt::RightButton) { - effective_tool = TIMELINE_TOOL_MENU; - panel_timeline->creating = false; + effective_tool = olive::timeline::TIMELINE_TOOL_MENU; + ParentTimeline()->creating = false; } // ensure cursor_frame and cursor_track are up to date mouseMoveEvent(event); // store current cursor positions - panel_timeline->drag_x_start = event->pos().x(); - panel_timeline->drag_y_start = event->pos().y(); + ParentTimeline()->drag_x_start = event->pos().x(); + ParentTimeline()->drag_y_start = event->pos().y(); // store current frame/tracks as the values to start dragging from - panel_timeline->drag_frame_start = panel_timeline->cursor_frame; - panel_timeline->drag_track_start = panel_timeline->cursor_track; + ParentTimeline()->drag_frame_start = ParentTimeline()->cursor_frame; + ParentTimeline()->drag_track_start = ParentTimeline()->cursor_track; // get the clip the user is currently hovering over, priority to trim_target set from mouseMoveEvent - int hovered_clip = panel_timeline->trim_target == -1 ? - getClipIndexFromCoords(panel_timeline->cursor_frame, panel_timeline->cursor_track) - : panel_timeline->trim_target; + Clip* hovered_clip = ParentTimeline()->trim_target == nullptr ? + GetClipAtCursor() + : ParentTimeline()->trim_target; bool shift = (event->modifiers() & Qt::ShiftModifier); bool alt = (event->modifiers() & Qt::AltModifier); @@ -599,40 +616,39 @@ void TimelineView::mousePressEvent(QMouseEvent *event) { // to the existing selections. `selection_offset` is the index to change selections from (and we don't touch // any prior to that) if (shift) { - panel_timeline->selection_offset = olive::ActiveSequence->selections.size(); + ParentTimeline()->selection_offset = sequence()->Selections().size(); } else { - panel_timeline->selection_offset = 0; + ParentTimeline()->selection_offset = 0; } // if the user is creating an object - if (panel_timeline->creating) { - int comp = 0; - switch (panel_timeline->creating_object) { + if (ParentTimeline()->creating) { + Track::Type create_type = Track::kTypeVideo; + switch (ParentTimeline()->creating_object) { case olive::timeline::ADD_OBJ_TITLE: case olive::timeline::ADD_OBJ_SOLID: case olive::timeline::ADD_OBJ_BARS: - comp = -1; break; case olive::timeline::ADD_OBJ_TONE: case olive::timeline::ADD_OBJ_NOISE: case olive::timeline::ADD_OBJ_AUDIO: - comp = 1; + create_type = Track::kTypeAudio; break; } // if the track the user clicked is correct for the type of object we're adding - if ((panel_timeline->drag_track_start < 0) == (comp < 0)) { + if (ParentTimeline()->drag_track_start->type() == create_type) { Ghost g; - g.in = g.old_in = g.out = g.old_out = panel_timeline->drag_frame_start; - g.track = g.old_track = panel_timeline->drag_track_start; + g.in = g.old_in = g.out = g.old_out = ParentTimeline()->drag_frame_start; + g.track = g.old_track = ParentTimeline()->drag_track_start; g.transition = nullptr; - g.clip = -1; + g.clip = nullptr; g.trim_type = olive::timeline::TRIM_OUT; - panel_timeline->ghosts.append(g); + ParentTimeline()->ghosts.append(g); - panel_timeline->moving_init = true; - panel_timeline->moving_proc = true; + ParentTimeline()->moving_init = true; + ParentTimeline()->moving_proc = true; } } else { @@ -640,73 +656,75 @@ void TimelineView::mousePressEvent(QMouseEvent *event) { switch (effective_tool) { // many tools share pointer-esque behavior - case TIMELINE_TOOL_POINTER: - case TIMELINE_TOOL_RIPPLE: - case TIMELINE_TOOL_SLIP: - case TIMELINE_TOOL_ROLLING: - case TIMELINE_TOOL_SLIDE: - case TIMELINE_TOOL_MENU: + case olive::timeline::TIMELINE_TOOL_POINTER: + case olive::timeline::TIMELINE_TOOL_RIPPLE: + case olive::timeline::TIMELINE_TOOL_SLIP: + case olive::timeline::TIMELINE_TOOL_ROLLING: + case olive::timeline::TIMELINE_TOOL_SLIDE: + case olive::timeline::TIMELINE_TOOL_MENU: { - if (track_resizing && effective_tool != TIMELINE_TOOL_MENU) { + if (track_resizing && effective_tool != olive::timeline::TIMELINE_TOOL_MENU) { // if the cursor is currently hovering over a track, init track resizing - panel_timeline->moving_init = true; + ParentTimeline()->moving_init = true; } else { // check if we're currently hovering over a clip or not - if (hovered_clip >= 0) { - Clip* clip = olive::ActiveSequence->clips.at(hovered_clip).get(); + if (hovered_clip != nullptr) { - if (clip->IsSelected()) { + if (hovered_clip->IsSelected()) { if (shift) { // if the user clicks a selected clip while holding shift, deselect the clip - panel_timeline->deselect_area(clip->timeline_in(), clip->timeline_out(), clip->track()); + hovered_clip->track()->DeselectArea(hovered_clip->timeline_in(), hovered_clip->timeline_out()); // if the user isn't holding alt, also deselect all of its links as well if (!alt) { - for (int i=0;ilinked.size();i++) { - ClipPtr link = olive::ActiveSequence->clips.at(clip->linked.at(i)); - panel_timeline->deselect_area(link->timeline_in(), link->timeline_out(), link->track()); + for (int i=0;ilinked.size();i++) { + Clip* link = hovered_clip->linked.at(i); + link->track()->DeselectArea(link->timeline_in(), link->timeline_out()); } } - } else if (panel_timeline->tool == TIMELINE_TOOL_POINTER - && panel_timeline->transition_select != kTransitionNone) { + } else if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_POINTER + && ParentTimeline()->transition_select != kTransitionNone) { // if the clip was selected by then the user clicked a transition, de-select the clip and its links // and select the transition only - panel_timeline->deselect_area(clip->timeline_in(), clip->timeline_out(), clip->track()); + hovered_clip->track()->DeselectArea(hovered_clip->timeline_in(), hovered_clip->timeline_out()); - for (int i=0;ilinked.size();i++) { - ClipPtr link = olive::ActiveSequence->clips.at(clip->linked.at(i)); - panel_timeline->deselect_area(link->timeline_in(), link->timeline_out(), link->track()); + for (int i=0;ilinked.size();i++) { + Clip* link = hovered_clip->linked.at(i); + link->track()->DeselectArea(link->timeline_in(), link->timeline_out()); } - Selection s; - s.track = clip->track(); + long s_in, s_out; // select the transition only - if (panel_timeline->transition_select == kTransitionOpening && clip->opening_transition != nullptr) { - s.in = clip->timeline_in(); + if (ParentTimeline()->transition_select == kTransitionOpening + && hovered_clip->opening_transition != nullptr) { + s_in = hovered_clip->timeline_in(); - if (clip->opening_transition->secondary_clip != nullptr) { - s.in -= clip->opening_transition->get_true_length(); + if (hovered_clip->opening_transition->secondary_clip != nullptr) { + s_in -= hovered_clip->opening_transition->get_true_length(); } - s.out = clip->timeline_in() + clip->opening_transition->get_true_length(); - } else if (panel_timeline->transition_select == kTransitionClosing && clip->closing_transition != nullptr) { - s.in = clip->timeline_out() - clip->closing_transition->get_true_length(); - s.out = clip->timeline_out(); + s_out = hovered_clip->timeline_in() + hovered_clip->opening_transition->get_true_length(); - if (clip->closing_transition->secondary_clip != nullptr) { - s.out += clip->closing_transition->get_true_length(); + } else if (ParentTimeline()->transition_select == kTransitionClosing + && hovered_clip->closing_transition != nullptr) { + + s_in = hovered_clip->timeline_out() - hovered_clip->closing_transition->get_true_length(); + s_out = hovered_clip->timeline_out(); + + if (hovered_clip->closing_transition->secondary_clip != nullptr) { + s_out += hovered_clip->closing_transition->get_true_length(); } } - olive::ActiveSequence->selections.append(s); + hovered_clip->track()->SelectArea(s_in, s_out); } } else { @@ -714,59 +732,52 @@ void TimelineView::mousePressEvent(QMouseEvent *event) { // if shift is NOT down, we change clear all current selections if (!shift) { - olive::ActiveSequence->selections.clear(); + sequence()->ClearSelections(); } - Selection s; - - s.in = clip->timeline_in(); - s.out = clip->timeline_out(); - s.track = clip->track(); + long s_in = hovered_clip->timeline_in(); + long s_out = hovered_clip->timeline_out(); // if user is using the pointer tool, they may be trying to select a transition // check if the use is hovering over a transition - if (panel_timeline->tool == TIMELINE_TOOL_POINTER) { - if (panel_timeline->transition_select == kTransitionOpening) { + if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_POINTER) { + if (ParentTimeline()->transition_select == kTransitionOpening) { // move the selection to only select the transitoin - s.out = clip->timeline_in() + clip->opening_transition->get_true_length(); + s_out = hovered_clip->timeline_in() + hovered_clip->opening_transition->get_true_length(); // if the transition is a "shared" transition, adjust the selection to select both sides - if (clip->opening_transition->secondary_clip != nullptr) { - s.in -= clip->opening_transition->get_true_length(); + if (hovered_clip->opening_transition->secondary_clip != nullptr) { + s_in -= hovered_clip->opening_transition->get_true_length(); } - } else if (panel_timeline->transition_select == kTransitionClosing) { + } else if (ParentTimeline()->transition_select == kTransitionClosing) { // move the selection to only select the transitoin - s.in = clip->timeline_out() - clip->closing_transition->get_true_length(); + s_in = hovered_clip->timeline_out() - hovered_clip->closing_transition->get_true_length(); // if the transition is a "shared" transition, adjust the selection to select both sides - if (clip->closing_transition->secondary_clip != nullptr) { - s.out += clip->closing_transition->get_true_length(); + if (hovered_clip->closing_transition->secondary_clip != nullptr) { + s_out += hovered_clip->closing_transition->get_true_length(); } } } // add the selection to the array - olive::ActiveSequence->selections.append(s); + hovered_clip->track()->SelectArea(s_in, s_out); // if the config is set to also seek with selections, do so now - if (olive::CurrentConfig.select_also_seeks) { - panel_sequence_viewer->seek(clip->timeline_in()); + if (olive::config.select_also_seeks) { + panel_sequence_viewer->seek(hovered_clip->timeline_in()); } // if alt is not down, select links (provided we're not selecting transitions) - if (!alt && panel_timeline->transition_select == kTransitionNone) { + if (!alt && ParentTimeline()->transition_select == kTransitionNone) { - for (int i=0;ilinked.size();i++) { + for (int i=0;ilinked.size();i++) { - Clip* link = olive::ActiveSequence->clips.at(clip->linked.at(i)).get(); + Clip* link = hovered_clip->linked.at(i); // check if the clip is already selected if (!link->IsSelected()) { - Selection ss; - ss.in = link->timeline_in(); - ss.out = link->timeline_out(); - ss.track = link->track(); - olive::ActiveSequence->selections.append(ss); + link->track()->SelectClip(link); } } @@ -775,8 +786,8 @@ void TimelineView::mousePressEvent(QMouseEvent *event) { } // authorize the starting of a move action if the mouse moves after this - if (effective_tool != TIMELINE_TOOL_MENU) { - panel_timeline->moving_init = true; + if (effective_tool != olive::timeline::TIMELINE_TOOL_MENU) { + ParentTimeline()->moving_init = true; } } else { @@ -784,10 +795,10 @@ void TimelineView::mousePressEvent(QMouseEvent *event) { // if the user did not click a clip at all, we start a rectangle selection if (!shift) { - olive::ActiveSequence->selections.clear(); + sequence()->ClearSelections(); } - panel_timeline->rect_select_init = true; + ParentTimeline()->rect_select_init = true; } // update everything @@ -795,42 +806,42 @@ void TimelineView::mousePressEvent(QMouseEvent *event) { } } break; - case TIMELINE_TOOL_HAND: + case olive::timeline::TIMELINE_TOOL_HAND: // initiate moving with the hand tool - panel_timeline->hand_moving = true; + ParentTimeline()->hand_moving = true; break; - case TIMELINE_TOOL_EDIT: + case olive::timeline::TIMELINE_TOOL_EDIT: // if the config is set to seek with the edit tool, do so now - if (olive::CurrentConfig.edit_tool_also_seeks) { - panel_sequence_viewer->seek(panel_timeline->drag_frame_start); + if (olive::config.edit_tool_also_seeks) { + panel_sequence_viewer->seek(ParentTimeline()->drag_frame_start); } // initiate selecting - panel_timeline->selecting = true; + ParentTimeline()->selecting = true; break; - case TIMELINE_TOOL_RAZOR: + case olive::timeline::TIMELINE_TOOL_RAZOR: { // initiate razor tool - panel_timeline->splitting = true; + ParentTimeline()->splitting = true; // add this track as a track being split by the razor - panel_timeline->split_tracks.append(panel_timeline->drag_track_start); + ParentTimeline()->split_tracks.append(ParentTimeline()->drag_track_start); update_ui(false); } break; - case TIMELINE_TOOL_TRANSITION: + case olive::timeline::TIMELINE_TOOL_TRANSITION: { // if there is a clip to run the transition tool on, initiate the transition tool - if (panel_timeline->transition_tool_open_clip > -1 - || panel_timeline->transition_tool_close_clip > -1) { - panel_timeline->transition_tool_init = true; + if (ParentTimeline()->transition_tool_open_clip != nullptr + || ParentTimeline()->transition_tool_close_clip != nullptr) { + ParentTimeline()->transition_tool_init = true; } } @@ -882,7 +893,7 @@ void make_room_for_transition(ComboAction* ca, } } -void VerifyTransitionsAfterCreating(ComboAction* ca, Clip* open, Clip* close, long transition_start, long transition_end) { +void TimelineView::VerifyTransitionsAfterCreating(ComboAction* ca, Clip* open, Clip* close, long transition_start, long transition_end) { // in case the user made the transition larger than the clips, we're going to delete everything under // the transition ghost and extend the clips to the transition's coordinates as necessary @@ -894,7 +905,7 @@ void VerifyTransitionsAfterCreating(ComboAction* ca, Clip* open, Clip* close, lo // determine whether this is a "shared" transition between to clips or not bool shared_transition = (open != nullptr && close != nullptr); - int track = 0; + Track* track = nullptr; // first we set the clips to "undeletable" so they aren't affected by delete_areas_and_relink() if (open != nullptr) { @@ -908,12 +919,8 @@ void VerifyTransitionsAfterCreating(ComboAction* ca, Clip* open, Clip* close, lo // set the area to delete to the transition's coordinates and clear it QVector areas; - Selection s; - s.in = transition_start; - s.out = transition_end; - s.track = track; - areas.append(s); - panel_timeline->delete_areas_and_relink(ca, areas, false); + areas.append(Selection(transition_start, transition_end, track)); + sequence()->DeleteAreas(ca, areas, false); // set the clips back to undeletable now that we're done if (open != nullptr) { @@ -962,7 +969,7 @@ void VerifyTransitionsAfterCreating(ComboAction* ca, Clip* open, Clip* close, lo - clip_ref->move(ca, + clip_ref->Move(ca, new_in, new_out, clip_ref->clip_in() - (clip_ref->timeline_in() - new_in), @@ -974,7 +981,7 @@ void VerifyTransitionsAfterCreating(ComboAction* ca, Clip* open, Clip* close, lo void TimelineView::mouseReleaseEvent(QMouseEvent *event) { QToolTip::hideText(); - if (olive::ActiveSequence != nullptr) { + if (sequence() != nullptr) { bool alt = (event->modifiers() & Qt::AltModifier); bool shift = (event->modifiers() & Qt::ShiftModifier); bool ctrl = (event->modifiers() & Qt::ControlModifier); @@ -983,45 +990,38 @@ void TimelineView::mouseReleaseEvent(QMouseEvent *event) { ComboAction* ca = new ComboAction(); bool push_undo = false; - if (panel_timeline->creating) { - if (panel_timeline->ghosts.size() > 0) { - const Ghost& g = panel_timeline->ghosts.at(0); + if (ParentTimeline()->creating) { + if (ParentTimeline()->ghosts.size() > 0) { + const Ghost& g = ParentTimeline()->ghosts.at(0); - if (panel_timeline->creating_object == olive::timeline::ADD_OBJ_AUDIO) { + if (ParentTimeline()->creating_object == olive::timeline::ADD_OBJ_AUDIO) { olive::MainWindow->statusBar()->clearMessage(); panel_sequence_viewer->cue_recording(qMin(g.in, g.out), qMax(g.in, g.out), g.track); - panel_timeline->creating = false; + ParentTimeline()->creating = false; } else if (g.in != g.out) { - ClipPtr c = std::make_shared(olive::ActiveSequence.get()); + ClipPtr c = std::make_shared(g.track); c->set_media(nullptr, 0); c->set_timeline_in(qMin(g.in, g.out)); c->set_timeline_out(qMax(g.in, g.out)); c->set_clip_in(0); c->set_color(192, 192, 64); - c->set_track(g.track); if (ctrl) { - insert_clips(ca); + insert_clips(ca, sequence()); } else { - Selection s; - s.in = c->timeline_in(); - s.out = c->timeline_out(); - s.track = c->track(); - QVector areas; - areas.append(s); - panel_timeline->delete_areas_and_relink(ca, areas, false); + sequence()->DeleteAreas(ca, {c->ToSelection()}, false); } QVector add; add.append(c); - ca->append(new AddClipCommand(olive::ActiveSequence.get(), add)); + ca->append(new AddClipCommand(add)); - if (c->track() < 0 && olive::CurrentConfig.add_default_effects_to_clips) { + if (c->type() == Track::kTypeVideo && olive::config.add_default_effects_to_clips) { // default video effects (before custom effects) c->effects.append(Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_TRANSFORM, EFFECT_TYPE_EFFECT))); } - switch (panel_timeline->creating_object) { + switch (ParentTimeline()->creating_object) { case olive::timeline::ADD_OBJ_TITLE: c->set_name(tr("Title")); c->effects.append(Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_RICHTEXT, EFFECT_TYPE_EFFECT))); @@ -1052,7 +1052,7 @@ void TimelineView::mouseReleaseEvent(QMouseEvent *event) { break; } - if (c->track() >= 0 && olive::CurrentConfig.add_default_effects_to_clips) { + if (c->type() == Track::kTypeAudio && olive::config.add_default_effects_to_clips) { // default audio effects (after custom effects) c->effects.append(Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_VOLUME, EFFECT_TYPE_EFFECT))); c->effects.append(Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_PAN, EFFECT_TYPE_EFFECT))); @@ -1061,19 +1061,19 @@ void TimelineView::mouseReleaseEvent(QMouseEvent *event) { push_undo = true; if (!shift) { - panel_timeline->creating = false; + ParentTimeline()->creating = false; } } } - } else if (panel_timeline->moving_proc) { + } else if (ParentTimeline()->moving_proc) { // see if any clips actually moved, otherwise we don't need to do any processing // (perhaps this could be moved further up to cover more actions?) bool process_moving = false; - for (int i=0;ighosts.size();i++) { - const Ghost& g = panel_timeline->ghosts.at(i); + for (int i=0;ighosts.size();i++) { + const Ghost& g = ParentTimeline()->ghosts.at(i); if (g.in != g.old_in || g.out != g.old_out || g.clip_in != g.old_clip_in @@ -1084,17 +1084,17 @@ void TimelineView::mouseReleaseEvent(QMouseEvent *event) { } if (process_moving) { - const Ghost& first_ghost = panel_timeline->ghosts.at(0); + const Ghost& first_ghost = ParentTimeline()->ghosts.at(0); // start a ripple movement - if (panel_timeline->tool == TIMELINE_TOOL_RIPPLE) { + if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_RIPPLE) { // ripple_length becomes the length/number of frames we trimmed // ripple_point is the "axis" around which we move all the clips, any clips after it get moved long ripple_length; long ripple_point = LONG_MAX; - if (panel_timeline->trim_type == olive::timeline::TRIM_IN) { + if (ParentTimeline()->trim_type == olive::timeline::TRIM_IN) { // it's assumed that all the ghosts rippled by the same length, so we just take the difference of the // first ghost here @@ -1102,66 +1102,63 @@ void TimelineView::mouseReleaseEvent(QMouseEvent *event) { // for in trimming movements we also move the selections forward (unnecessary for out trimming since // the selected clips more or less stay in the same place) - for (int i=0;iselections.size();i++) { - olive::ActiveSequence->selections[i].in += ripple_length; - olive::ActiveSequence->selections[i].out += ripple_length; + /* + for (int i=0;iselections.size();i++) { + sequence()->selections[i].in += ripple_length; + sequence()->selections[i].out += ripple_length; } + */ } else { // use the out points for length if the user trimmed the out point - ripple_length = first_ghost.old_out - panel_timeline->ghosts.at(0).out; + ripple_length = first_ghost.old_out - ParentTimeline()->ghosts.at(0).out; } // build a list of "ignore clips" that won't get affected by ripple_clips() below - QVector ignore_clips; - for (int i=0;ighosts.size();i++) { - const Ghost& g = panel_timeline->ghosts.at(i); + QVector ignore_clips; + for (int i=0;ighosts.size();i++) { + const Ghost& g = ParentTimeline()->ghosts.at(i); // for the same reason that we pushed selections forward above, for in trimming, // we push the ghosts forward here - if (panel_timeline->trim_type == olive::timeline::TRIM_IN) { + if (ParentTimeline()->trim_type == olive::timeline::TRIM_IN) { ignore_clips.append(g.clip); - panel_timeline->ghosts[i].in += ripple_length; - panel_timeline->ghosts[i].out += ripple_length; + ParentTimeline()->ghosts[i].in += ripple_length; + ParentTimeline()->ghosts[i].out += ripple_length; } // find the earliest ripple point - long comp_point = (panel_timeline->trim_type == olive::timeline::TRIM_IN) ? g.old_in : g.old_out; + long comp_point = (ParentTimeline()->trim_type == olive::timeline::TRIM_IN) ? g.old_in : g.old_out; ripple_point = qMin(ripple_point, comp_point); } // if this was out trimming, flip the direction of the ripple - if (panel_timeline->trim_type == olive::timeline::TRIM_OUT) ripple_length = -ripple_length; + if (ParentTimeline()->trim_type == olive::timeline::TRIM_OUT) ripple_length = -ripple_length; // finally, ripple everything - ripple_clips(ca, olive::ActiveSequence.get(), ripple_point, ripple_length, ignore_clips); + sequence()->Ripple(ca, ripple_point, ripple_length, ignore_clips); } - if (panel_timeline->tool == TIMELINE_TOOL_POINTER + if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_POINTER && (event->modifiers() & Qt::AltModifier) - && panel_timeline->trim_target == -1) { + && ParentTimeline()->trim_target == nullptr) { // if the user was holding alt (and not trimming), we duplicate clips rather than move them - QVector old_clips; + QVector old_clips; QVector new_clips; QVector delete_areas; - for (int i=0;ighosts.size();i++) { - const Ghost& g = panel_timeline->ghosts.at(i); + for (int i=0;ighosts.size();i++) { + const Ghost& g = ParentTimeline()->ghosts.at(i); if (g.old_in != g.in || g.old_out != g.out || g.track != g.old_track || g.clip_in != g.old_clip_in) { // create copy of clip - ClipPtr c = olive::ActiveSequence->clips.at(g.clip)->copy(olive::ActiveSequence.get()); + ClipPtr c = g.clip->copy(g.track); c->set_timeline_in(g.in); c->set_timeline_out(g.out); - c->set_track(g.track); - Selection s; - s.in = g.in; - s.out = g.out; - s.track = g.track; - delete_areas.append(s); + delete_areas.append(g.ToSelection()); old_clips.append(g.clip); new_clips.append(c); @@ -1172,13 +1169,13 @@ void TimelineView::mouseReleaseEvent(QMouseEvent *event) { if (new_clips.size() > 0) { // delete anything under the new clips - panel_timeline->delete_areas_and_relink(ca, delete_areas, false); + sequence()->DeleteAreas(ca, delete_areas, false); // relink duplicated clips - panel_timeline->relink_clips_using_ids(old_clips, new_clips); + olive::timeline::RelinkClips(old_clips, new_clips); // add them - ca->append(new AddClipCommand(olive::ActiveSequence.get(), new_clips)); + ca->append(new AddClipCommand(new_clips)); } @@ -1187,22 +1184,22 @@ void TimelineView::mouseReleaseEvent(QMouseEvent *event) { // if we're not holding alt, this will just be a move // if the user is holding ctrl, perform an insert rather than an overwrite - if (panel_timeline->tool == TIMELINE_TOOL_POINTER && ctrl) { + if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_POINTER && ctrl) { - insert_clips(ca); + insert_clips(ca, sequence()); - } else if (panel_timeline->tool == TIMELINE_TOOL_POINTER || panel_timeline->tool == TIMELINE_TOOL_SLIDE) { + } else if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_POINTER || olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_SLIDE) { // if the user is not holding ctrl, we start standard clip movement // delete everything under the new clips QVector delete_areas; - for (int i=0;ighosts.size();i++) { + for (int i=0;ighosts.size();i++) { // step 1 - set clips that are moving to "undeletable" (to avoid step 2 deleting any part of them) - const Ghost& g = panel_timeline->ghosts.at(i); + const Ghost& g = ParentTimeline()->ghosts.at(i); // set clip to undeletable so it's unaffected by delete_areas_and_relink() below - olive::ActiveSequence->clips.at(g.clip)->undeletable = true; + g.clip->undeletable = true; // if the user was moving a transition make sure they're undeletable too if (g.transition != nullptr) { @@ -1213,19 +1210,15 @@ void TimelineView::mouseReleaseEvent(QMouseEvent *event) { } // set area to delete - Selection s; - s.in = g.in; - s.out = g.out; - s.track = g.track; - delete_areas.append(s); + delete_areas.append(g.ToSelection()); } - panel_timeline->delete_areas_and_relink(ca, delete_areas, false); + sequence()->DeleteAreas(ca, delete_areas, false); // clean up, i.e. make everything not undeletable again - for (int i=0;ighosts.size();i++) { - const Ghost& g = panel_timeline->ghosts.at(i); - olive::ActiveSequence->clips.at(g.clip)->undeletable = false; + for (int i=0;ighosts.size();i++) { + const Ghost& g = ParentTimeline()->ghosts.at(i); + g.clip->undeletable = false; if (g.transition != nullptr) { g.transition->parent_clip->undeletable = false; @@ -1237,16 +1230,22 @@ void TimelineView::mouseReleaseEvent(QMouseEvent *event) { } // finally, perform actual movement of clips - for (int i=0;ighosts.size();i++) { - Ghost& g = panel_timeline->ghosts[i]; + for (int i=0;ighosts.size();i++) { + Ghost& g = ParentTimeline()->ghosts[i]; - Clip* c = olive::ActiveSequence->clips.at(g.clip).get(); + Clip* c = g.clip; if (g.transition == nullptr) { // if this was a clip rather than a transition - c->move(ca, (g.in - g.old_in), (g.out - g.old_out), (g.clip_in - g.old_clip_in), (g.track - g.old_track), false, true); + c->Move(ca, + (g.in - g.old_in), + (g.out - g.old_out), + (g.clip_in - g.old_clip_in), + g.track, + false, + true); } else { @@ -1257,7 +1256,7 @@ void TimelineView::mouseReleaseEvent(QMouseEvent *event) { if (g.transition->secondary_clip != nullptr) new_transition_length >>= 1; ca->append( new ModifyTransitionCommand(is_opening_transition ? c->opening_transition : c->closing_transition, - new_transition_length) + new_transition_length) ); long clip_length = c->length(); @@ -1280,8 +1279,8 @@ void TimelineView::mouseReleaseEvent(QMouseEvent *event) { timeline_in_movement = g.in - g.transition->secondary_clip->timeline_in(); } - g.transition->parent_clip->move(ca, movement, timeline_out_movement, movement, 0, false, true); - g.transition->secondary_clip->move(ca, timeline_in_movement, movement, timeline_in_movement, 0, false, true); + g.transition->parent_clip->Move(ca, movement, timeline_out_movement, movement, g.transition->parent_clip->track(), false, true); + g.transition->secondary_clip->Move(ca, timeline_in_movement, movement, timeline_in_movement, g.transition->secondary_clip->track(), false, true); make_room_for_transition(ca, g.transition->parent_clip, kTransitionOpening, g.in, g.out, false); make_room_for_transition(ca, g.transition->secondary_clip, kTransitionClosing, g.in, g.out, false); @@ -1299,7 +1298,7 @@ void TimelineView::mouseReleaseEvent(QMouseEvent *event) { timeline_out_movement = g.out - g.transition->parent_clip->timeline_out(); } - c->move(ca, (g.in - g.old_in), timeline_out_movement, (g.clip_in - g.old_clip_in), 0, false, true); + c->Move(ca, (g.in - g.old_in), timeline_out_movement, (g.clip_in - g.old_clip_in), 0, false, true); clip_length -= (g.in - g.old_in); } @@ -1316,7 +1315,7 @@ void TimelineView::mouseReleaseEvent(QMouseEvent *event) { } // if transition is going to make the clip bigger, make the clip bigger - c->move(ca, timeline_in_movement, (g.out - g.old_out), timeline_in_movement, 0, false, true); + c->Move(ca, timeline_in_movement, (g.out - g.old_out), timeline_in_movement, 0, false, true); clip_length += (g.out - g.old_out); } @@ -1327,12 +1326,12 @@ void TimelineView::mouseReleaseEvent(QMouseEvent *event) { } // time to verify the transitions of moved clips - for (int i=0;ighosts.size();i++) { - const Ghost& g = panel_timeline->ghosts.at(i); + for (int i=0;ighosts.size();i++) { + const Ghost& g = ParentTimeline()->ghosts.at(i); // only applies to moving clips, transitions are verified above instead if (g.transition == nullptr) { - ClipPtr c = olive::ActiveSequence->clips.at(g.clip); + Clip* c = g.clip; long new_clip_length = g.out - g.in; @@ -1369,12 +1368,12 @@ void TimelineView::mouseReleaseEvent(QMouseEvent *event) { // for a shared transition, the secondary_clip will always be the closing transition side and // the parent_clip will always be the opening transition side Clip* search_clip = (t == kTransitionOpening) - ? transition->secondary_clip : transition->parent_clip; + ? transition->secondary_clip : transition->parent_clip; - for (int j=0;jghosts.size();j++) { - const Ghost& other_clip_ghost = panel_timeline->ghosts.at(j); + for (int j=0;jghosts.size();j++) { + const Ghost& other_clip_ghost = ParentTimeline()->ghosts.at(j); - if (olive::ActiveSequence->clips.at(other_clip_ghost.clip).get() == search_clip) { + if (other_clip_ghost.clip == search_clip) { // we found the other clip in the current ghosts/selections @@ -1442,9 +1441,9 @@ void TimelineView::mouseReleaseEvent(QMouseEvent *event) { } push_undo = true; } - } else if (panel_timeline->selecting || panel_timeline->rect_select_proc) { - } else if (panel_timeline->transition_tool_proc) { - const Ghost& g = panel_timeline->ghosts.at(0); + } else if (ParentTimeline()->selecting || ParentTimeline()->rect_select_proc) { + } else if (ParentTimeline()->transition_tool_proc) { + const Ghost& g = ParentTimeline()->ghosts.at(0); // if the transition is greater than 0 length (if it is 0, we make nothing) if (g.in != g.out) { @@ -1454,13 +1453,9 @@ void TimelineView::mouseReleaseEvent(QMouseEvent *event) { long transition_end = qMax(g.in, g.out); // get clip references from tool's cached data - Clip* open = (panel_timeline->transition_tool_open_clip > -1) - ? olive::ActiveSequence->clips.at(panel_timeline->transition_tool_open_clip).get() - : nullptr; + Clip* open = ParentTimeline()->transition_tool_open_clip; - Clip* close = (panel_timeline->transition_tool_close_clip > -1) - ? olive::ActiveSequence->clips.at(panel_timeline->transition_tool_close_clip).get() - : nullptr; + Clip* close = ParentTimeline()->transition_tool_close_clip; @@ -1476,16 +1471,17 @@ void TimelineView::mouseReleaseEvent(QMouseEvent *event) { ca->append(new AddTransitionCommand(open, close, nullptr, - panel_timeline->transition_tool_meta, + ParentTimeline()->transition_tool_meta, transition_length)); push_undo = true; } - } else if (panel_timeline->splitting) { + } else if (ParentTimeline()->splitting) { bool split = false; - for (int i=0;isplit_tracks.size();i++) { - int split_index = getClipIndexFromCoords(panel_timeline->drag_frame_start, panel_timeline->split_tracks.at(i)); - if (split_index > -1 && panel_timeline->split_clip_and_relink(ca, split_index, panel_timeline->drag_frame_start, !alt)) { + for (int i=0;isplit_tracks.size();i++) { + Clip* split_index = ParentTimeline()->split_tracks.at(i)->GetClipFromPoint(ParentTimeline()->drag_frame_start); + if (split_index != nullptr + && sequence()->SplitClipAtPositions(ca, split_index, {ParentTimeline()->drag_frame_start}, !alt)) { split = true; } } @@ -1495,54 +1491,56 @@ void TimelineView::mouseReleaseEvent(QMouseEvent *event) { } // remove duplicate selections - panel_timeline->clean_up_selections(olive::ActiveSequence->selections); + sequence()->TidySelections(); + /* if (selection_command != nullptr) { - selection_command->new_data = olive::ActiveSequence->selections; + selection_command->new_data = sequence()->selections; ca->append(selection_command); selection_command = nullptr; push_undo = true; } + */ if (push_undo) { - olive::UndoStack.push(ca); + olive::undo_stack.push(ca); } else { delete ca; } // destroy all ghosts - panel_timeline->ghosts.clear(); + ParentTimeline()->ghosts.clear(); // clear split tracks - panel_timeline->split_tracks.clear(); + ParentTimeline()->split_tracks.clear(); - panel_timeline->selecting = false; - panel_timeline->moving_proc = false; - panel_timeline->moving_init = false; - panel_timeline->splitting = false; - panel_timeline->snapped = false; - panel_timeline->rect_select_init = false; - panel_timeline->rect_select_proc = false; - panel_timeline->transition_tool_init = false; - panel_timeline->transition_tool_proc = false; + ParentTimeline()->selecting = false; + ParentTimeline()->moving_proc = false; + ParentTimeline()->moving_init = false; + ParentTimeline()->splitting = false; + olive::timeline::snapped = false; + ParentTimeline()->rect_select_init = false; + ParentTimeline()->rect_select_proc = false; + ParentTimeline()->transition_tool_init = false; + ParentTimeline()->transition_tool_proc = false; pre_clips.clear(); post_clips.clear(); update_ui(true); } - panel_timeline->hand_moving = false; + ParentTimeline()->hand_moving = false; } } void TimelineView::init_ghosts() { - for (int i=0;ighosts.size();i++) { - Ghost& g = panel_timeline->ghosts[i]; - ClipPtr c = olive::ActiveSequence->clips.at(g.clip); + for (int i=0;ighosts.size();i++) { + Ghost& g = ParentTimeline()->ghosts[i]; + Clip* c = g.clip; g.track = g.old_track = c->track(); g.clip_in = g.old_clip_in = c->clip_in(); - if (panel_timeline->tool == TIMELINE_TOOL_SLIP) { + if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_SLIP) { g.clip_in = g.old_clip_in = c->clip_in(true); g.in = g.old_in = c->timeline_in(true); g.out = g.old_out = c->timeline_out(true); @@ -1566,12 +1564,14 @@ void TimelineView::init_ghosts() { // used for trim ops g.media_length = c->media_length(); } - for (int i=0;iselections.size();i++) { - Selection& s = olive::ActiveSequence->selections[i]; + /* + for (int i=0;iselections.size();i++) { + Selection& s = sequence()->selections[i]; s.old_in = s.in; s.old_out = s.out; s.old_track = s.track; } + */ } void validate_transitions(Clip* c, int transition_type, long& frame_diff) { @@ -1605,52 +1605,54 @@ void validate_transitions(Clip* c, int transition_type, long& frame_diff) { } void TimelineView::update_ghosts(const QPoint& mouse_pos, bool lock_frame) { - int effective_tool = panel_timeline->tool; - if (panel_timeline->importing || panel_timeline->creating) effective_tool = TIMELINE_TOOL_POINTER; + int effective_tool = olive::timeline::current_tool; + if (ParentTimeline()->importing || ParentTimeline()->creating) effective_tool = olive::timeline::TIMELINE_TOOL_POINTER; - int mouse_track = getTrackFromScreenPoint(mouse_pos.y()); - long frame_diff = (lock_frame) ? 0 : panel_timeline->getTimelineFrameFromScreenPoint(mouse_pos.x()) - panel_timeline->drag_frame_start; - int track_diff = ((effective_tool == TIMELINE_TOOL_SLIDE || panel_timeline->transition_select != kTransitionNone) && !panel_timeline->importing) ? 0 : mouse_track - panel_timeline->drag_track_start; + Track* mouse_track = getTrackFromScreenPoint(mouse_pos.y()); + long frame_diff = (lock_frame) ? 0 : ParentTimeline()->getTimelineFrameFromScreenPoint(mouse_pos.x()) - ParentTimeline()->drag_frame_start; + int track_diff = ((effective_tool == olive::timeline::TIMELINE_TOOL_SLIDE || ParentTimeline()->transition_select != kTransitionNone) && !ParentTimeline()->importing) ? 0 : mouse_track - ParentTimeline()->drag_track_start; long validator; long earliest_in_point = LONG_MAX; // first try to snap long fm; - if (effective_tool != TIMELINE_TOOL_SLIP) { + if (effective_tool != olive::timeline::TIMELINE_TOOL_SLIP) { // slipping doesn't move the clips so we don't bother snapping for it - for (int i=0;ighosts.size();i++) { - const Ghost& g = panel_timeline->ghosts.at(i); + for (int i=0;ighosts.size();i++) { + const Ghost& g = ParentTimeline()->ghosts.at(i); // snap ghost's in point - if ((panel_timeline->tool != TIMELINE_TOOL_TRANSITION && panel_timeline->trim_target == -1) + if ((olive::timeline::current_tool != olive::timeline::TIMELINE_TOOL_TRANSITION && ParentTimeline()->trim_target == nullptr) || g.trim_type == olive::timeline::TRIM_IN - || panel_timeline->transition_tool_open_clip > -1) { + || ParentTimeline()->transition_tool_open_clip != nullptr) { fm = g.old_in + frame_diff; - if (panel_timeline->snap_to_timeline(&fm, true, true, true)) { + if (sequence()->SnapPoint(&fm, ParentTimeline()->zoom, true, true, true)) { frame_diff = fm - g.old_in; break; } } // snap ghost's out point - if ((panel_timeline->tool != TIMELINE_TOOL_TRANSITION && panel_timeline->trim_target == -1) + if ((olive::timeline::current_tool != olive::timeline::TIMELINE_TOOL_TRANSITION && ParentTimeline()->trim_target == nullptr) || g.trim_type == olive::timeline::TRIM_OUT - || panel_timeline->transition_tool_close_clip > -1) { + || ParentTimeline()->transition_tool_close_clip != nullptr) { fm = g.old_out + frame_diff; - if (panel_timeline->snap_to_timeline(&fm, true, true, true)) { + if (sequence()->SnapPoint(&fm, ParentTimeline()->zoom, true, true, true)) { frame_diff = fm - g.old_out; break; } } // if the ghost is attached to a clip, snap its markers too - if (panel_timeline->trim_target == -1 && g.clip >= 0 && panel_timeline->tool != TIMELINE_TOOL_TRANSITION) { - ClipPtr c = olive::ActiveSequence->clips.at(g.clip); + if (ParentTimeline()->trim_target == nullptr + && g.clip != nullptr + && olive::timeline::current_tool != olive::timeline::TIMELINE_TOOL_TRANSITION) { + Clip* c = g.clip; for (int j=0;jget_markers().size();j++) { long marker_real_time = c->get_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)) { + if (sequence()->SnapPoint(&fm, ParentTimeline()->zoom, true, true, true)) { frame_diff = fm - marker_real_time; break; } @@ -1659,26 +1661,26 @@ void TimelineView::update_ghosts(const QPoint& mouse_pos, bool lock_frame) { } } - bool clips_are_movable = (effective_tool == TIMELINE_TOOL_POINTER || effective_tool == TIMELINE_TOOL_SLIDE); + bool clips_are_movable = (effective_tool == olive::timeline::TIMELINE_TOOL_POINTER || effective_tool == olive::timeline::TIMELINE_TOOL_SLIDE); // validate ghosts long temp_frame_diff = frame_diff; // cache to see if we change it (thus cancelling any snap) - for (int i=0;ighosts.size();i++) { - const Ghost& g = panel_timeline->ghosts.at(i); + for (int i=0;ighosts.size();i++) { + const Ghost& g = ParentTimeline()->ghosts.at(i); Clip* c = nullptr; - if (g.clip != -1) { - c = olive::ActiveSequence->clips.at(g.clip).get(); + if (g.clip != nullptr) { + c = g.clip; } const FootageStream* ms = nullptr; - if (g.clip != -1 && c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) { + if (g.clip != nullptr && c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) { ms = c->media_stream(); } // validate ghosts for trimming - if (panel_timeline->creating) { + if (ParentTimeline()->creating) { // i feel like we might need something here but we haven't so far? - } else if (effective_tool == TIMELINE_TOOL_SLIP) { + } else if (effective_tool == olive::timeline::TIMELINE_TOOL_SLIP) { if ((c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_SEQUENCE) || (ms != nullptr && !ms->infinite_length)) { // prevent slip moving a clip below 0 clip_in @@ -1696,7 +1698,7 @@ void TimelineView::update_ghosts(const QPoint& mouse_pos, bool lock_frame) { if (validator < 1) frame_diff -= (1 - validator); // prevent timeline in from going below 0 - if (effective_tool != TIMELINE_TOOL_RIPPLE) { + if (effective_tool != olive::timeline::TIMELINE_TOOL_RIPPLE) { validator = g.old_in + frame_diff; if (validator < 0) frame_diff -= validator; } @@ -1747,21 +1749,21 @@ void TimelineView::update_ghosts(const QPoint& mouse_pos, bool lock_frame) { } // ripple ops - if (effective_tool == TIMELINE_TOOL_RIPPLE) { + if (effective_tool == olive::timeline::TIMELINE_TOOL_RIPPLE) { for (int j=0;jtrim_type == olive::timeline::TRIM_IN) { + if (ParentTimeline()->trim_type == olive::timeline::TRIM_IN) { validator = post->timeline_in() - frame_diff; if (validator < 0) frame_diff += validator; } // prevent any post-clips colliding with pre-clips for (int k=0;ktrack() == post->track()) { - if (panel_timeline->trim_type == olive::timeline::TRIM_IN) { + if (ParentTimeline()->trim_type == olive::timeline::TRIM_IN) { validator = post->timeline_in() - frame_diff - pre->timeline_out(); if (validator < 0) frame_diff += validator; } else { @@ -1810,7 +1812,8 @@ void TimelineView::update_ghosts(const QPoint& mouse_pos, bool lock_frame) { } // prevent clips from crossing tracks - if (same_sign(g.old_track, panel_timeline->drag_track_start)) { + /* + if (same_sign(g.old_track, ParentTimeline()->drag_track_start)) { while (!same_sign(g.old_track, g.old_track + track_diff)) { if (g.old_track < 0) { track_diff--; @@ -1819,16 +1822,17 @@ void TimelineView::update_ghosts(const QPoint& mouse_pos, bool lock_frame) { } } } - } else if (effective_tool == TIMELINE_TOOL_TRANSITION) { - if (panel_timeline->transition_tool_open_clip == -1 - || panel_timeline->transition_tool_close_clip == -1) { + */ + } else if (effective_tool == olive::timeline::TIMELINE_TOOL_TRANSITION) { + if (ParentTimeline()->transition_tool_open_clip == nullptr + || ParentTimeline()->transition_tool_close_clip == nullptr) { validate_transitions(c, g.media_stream, frame_diff); } else { // open transition clip - Clip* otc = olive::ActiveSequence->clips.at(panel_timeline->transition_tool_open_clip).get(); + Clip* otc = ParentTimeline()->transition_tool_open_clip; // close transition clip - Clip* ctc = olive::ActiveSequence->clips.at(panel_timeline->transition_tool_close_clip).get(); + Clip* ctc = ParentTimeline()->transition_tool_close_clip; if (g.media_stream == kTransitionClosing) { // swap @@ -1852,21 +1856,21 @@ void TimelineView::update_ghosts(const QPoint& mouse_pos, bool lock_frame) { // if the above validation changed the frame movement, it's unlikely we're still snapped if (temp_frame_diff != frame_diff) { - panel_timeline->snapped = false; + olive::timeline::snapped = false; } // apply changes to ghosts - for (int i=0;ighosts.size();i++) { - Ghost& g = panel_timeline->ghosts[i]; + for (int i=0;ighosts.size();i++) { + Ghost& g = ParentTimeline()->ghosts[i]; - if (effective_tool == TIMELINE_TOOL_SLIP) { + if (effective_tool == olive::timeline::TIMELINE_TOOL_SLIP) { g.clip_in = g.old_clip_in - frame_diff; } else if (g.trim_type != olive::timeline::TRIM_NONE) { long ghost_diff = frame_diff; // prevent trimming clips from overlapping each other - for (int j=0;jghosts.size();j++) { - const Ghost& comp = panel_timeline->ghosts.at(j); + for (int j=0;jghosts.size();j++) { + const Ghost& comp = ParentTimeline()->ghosts.at(j); if (i != j && g.track == comp.track) { long validator; if (g.trim_type == olive::timeline::TRIM_IN && comp.out < g.out) { @@ -1896,13 +1900,14 @@ void TimelineView::update_ghosts(const QPoint& mouse_pos, bool lock_frame) { g.out = g.old_out + frame_diff; if (g.transition != nullptr - && g.transition == olive::ActiveSequence->clips.at(g.clip)->opening_transition) { + && g.transition == g.clip->opening_transition) { g.clip_in = g.old_clip_in + frame_diff; } - if (panel_timeline->importing) { - if ((panel_timeline->video_ghosts && mouse_track < 0) - || (panel_timeline->audio_ghosts && mouse_track >= 0)) { + if (ParentTimeline()->importing) { + /* + if ((ParentTimeline()->video_ghosts && mouse_track->type() == Track::kTypeVideo) + || (ParentTimeline()->audio_ghosts && mouse_track->type() == Track::kTypeAudio)) { int abs_track_diff = abs(track_diff); if (g.old_track < 0) { // clip is video g.track -= abs_track_diff; @@ -1910,15 +1915,17 @@ void TimelineView::update_ghosts(const QPoint& mouse_pos, bool lock_frame) { g.track += abs_track_diff; } } - } else if (same_sign(g.old_track, panel_timeline->drag_track_start)) { + */ + g.track = track_list_->First(); + } else if (g.old_track->type() == ParentTimeline()->drag_track_start->type()) { g.track += track_diff; } - } else if (effective_tool == TIMELINE_TOOL_TRANSITION) { - if (panel_timeline->transition_tool_open_clip > -1 - && panel_timeline->transition_tool_close_clip > -1) { + } else if (effective_tool == olive::timeline::TIMELINE_TOOL_TRANSITION) { + if (ParentTimeline()->transition_tool_open_clip != nullptr + && ParentTimeline()->transition_tool_close_clip != nullptr) { g.in = g.old_in - frame_diff; g.out = g.old_out + frame_diff; - } else if (panel_timeline->transition_tool_open_clip == g.clip) { + } else if (ParentTimeline()->transition_tool_open_clip == g.clip) { g.out = g.old_out + frame_diff; } else { g.in = g.old_in + frame_diff; @@ -1929,23 +1936,24 @@ void TimelineView::update_ghosts(const QPoint& mouse_pos, bool lock_frame) { } // apply changes to selections - if (effective_tool != TIMELINE_TOOL_SLIP && !panel_timeline->importing && !panel_timeline->creating) { - for (int i=0;iselections.size();i++) { - Selection& s = olive::ActiveSequence->selections[i]; - if (panel_timeline->trim_target > -1) { - if (panel_timeline->trim_type == olive::timeline::TRIM_IN) { + /* + if (effective_tool != olive::timeline::TIMELINE_TOOL_SLIP && !ParentTimeline()->importing && !ParentTimeline()->creating) { + for (int i=0;iselections.size();i++) { + Selection& s = sequence()->selections[i]; + if (ParentTimeline()->trim_target > -1) { + if (ParentTimeline()->trim_type == olive::timeline::TRIM_IN) { s.in = s.old_in + frame_diff; } else { s.out = s.old_out + frame_diff; } } else if (clips_are_movable) { - for (int i=0;iselections.size();i++) { - Selection& s = olive::ActiveSequence->selections[i]; + for (int i=0;iselections.size();i++) { + Selection& s = sequence()->selections[i]; s.in = s.old_in + frame_diff; s.out = s.old_out + frame_diff; s.track = s.old_track; - if (panel_timeline->importing) { + if (ParentTimeline()->importing) { int abs_track_diff = abs(track_diff); if (s.old_track < 0) { s.track -= abs_track_diff; @@ -1953,23 +1961,25 @@ void TimelineView::update_ghosts(const QPoint& mouse_pos, bool lock_frame) { s.track += abs_track_diff; } } else { - if (same_sign(s.track, panel_timeline->drag_track_start)) s.track += track_diff; + if (same_sign(s.track, ParentTimeline()->drag_track_start)) s.track += track_diff; } } } } } + */ - if (panel_timeline->importing) { - QToolTip::showText(mapToGlobal(mouse_pos), frame_to_timecode(earliest_in_point, olive::CurrentConfig.timecode_view, olive::ActiveSequence->frame_rate)); + if (ParentTimeline()->importing) { + QToolTip::showText(mapToGlobal(mouse_pos), frame_to_timecode(earliest_in_point, olive::config.timecode_view, sequence()->frame_rate)); } else { - QString tip = ((frame_diff < 0) ? "-" : "+") + frame_to_timecode(qAbs(frame_diff), olive::CurrentConfig.timecode_view, olive::ActiveSequence->frame_rate); - if (panel_timeline->trim_target > -1) { + QString tip = ((frame_diff < 0) ? "-" : "+") + frame_to_timecode(qAbs(frame_diff), olive::config.timecode_view, sequence()->frame_rate); + + if (ParentTimeline()->trim_target != nullptr) { // find which clip is being moved const Ghost* g = nullptr; - for (int i=0;ighosts.size();i++) { - if (panel_timeline->ghosts.at(i).clip == panel_timeline->trim_target) { - g = &panel_timeline->ghosts.at(i); + for (int i=0;ighosts.size();i++) { + if (ParentTimeline()->ghosts.at(i).clip == ParentTimeline()->trim_target) { + g = &ParentTimeline()->ghosts.at(i); break; } } @@ -1977,14 +1987,15 @@ void TimelineView::update_ghosts(const QPoint& mouse_pos, bool lock_frame) { if (g != nullptr) { tip += " " + tr("Duration:") + " "; long len = (g->old_out-g->old_in); - if (panel_timeline->trim_type == olive::timeline::TRIM_IN) { + if (ParentTimeline()->trim_type == olive::timeline::TRIM_IN) { len -= frame_diff; } else { len += frame_diff; } - tip += frame_to_timecode(len, olive::CurrentConfig.timecode_view, olive::ActiveSequence->frame_rate); + tip += frame_to_timecode(len, olive::config.timecode_view, sequence()->frame_rate); } } + QToolTip::showText(mapToGlobal(mouse_pos), tip); } } @@ -1993,85 +2004,87 @@ void TimelineView::mouseMoveEvent(QMouseEvent *event) { // interrupt any potential tooltip about to show tooltip_timer.stop(); - if (olive::ActiveSequence != nullptr) { + if (sequence() != nullptr) { bool alt = (event->modifiers() & Qt::AltModifier); // store current frame/track corresponding to the cursor - panel_timeline->cursor_frame = panel_timeline->getTimelineFrameFromScreenPoint(event->pos().x()); - panel_timeline->cursor_track = getTrackFromScreenPoint(event->pos().y()); + ParentTimeline()->cursor_frame = ParentTimeline()->getTimelineFrameFromScreenPoint(event->pos().x()); + ParentTimeline()->cursor_track = getTrackFromScreenPoint(event->pos().y()); // if holding the mouse button down, let's scroll to that location - if (event->buttons() != 0 && panel_timeline->tool != TIMELINE_TOOL_HAND) { - panel_timeline->scroll_to_frame(panel_timeline->cursor_frame); + if (event->buttons() != 0 && olive::timeline::current_tool != olive::timeline::TIMELINE_TOOL_HAND) { + ParentTimeline()->scroll_to_frame(ParentTimeline()->cursor_frame); } // determine if the action should be "inserting" rather than "overwriting" // Default behavior is to replace/overwrite clips under any clips we're dropping over them. Inserting will // split and move existing clips at the drop point to make space for the drop - panel_timeline->move_insert = ((event->modifiers() & Qt::ControlModifier) - && (panel_timeline->tool == TIMELINE_TOOL_POINTER - || panel_timeline->importing - || panel_timeline->creating)); + ParentTimeline()->move_insert = ((event->modifiers() & Qt::ControlModifier) + && (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_POINTER + || ParentTimeline()->importing + || ParentTimeline()->creating)); // if we're not currently resizing already, default track resizing to false (we'll set it to true later if // the user is still hovering over a track line) - if (!panel_timeline->moving_init) { + if (!ParentTimeline()->moving_init) { track_resizing = false; } // if the current tool uses an on-screen visible cursor, we snap the cursor to the timeline if (current_tool_shows_cursor()) { - panel_timeline->snap_to_timeline(&panel_timeline->cursor_frame, + sequence()->SnapPoint(&ParentTimeline()->cursor_frame, + ParentTimeline()->zoom, - // only snap to the playhead if the edit tool doesn't force the playhead to - // follow it (or if we're not selecting since that means the playhead is - // static at the moment) - !olive::CurrentConfig.edit_tool_also_seeks || !panel_timeline->selecting, + // only snap to the playhead if the edit tool doesn't force the playhead to + // follow it (or if we're not selecting since that means the playhead is + // static at the moment) + !olive::config.edit_tool_also_seeks || !ParentTimeline()->selecting, - true, - true); + true, + true); } - if (panel_timeline->selecting) { + if (ParentTimeline()->selecting) { + /* // get number of selections based on tracks in selection area - int selection_tool_count = 1 + qMax(panel_timeline->cursor_track, panel_timeline->drag_track_start) - qMin(panel_timeline->cursor_track, panel_timeline->drag_track_start); + int selection_tool_count = 1 + qMax(ParentTimeline()->cursor_track, ParentTimeline()->drag_track_start) - qMin(ParentTimeline()->cursor_track, ParentTimeline()->drag_track_start); // add count to selection offset for the total number of selection objects // (offset is usually 0, unless the user is holding shift in which case we add to existing selections) - int selection_count = selection_tool_count + panel_timeline->selection_offset; + int selection_count = selection_tool_count + ParentTimeline()->selection_offset; // resize selection object array to new count - if (olive::ActiveSequence->selections.size() != selection_count) { - olive::ActiveSequence->selections.resize(selection_count); + if (sequence()->selections.size() != selection_count) { + sequence()->selections.resize(selection_count); } // loop through tracks in selection area and adjust them accordingly - int minimum_selection_track = qMin(panel_timeline->cursor_track, panel_timeline->drag_track_start); - int maximum_selection_track = qMax(panel_timeline->cursor_track, panel_timeline->drag_track_start); - long selection_in = qMin(panel_timeline->drag_frame_start, panel_timeline->cursor_frame); - long selection_out = qMax(panel_timeline->drag_frame_start, panel_timeline->cursor_frame); - for (int i=panel_timeline->selection_offset;iselections[i]; - s.track = minimum_selection_track + i - panel_timeline->selection_offset; + int minimum_selection_track = qMin(ParentTimeline()->cursor_track, ParentTimeline()->drag_track_start); + int maximum_selection_track = qMax(ParentTimeline()->cursor_track, ParentTimeline()->drag_track_start); + long selection_in = qMin(ParentTimeline()->drag_frame_start, ParentTimeline()->cursor_frame); + long selection_out = qMax(ParentTimeline()->drag_frame_start, ParentTimeline()->cursor_frame); + for (int i=ParentTimeline()->selection_offset;iselections[i]; + s.track = minimum_selection_track + i - ParentTimeline()->selection_offset; s.in = selection_in; s.out = selection_out; } // If the config is set to select links as well with the edit tool - if (olive::CurrentConfig.edit_tool_selects_links) { + if (olive::config.edit_tool_selects_links) { // find which clips are selected - for (int j=0;jclips.size();j++) { + for (int j=0;jclips.size();j++) { - Clip* c = olive::ActiveSequence->clips.at(j).get(); + Clip* c = sequence()->clips.at(j).get(); if (c != nullptr && c->IsSelected(false)) { // loop through linked clips for (int k=0;klinked.size();k++) { - ClipPtr link = olive::ActiveSequence->clips.at(c->linked.at(k)); + ClipPtr link = sequence()->clips.at(c->linked.at(k)); // see if one of the selections is already covering this track if (!(link->track() >= minimum_selection_track @@ -2082,7 +2095,7 @@ void TimelineView::mouseMoveEvent(QMouseEvent *event) { link_sel.in = selection_in; link_sel.out = selection_out; link_sel.track = link->track(); - olive::ActiveSequence->selections.append(link_sel); + sequence()->selections.append(link_sel); } @@ -2093,40 +2106,41 @@ void TimelineView::mouseMoveEvent(QMouseEvent *event) { } // if the config is set to seek with the edit too, do so now - if (olive::CurrentConfig.edit_tool_also_seeks) { - panel_sequence_viewer->seek(qMin(panel_timeline->drag_frame_start, panel_timeline->cursor_frame)); + if (olive::config.edit_tool_also_seeks) { + panel_sequence_viewer->seek(qMin(ParentTimeline()->drag_frame_start, ParentTimeline()->cursor_frame)); } else { // if not, repaint (seeking will trigger a repaint) - panel_timeline->repaint_timeline(); + ParentTimeline()->repaint_timeline(); } + */ - } else if (panel_timeline->hand_moving) { + } else if (ParentTimeline()->hand_moving) { // if we're hand moving, we'll be adding values directly to the scrollbars // the scrollbars trigger repaints when they scroll, which is unnecessary here so we block them - panel_timeline->block_repaints = true; - panel_timeline->horizontalScrollBar->setValue(panel_timeline->horizontalScrollBar->value() + panel_timeline->drag_x_start - event->pos().x()); - scrollBar->setValue(scrollBar->value() + panel_timeline->drag_y_start - event->pos().y()); - panel_timeline->block_repaints = false; + ParentTimeline()->block_repaints = true; + ParentTimeline()->horizontalScrollBar->setValue(ParentTimeline()->horizontalScrollBar->value() + ParentTimeline()->drag_x_start - event->pos().x()); + scrollBar->setValue(scrollBar->value() + ParentTimeline()->drag_y_start - event->pos().y()); + ParentTimeline()->block_repaints = false; // finally repaint - panel_timeline->repaint_timeline(); + ParentTimeline()->repaint_timeline(); // store current cursor position for next hand move event - panel_timeline->drag_x_start = event->pos().x(); - panel_timeline->drag_y_start = event->pos().y(); + ParentTimeline()->drag_x_start = event->pos().x(); + ParentTimeline()->drag_y_start = event->pos().y(); - } else if (panel_timeline->moving_init) { + } else if (ParentTimeline()->moving_init) { if (track_resizing) { // get cursor movement - int diff = (event->pos().y() - panel_timeline->drag_y_start); + int diff = (event->pos().y() - ParentTimeline()->drag_y_start); // add it to the current track height - int new_height = panel_timeline->GetTrackHeight(track_target); - if (bottom_align) { + int new_height = track_target->height(); + if (alignment_ == olive::timeline::kAlignmentBottom) { new_height -= diff; } else { new_height += diff; @@ -2136,13 +2150,13 @@ void TimelineView::mouseMoveEvent(QMouseEvent *event) { new_height = qMax(new_height, olive::timeline::kTrackMinHeight); // set the track height - panel_timeline->SetTrackHeight(track_target, new_height); + track_target->set_height(new_height); // store current cursor position for next track resize event - panel_timeline->drag_y_start = event->pos().y(); + ParentTimeline()->drag_y_start = event->pos().y(); update(); - } else if (panel_timeline->moving_proc) { + } else if (ParentTimeline()->moving_proc) { // we're currently dragging ghosts update_ghosts(event->pos(), event->modifiers() & Qt::ShiftModifier); @@ -2153,9 +2167,10 @@ void TimelineView::mouseMoveEvent(QMouseEvent *event) { // actually apply it to the clips (in mouseReleaseEvent) // loop through clips for any currently selected - for (int i=0;iclips.size();i++) { + QVector partially_selected_clips = sequence()->SelectedClips(false); + for (int i=0;iclips.at(i).get(); + Clip* c = partially_selected_clips.at(i); if (c != nullptr) { Ghost g; @@ -2166,30 +2181,16 @@ void TimelineView::mouseMoveEvent(QMouseEvent *event) { // check if a transition is selected (prioritize transition selection) // (only the pointer tool supports moving transitions) - if (panel_timeline->tool == TIMELINE_TOOL_POINTER + if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_POINTER && (c->opening_transition != nullptr || c->closing_transition != nullptr)) { // check if any selections contain a whole transition - for (int j=0;jselections.size();j++) { - - const Selection& s = olive::ActiveSequence->selections.at(j); - - if (s.track == c->track()) { - if (selection_contains_transition(s, c, kTransitionOpening)) { - - g.transition = c->opening_transition; - add = true; - break; - - } else if (selection_contains_transition(s, c, kTransitionClosing)) { - - g.transition = c->closing_transition; - add = true; - break; - - } - } - + if (c->IsTransitionSelected(kTransitionOpening)) { + g.transition = c->opening_transition; + add = true; + } else if (c->IsTransitionSelected(kTransitionClosing)) { + g.transition = c->closing_transition; + add = true; } } @@ -2204,8 +2205,8 @@ void TimelineView::mouseMoveEvent(QMouseEvent *event) { if (g.transition != nullptr) { // transition may be a dual transition, check if it's already been added elsewhere - for (int j=0;jghosts.size();j++) { - if (panel_timeline->ghosts.at(j).transition == g.transition) { + for (int j=0;jghosts.size();j++) { + if (ParentTimeline()->ghosts.at(j).transition == g.transition) { add = false; break; } @@ -2214,61 +2215,52 @@ void TimelineView::mouseMoveEvent(QMouseEvent *event) { } if (add) { - g.clip = i; - g.trim_type = panel_timeline->trim_type; - panel_timeline->ghosts.append(g); + g.clip = c; + g.trim_type = ParentTimeline()->trim_type; + ParentTimeline()->ghosts.append(g); } } } } - if (panel_timeline->tool == TIMELINE_TOOL_SLIDE) { + if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_SLIDE) { // for the slide tool, we add the surrounding clips as ghosts that are getting trimmed the opposite way // store original array size since we'll be adding to it - int ghost_arr_size = panel_timeline->ghosts.size(); + int ghost_arr_size = ParentTimeline()->ghosts.size(); // loop through clips for any that are "touching" the selected clips - for (int j=0;jclips.size();j++) { + for (int i=0;ighosts.at(i).clip; - ClipPtr c = olive::ActiveSequence->clips.at(j); - if (c != nullptr) { + Clip* pre_clip = ghost_clip->track()->GetClipFromPoint(ghost_clip->timeline_in() - 1); + Clip* post_clip = ghost_clip->track()->GetClipFromPoint(ghost_clip->timeline_out() + 1); - for (int i=0;ighosts[i]; - g.trim_type = olive::timeline::TRIM_NONE; // the selected clips will be moving, not trimming - - ClipPtr ghost_clip = olive::ActiveSequence->clips.at(g.clip); - - if (c->track() == ghost_clip->track()) { - - // see if this clip is currently selected, if so we won't add it as a "touching" clip - bool found = false; - for (int k=0;kghosts.at(k).clip == j) { - found = true; - break; - } - } - - if (!found) { // the clip is not currently selected - - // check if this clip is indeed touching - bool is_in = (c->timeline_in() == ghost_clip->timeline_out()); - if (is_in || c->timeline_out() == ghost_clip->timeline_in()) { - Ghost gh; - gh.transition = nullptr; - gh.clip = j; - gh.trim_type = is_in ? olive::timeline::TRIM_IN : olive::timeline::TRIM_OUT; - panel_timeline->ghosts.append(gh); - } - } - } + // Check if this clip is already in the ghosts, in which case don't add it + for (int j=0;jghosts.at(j).clip == pre_clip) { + pre_clip = nullptr; + } else if (ParentTimeline()->ghosts.at(j).clip == post_clip) { + post_clip = nullptr; } } + + Ghost gh; + gh.transition = nullptr; + + if (pre_clip != nullptr) { + gh.clip = pre_clip; + gh.trim_type = olive::timeline::TRIM_OUT; + ParentTimeline()->ghosts.append(gh); + } + + if (post_clip != nullptr) { + gh.clip = post_clip; + gh.trim_type = olive::timeline::TRIM_IN; + ParentTimeline()->ghosts.append(gh); + } } } @@ -2276,18 +2268,18 @@ void TimelineView::mouseMoveEvent(QMouseEvent *event) { init_ghosts(); // if the ripple tool is selected, prepare to ripple - if (panel_timeline->tool == TIMELINE_TOOL_RIPPLE) { + if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_RIPPLE) { long axis = LONG_MAX; // find the earliest point within the selected clips which is the point we'll ripple around // also store the currently selected clips so we don't have to do it later - QVector ghost_clips; - ghost_clips.resize(panel_timeline->ghosts.size()); + QVector ghost_clips; + ghost_clips.resize(ParentTimeline()->ghosts.size()); - for (int i=0;ighosts.size();i++) { - ClipPtr c = olive::ActiveSequence->clips.at(panel_timeline->ghosts.at(i).clip); - if (panel_timeline->trim_type == olive::timeline::TRIM_IN) { + for (int i=0;ighosts.size();i++) { + Clip* c = ParentTimeline()->ghosts.at(i).clip; + if (ParentTimeline()->trim_type == olive::timeline::TRIM_IN) { axis = qMin(axis, c->timeline_in()); } else { axis = qMin(axis, c->timeline_out()); @@ -2298,19 +2290,20 @@ void TimelineView::mouseMoveEvent(QMouseEvent *event) { } // loop through clips and cache which are earlier than the axis and which after after - for (int i=0;iclips.size();i++) { - ClipPtr c = olive::ActiveSequence->clips.at(i); - if (c != nullptr && !ghost_clips.contains(c)) { + QVector sequence_clips = sequence()->GetAllClips(); + for (int i=0;itimeline_in() >= axis); // construct the list of pre and post clips - QVector& clip_list = (clip_is_post) ? post_clips : pre_clips; + QVector& clip_list = (clip_is_post) ? post_clips : pre_clips; // check if there's already a clip in this list on this track, and if this clip is closer or not bool found = false; for (int j=0;jtrack() == c->track()) { @@ -2335,26 +2328,28 @@ void TimelineView::mouseMoveEvent(QMouseEvent *event) { } // store selections - selection_command = new SetSelectionsCommand(olive::ActiveSequence.get()); - selection_command->old_data = olive::ActiveSequence->selections; + /* + selection_command = new SetSelectionsCommand(sequence().get()); + selection_command->old_data = sequence()->selections; + */ // ready to start moving clips - panel_timeline->moving_proc = true; + ParentTimeline()->moving_proc = true; } update_ui(false); - } else if (panel_timeline->splitting) { + } else if (ParentTimeline()->splitting) { // get the range of tracks currently dragged - int track_start = qMin(panel_timeline->cursor_track, panel_timeline->drag_track_start); - int track_end = qMax(panel_timeline->cursor_track, panel_timeline->drag_track_start); + int track_start = qMin(ParentTimeline()->cursor_track->Index(), ParentTimeline()->drag_track_start->Index()); + int track_end = qMax(ParentTimeline()->cursor_track->Index(), ParentTimeline()->drag_track_start->Index()); int track_size = 1 + track_end - track_start; // set tracks to be split - panel_timeline->split_tracks.resize(track_size); + ParentTimeline()->split_tracks.resize(track_size); for (int i=0;isplit_tracks[i] = track_start + i; + ParentTimeline()->split_tracks[i] = ParentTimeline()->cursor_track->track_list()->TrackAt(track_start + i); } // if alt isn't being held, also add the tracks of the clip's links @@ -2362,17 +2357,16 @@ void TimelineView::mouseMoveEvent(QMouseEvent *event) { for (int i=0;idrag_frame_start, panel_timeline->split_tracks[i]); + Clip* clip = ParentTimeline()->split_tracks[i]->GetClipFromPoint(ParentTimeline()->drag_frame_start); - if (clip_index > -1) { - ClipPtr clip = olive::ActiveSequence->clips.at(clip_index); + if (clip != nullptr) { for (int j=0;jlinked.size();j++) { - ClipPtr link = olive::ActiveSequence->clips.at(clip->linked.at(j)); + Clip* link = clip->linked.at(j); // if this clip isn't already in the list of tracks to split - if (link->track() < track_start || link->track() > track_end) { - panel_timeline->split_tracks.append(link->track()); + if (link->track()->Index() < track_start || link->track()->Index() > track_end) { + ParentTimeline()->split_tracks.append(link->track()); } } @@ -2382,108 +2376,95 @@ void TimelineView::mouseMoveEvent(QMouseEvent *event) { update_ui(false); - } else if (panel_timeline->rect_select_init) { + } else if (ParentTimeline()->rect_select_init) { // set if the user started dragging at point where there was no clip - if (panel_timeline->rect_select_proc) { + if (ParentTimeline()->rect_select_proc) { // we're currently rectangle selecting // set the right/bottom coords to the current mouse position // (left/top were set to the starting drag position earlier) - panel_timeline->rect_select_rect.setRight(event->pos().x()); + ParentTimeline()->rect_select_rect.setRight(event->pos().x()); - if (bottom_align) { - panel_timeline->rect_select_rect.setBottom(event->pos().y() - height()); + if (alignment_ == olive::timeline::kAlignmentBottom) { + ParentTimeline()->rect_select_rect.setBottom(event->pos().y() - height()); } else { - panel_timeline->rect_select_rect.setBottom(event->pos().y()); + ParentTimeline()->rect_select_rect.setBottom(event->pos().y()); } - long frame_min = qMin(panel_timeline->drag_frame_start, panel_timeline->cursor_frame); - long frame_max = qMax(panel_timeline->drag_frame_start, panel_timeline->cursor_frame); + long frame_min = qMin(ParentTimeline()->drag_frame_start, ParentTimeline()->cursor_frame); + long frame_max = qMax(ParentTimeline()->drag_frame_start, ParentTimeline()->cursor_frame); - int track_min = qMin(panel_timeline->drag_track_start, panel_timeline->cursor_track); - int track_max = qMax(panel_timeline->drag_track_start, panel_timeline->cursor_track); + int track_min = qMin(ParentTimeline()->drag_track_start->Index(), ParentTimeline()->cursor_track->Index()); + int track_max = qMax(ParentTimeline()->drag_track_start->Index(), ParentTimeline()->cursor_track->Index()); // determine which clips are in this rectangular selection - QVector selected_clips; - for (int i=0;iclips.size();i++) { - ClipPtr clip = olive::ActiveSequence->clips.at(i); - if (clip != nullptr && - clip->track() >= track_min && - clip->track() <= track_max && - !(clip->timeline_in() < frame_min && clip->timeline_out() < frame_min) && - !(clip->timeline_in() > frame_max && clip->timeline_out() > frame_max)) { + QVector selected_clips; + for (int j=0;jTrackCount();j++) { + Track* track = track_list_->TrackAt(j); - // create a group of the clip (and its links if alt is not pressed) - QVector session_clips; - session_clips.append(clip); + for (int i=0;iClipCount();i++) { + Clip* clip = track->GetClip(i).get(); + if (clip->track()->Index() >= track_min && + clip->track()->Index() <= track_max && + !(clip->timeline_in() < frame_min && clip->timeline_out() < frame_min) && + !(clip->timeline_in() > frame_max && clip->timeline_out() > frame_max)) { - if (!alt) { - for (int j=0;jlinked.size();j++) { - session_clips.append(olive::ActiveSequence->clips.at(clip->linked.at(j))); + // create a group of the clip (and its links if alt is not pressed) + QVector session_clips; + session_clips.append(clip); + + if (!alt) { + session_clips.append(clip->linked); } - } - // for each of these clips, see if clip has already been added - - // this can easily happen due to adding linked clips - for (int j=0;jselections.resize(selected_clips.size() + panel_timeline->selection_offset); for (int i=0;iselections[i+panel_timeline->selection_offset]; - ClipPtr clip = selected_clips.at(i); - s.old_in = s.in = clip->timeline_in(); - s.old_out = s.out = clip->timeline_out(); - s.old_track = s.track = clip->track(); + selected_clips.at(i)->track()->SelectClip(selected_clips.at(i)); } - panel_timeline->repaint_timeline(); + ParentTimeline()->repaint_timeline(); } else { // set up rectangle selecting - panel_timeline->rect_select_rect.setX(event->pos().x()); + ParentTimeline()->rect_select_rect.setX(event->pos().x()); - if (bottom_align) { + if (alignment_ == olive::timeline::kAlignmentBottom) { // bottom aligned widgets start with 0 at the bottom and go down to a negative number - panel_timeline->rect_select_rect.setY(event->pos().y() - height()); + ParentTimeline()->rect_select_rect.setY(event->pos().y() - height()); } else { - panel_timeline->rect_select_rect.setY(event->pos().y()); + ParentTimeline()->rect_select_rect.setY(event->pos().y()); } - panel_timeline->rect_select_rect.setWidth(0); - panel_timeline->rect_select_rect.setHeight(0); + ParentTimeline()->rect_select_rect.setWidth(0); + ParentTimeline()->rect_select_rect.setHeight(0); - panel_timeline->rect_select_proc = true; + ParentTimeline()->rect_select_proc = true; } } else if (current_tool_shows_cursor()) { // we're not currently performing an action (click is not pressed), but redraw because we have an on-screen cursor - panel_timeline->repaint_timeline(); + ParentTimeline()->repaint_timeline(); - } else if (panel_timeline->tool == TIMELINE_TOOL_POINTER || - panel_timeline->tool == TIMELINE_TOOL_RIPPLE || - panel_timeline->tool == TIMELINE_TOOL_ROLLING) { + } else if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_POINTER || + olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_RIPPLE || + olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_ROLLING) { // hide any tooltip that may be currently showing QToolTip::hideText(); @@ -2497,8 +2478,8 @@ void TimelineView::mouseMoveEvent(QMouseEvent *event) { // threshold around a trim point that the cursor can be within and still considered "trimming" int lim = 5; - long mouse_frame_lower = panel_timeline->getTimelineFrameFromScreenPoint(pos.x()-lim)-1; - long mouse_frame_upper = panel_timeline->getTimelineFrameFromScreenPoint(pos.x()+lim)+1; + long mouse_frame_lower = ParentTimeline()->getTimelineFrameFromScreenPoint(pos.x()-lim)-1; + long mouse_frame_upper = ParentTimeline()->getTimelineFrameFromScreenPoint(pos.x()+lim)+1; // used to determine whether we the cursor found a trim point or not bool found = false; @@ -2510,135 +2491,126 @@ void TimelineView::mouseMoveEvent(QMouseEvent *event) { // (and more specifically, whether another point is closer or not) int closeness = INT_MAX; - // while we loop through the clips, we cache the maximum/minimum tracks in this sequence - int min_track = INT_MAX; - int max_track = INT_MIN; - // we default to selecting no transition, but set this accordingly if the cursor is on a transition - panel_timeline->transition_select = kTransitionNone; + ParentTimeline()->transition_select = kTransitionNone; // we also default to no trimming which may be changed later in this function - panel_timeline->trim_type = olive::timeline::TRIM_NONE; + ParentTimeline()->trim_type = olive::timeline::TRIM_NONE; // set currently trimming clip to -1 (aka null) - panel_timeline->trim_target = -1; + ParentTimeline()->trim_target = nullptr; // loop through current clips in the sequence - for (int i=0;iclips.size();i++) { - ClipPtr c = olive::ActiveSequence->clips.at(i); - if (c != nullptr) { + QVector sequence_clips = sequence()->GetAllClips(); + for (int i=0;itrack()); - max_track = qMax(max_track, c->track()); + // if this clip is on the same track the mouse is + if (c->track() == ParentTimeline()->cursor_track) { - // if this clip is on the same track the mouse is - if (c->track() == panel_timeline->cursor_track) { + // if this cursor is inside the boundaries of this clip (hovering over the clip) + if (ParentTimeline()->cursor_frame >= c->timeline_in() && + ParentTimeline()->cursor_frame <= c->timeline_out()) { - // if this cursor is inside the boundaries of this clip (hovering over the clip) - if (panel_timeline->cursor_frame >= c->timeline_in() && - panel_timeline->cursor_frame <= c->timeline_out()) { + // acknowledge that we are hovering over a clip + cursor_contains_clip = true; - // acknowledge that we are hovering over a clip - cursor_contains_clip = true; + // start a timer to show a tooltip about this clip + tooltip_timer.start(); + tooltip_clip = c; - // start a timer to show a tooltip about this clip - tooltip_timer.start(); - tooltip_clip = i; + // check if the cursor is specifically hovering over one of the clip's transitions + if (c->opening_transition != nullptr + && ParentTimeline()->cursor_frame <= c->timeline_in() + c->opening_transition->get_true_length()) { - // check if the cursor is specifically hovering over one of the clip's transitions - if (c->opening_transition != nullptr - && panel_timeline->cursor_frame <= c->timeline_in() + c->opening_transition->get_true_length()) { + ParentTimeline()->transition_select = kTransitionOpening; - panel_timeline->transition_select = kTransitionOpening; + } else if (c->closing_transition != nullptr + && ParentTimeline()->cursor_frame >= c->timeline_out() - c->closing_transition->get_true_length()) { - } else if (c->closing_transition != nullptr - && panel_timeline->cursor_frame >= c->timeline_out() - c->closing_transition->get_true_length()) { + ParentTimeline()->transition_select = kTransitionClosing; - panel_timeline->transition_select = kTransitionClosing; - - } } + } - // is the cursor hovering around the clip's IN point? - if (c->timeline_in() > mouse_frame_lower && c->timeline_in() < mouse_frame_upper) { + // is the cursor hovering around the clip's IN point? + if (c->timeline_in() > mouse_frame_lower && c->timeline_in() < mouse_frame_upper) { - // test how close this IN point is to the cursor - int nc = qAbs(c->timeline_in() + 1 - panel_timeline->cursor_frame); + // test how close this IN point is to the cursor + int nc = qAbs(c->timeline_in() + 1 - ParentTimeline()->cursor_frame); - // and test whether it's closer than the last in/out point we found - if (nc < closeness) { + // and test whether it's closer than the last in/out point we found + if (nc < closeness) { - // if so, this is the point we'll make active for now (unless we find a closer one later) - panel_timeline->trim_target = i; - panel_timeline->trim_type = olive::timeline::TRIM_IN; - closeness = nc; - found = true; + // if so, this is the point we'll make active for now (unless we find a closer one later) + ParentTimeline()->trim_target = c; + ParentTimeline()->trim_type = olive::timeline::TRIM_IN; + closeness = nc; + found = true; - } } + } - // is the cursor hovering around the clip's OUT point? - if (c->timeline_out() > mouse_frame_lower && c->timeline_out() < mouse_frame_upper) { + // is the cursor hovering around the clip's OUT point? + if (c->timeline_out() > mouse_frame_lower && c->timeline_out() < mouse_frame_upper) { - // test how close this OUT point is to the cursor - int nc = qAbs(c->timeline_out() - 1 - panel_timeline->cursor_frame); + // test how close this OUT point is to the cursor + int nc = qAbs(c->timeline_out() - 1 - ParentTimeline()->cursor_frame); - // and test whether it's closer than the last in/out point we found - if (nc < closeness) { + // and test whether it's closer than the last in/out point we found + if (nc < closeness) { - // if so, this is the point we'll make active for now (unless we find a closer one later) - panel_timeline->trim_target = i; - panel_timeline->trim_type = olive::timeline::TRIM_OUT; - closeness = nc; - found = true; + // if so, this is the point we'll make active for now (unless we find a closer one later) + ParentTimeline()->trim_target = c; + ParentTimeline()->trim_type = olive::timeline::TRIM_OUT; + closeness = nc; + found = true; - } } + } - // the pointer can be used to resize/trim transitions, here we test if the - // cursor is within the trim point of one of the clip's transitions - if (panel_timeline->tool == TIMELINE_TOOL_POINTER) { + // the pointer can be used to resize/trim transitions, here we test if the + // cursor is within the trim point of one of the clip's transitions + if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_POINTER) { - // if the clip has an opening transition - if (c->opening_transition != nullptr) { + // if the clip has an opening transition + if (c->opening_transition != nullptr) { - // cache the timeline frame where the transition ends - long transition_point = c->timeline_in() + c->opening_transition->get_true_length(); + // cache the timeline frame where the transition ends + long transition_point = c->timeline_in() + c->opening_transition->get_true_length(); - // check if the cursor is hovering around it (within the threshold) - if (transition_point > mouse_frame_lower && transition_point < mouse_frame_upper) { + // check if the cursor is hovering around it (within the threshold) + if (transition_point > mouse_frame_lower && transition_point < mouse_frame_upper) { - // similar to above, test how close it is and if it's closer, make this active - int nc = qAbs(transition_point - 1 - panel_timeline->cursor_frame); - if (nc < closeness) { - panel_timeline->trim_target = i; - panel_timeline->trim_type = olive::timeline::TRIM_OUT; - panel_timeline->transition_select = kTransitionOpening; - closeness = nc; - found = true; - } + // similar to above, test how close it is and if it's closer, make this active + int nc = qAbs(transition_point - 1 - ParentTimeline()->cursor_frame); + if (nc < closeness) { + ParentTimeline()->trim_target = c; + ParentTimeline()->trim_type = olive::timeline::TRIM_OUT; + ParentTimeline()->transition_select = kTransitionOpening; + closeness = nc; + found = true; } } + } - // if the clip has a closing transition - if (c->closing_transition != nullptr) { + // if the clip has a closing transition + if (c->closing_transition != nullptr) { - // cache the timeline frame where the transition starts - long transition_point = c->timeline_out() - c->closing_transition->get_true_length(); + // cache the timeline frame where the transition starts + long transition_point = c->timeline_out() - c->closing_transition->get_true_length(); - // check if the cursor is hovering around it (within the threshold) - if (transition_point > mouse_frame_lower && transition_point < mouse_frame_upper) { + // check if the cursor is hovering around it (within the threshold) + if (transition_point > mouse_frame_lower && transition_point < mouse_frame_upper) { - // similar to above, test how close it is and if it's closer, make this active - int nc = qAbs(transition_point + 1 - panel_timeline->cursor_frame); - if (nc < closeness) { - panel_timeline->trim_target = i; - panel_timeline->trim_type = olive::timeline::TRIM_IN; - panel_timeline->transition_select = kTransitionClosing; - closeness = nc; - found = true; - } + // similar to above, test how close it is and if it's closer, make this active + int nc = qAbs(transition_point + 1 - ParentTimeline()->cursor_frame); + if (nc < closeness) { + ParentTimeline()->trim_target = c; + ParentTimeline()->trim_type = olive::timeline::TRIM_IN; + ParentTimeline()->transition_select = kTransitionClosing; + closeness = nc; + found = true; } } } @@ -2649,10 +2621,10 @@ void TimelineView::mouseMoveEvent(QMouseEvent *event) { // if the cursor is indeed on a clip edge, we set the cursor accordingly if (found) { - if (panel_timeline->trim_type == olive::timeline::TRIM_IN) { // if we're trimming an IN point - setCursor(panel_timeline->tool == TIMELINE_TOOL_RIPPLE ? olive::cursor::LeftRipple : olive::cursor::LeftTrim); + if (ParentTimeline()->trim_type == olive::timeline::TRIM_IN) { // if we're trimming an IN point + setCursor(olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_RIPPLE ? olive::cursor::LeftRipple : olive::cursor::LeftTrim); } else { // if we're trimming an OUT point - setCursor(panel_timeline->tool == TIMELINE_TOOL_RIPPLE ? olive::cursor::RightRipple : olive::cursor::RightTrim); + setCursor(olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_RIPPLE ? olive::cursor::RightRipple : olive::cursor::RightTrim); } } else { @@ -2662,44 +2634,44 @@ void TimelineView::mouseMoveEvent(QMouseEvent *event) { unsetCursor(); // check to see if we're resizing a track height - int test_range = 5; int mouse_pos = event->pos().y(); - int hover_track = getTrackFromScreenPoint(mouse_pos); - int track_y_edge = getScreenPointFromTrack(hover_track); + Track* hover_track = getTrackFromScreenPoint(mouse_pos); - if (!bottom_align) { - track_y_edge += panel_timeline->GetTrackHeight(hover_track); - } + if (hover_track != nullptr) { + int test_range = 5; // FIXME magic number - if (mouse_pos > track_y_edge - test_range - && mouse_pos < track_y_edge + test_range) { - if (cursor_contains_clip - || (olive::CurrentConfig.show_track_lines - && panel_timeline->cursor_track >= min_track - && panel_timeline->cursor_track <= max_track)) { + int track_y_edge = getScreenPointFromTrack(hover_track); + + if (alignment_ == olive::timeline::kAlignmentTop) { + track_y_edge += hover_track->height(); + } + + if (mouse_pos > track_y_edge - test_range + && mouse_pos < track_y_edge + test_range) { track_resizing = true; track_target = hover_track; setCursor(Qt::SizeVerCursor); } } + } - } else if (panel_timeline->tool == TIMELINE_TOOL_SLIP) { + } else if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_SLIP) { // we're not currently performing any slipping, all we do here is set the cursor if mouse is hovering over a // cursor - if (getClipIndexFromCoords(panel_timeline->cursor_frame, panel_timeline->cursor_track) > -1) { + if (GetClipAtCursor() != nullptr) { setCursor(olive::cursor::Slip); } else { unsetCursor(); } - } else if (panel_timeline->tool == TIMELINE_TOOL_TRANSITION) { + } else if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_TRANSITION) { - if (panel_timeline->transition_tool_init) { + if (ParentTimeline()->transition_tool_init) { // the transition tool has started - if (panel_timeline->transition_tool_proc) { + if (ParentTimeline()->transition_tool_proc) { // ghosts have been set up, so just run update update_ghosts(event->pos(), event->modifiers() & Qt::ShiftModifier); @@ -2707,29 +2679,27 @@ void TimelineView::mouseMoveEvent(QMouseEvent *event) { } else { // transition tool is being used but ghosts haven't been set up yet, set them up now - int primary_type = kTransitionOpening; - int primary = panel_timeline->transition_tool_open_clip; - if (primary == -1) { + TransitionType primary_type = kTransitionOpening; + Clip* primary = ParentTimeline()->transition_tool_open_clip; + if (primary == nullptr) { primary_type = kTransitionClosing; - primary = panel_timeline->transition_tool_close_clip; + primary = ParentTimeline()->transition_tool_close_clip; } - ClipPtr c = olive::ActiveSequence->clips.at(primary); - Ghost g; g.in = g.old_in = g.out = g.old_out = (primary_type == kTransitionOpening) ? - c->timeline_in() - : c->timeline_out(); + primary->timeline_in() + : primary->timeline_out(); - g.track = c->track(); + g.track = primary->track(); g.clip = primary; g.media_stream = primary_type; g.trim_type = olive::timeline::TRIM_NONE; - panel_timeline->ghosts.append(g); + ParentTimeline()->ghosts.append(g); - panel_timeline->transition_tool_proc = true; + ParentTimeline()->transition_tool_proc = true; } @@ -2738,42 +2708,40 @@ void TimelineView::mouseMoveEvent(QMouseEvent *event) { // transition tool has been selected but is not yet active, so we show screen feedback to the user on // possible transitions - int mouse_clip = getClipIndexFromCoords(panel_timeline->cursor_frame, panel_timeline->cursor_track); + Clip* mouse_clip = GetClipAtCursor(); // set default transition tool references to no clip - panel_timeline->transition_tool_open_clip = -1; - panel_timeline->transition_tool_close_clip = -1; + ParentTimeline()->transition_tool_open_clip = nullptr; + ParentTimeline()->transition_tool_close_clip = nullptr; - if (mouse_clip > -1) { + if (mouse_clip != nullptr) { // cursor is hovering over a clip - ClipPtr c = olive::ActiveSequence->clips.at(mouse_clip); - // check if the clip and transition are both the same sign (meaning video/audio are the same) - if (same_sign(c->track(), panel_timeline->transition_tool_side)) { + if (mouse_clip->track()->type() == ParentTimeline()->transition_tool_side) { // the range within which the transition tool will assume the user wants to make a shared transition // between two clips rather than just one transition on one clip - long between_range = getFrameFromScreenPoint(panel_timeline->zoom, TRANSITION_BETWEEN_RANGE) + 1; + long between_range = getFrameFromScreenPoint(ParentTimeline()->zoom, TRANSITION_BETWEEN_RANGE) + 1; // set whether the transition is opening or closing based on whether the cursor is on the left half // or right half of the clip - if (panel_timeline->cursor_frame > (c->timeline_in() + (c->length()/2))) { - panel_timeline->transition_tool_close_clip = mouse_clip; + if (ParentTimeline()->cursor_frame > (mouse_clip->timeline_in() + (mouse_clip->length()/2))) { + ParentTimeline()->transition_tool_close_clip = mouse_clip; // if the cursor is within this range, set the post_clip to be the next clip touching // // getClipIndexFromCoords() will automatically set to -1 if there's no clip there which means the // end result will be the same as not setting a clip here at all - if (panel_timeline->cursor_frame > c->timeline_out() - between_range) { - panel_timeline->transition_tool_open_clip = getClipIndexFromCoords(c->timeline_out()+1, c->track()); + if (ParentTimeline()->cursor_frame > mouse_clip->timeline_out() - between_range) { + ParentTimeline()->transition_tool_open_clip = mouse_clip->track()->GetClipFromPoint(mouse_clip->timeline_out()+1); } } else { - panel_timeline->transition_tool_open_clip = mouse_clip; + ParentTimeline()->transition_tool_open_clip = mouse_clip; - if (panel_timeline->cursor_frame < c->timeline_in() + between_range) { - panel_timeline->transition_tool_close_clip = getClipIndexFromCoords(c->timeline_in()-1, c->track()); + if (ParentTimeline()->cursor_frame < mouse_clip->timeline_in() + between_range) { + ParentTimeline()->transition_tool_close_clip = mouse_clip->track()->GetClipFromPoint(mouse_clip->timeline_in()-1); } } @@ -2781,7 +2749,7 @@ void TimelineView::mouseMoveEvent(QMouseEvent *event) { } } - panel_timeline->repaint_timeline(); + ParentTimeline()->repaint_timeline(); } } } @@ -2790,7 +2758,7 @@ void TimelineView::leaveEvent(QEvent*) { tooltip_timer.stop(); } -void draw_waveform(ClipPtr clip, const FootageStream* ms, long media_length, QPainter *p, const QRect& clip_rect, int waveform_start, int waveform_limit, double zoom) { +void draw_waveform(Clip* clip, const FootageStream* ms, long media_length, QPainter *p, const QRect& clip_rect, int waveform_start, int waveform_limit, double zoom) { // audio channels multiplied by the number of bytes in a 16-bit audio sample int divider = ms->audio_channels*2; @@ -2808,7 +2776,7 @@ void draw_waveform(ClipPtr clip, const FootageStream* ms, long media_length, QPa if (last_waveform_index < 0) last_waveform_index = waveform_index; for (int j=0;jaudio_channels;j++) { - int mid = (olive::CurrentConfig.rectified_waveforms) ? clip_rect.top()+channel_height*(j+1) : clip_rect.top()+channel_height*j+(channel_height/2); + int mid = (olive::config.rectified_waveforms) ? clip_rect.top()+channel_height*(j+1) : clip_rect.top()+channel_height*j+(channel_height/2); int offset_range_start = last_waveform_index+(j*2); int offset_range_end = waveform_index+(j*2); @@ -2832,7 +2800,7 @@ void draw_waveform(ClipPtr clip, const FootageStream* ms, long media_length, QPa } // draw waveforms - if (olive::CurrentConfig.rectified_waveforms) { + if (olive::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)); @@ -2848,11 +2816,11 @@ void draw_waveform(ClipPtr clip, const FootageStream* ms, long media_length, QPa } } -void draw_transition(QPainter& p, ClipPtr c, const QRect& clip_rect, QRect& text_rect, int transition_type) { +void TimelineView::draw_transition(QPainter& p, Clip* c, const QRect& clip_rect, QRect& text_rect, int transition_type) { TransitionPtr t = (transition_type == kTransitionOpening) ? c->opening_transition : c->closing_transition; if (t != nullptr) { QColor transition_color(255, 0, 0, 16); - int transition_width = getScreenPointFromFrame(panel_timeline->zoom, t->get_true_length()); + int transition_width = getScreenPointFromFrame(ParentTimeline()->zoom, t->get_true_length()); int transition_height = clip_rect.height(); int tr_y = clip_rect.y(); int tr_x = 0; @@ -2900,44 +2868,40 @@ void draw_transition(QPainter& p, ClipPtr c, const QRect& clip_rect, QRect& text void TimelineView::paintEvent(QPaintEvent*) { // Draw clips - if (olive::ActiveSequence != nullptr) { + if (track_list_ != nullptr) { QPainter p(this); // get widget width and height - int video_track_limit = 0; - int audio_track_limit = 0; - for (int i=0;iclips.size();i++) { - ClipPtr clip = olive::ActiveSequence->clips.at(i); - if (clip != nullptr) { - video_track_limit = qMin(video_track_limit, clip->track()); - audio_track_limit = qMax(audio_track_limit, clip->track()); - } - } // start by adding a track height worth of padding int panel_height = olive::timeline::kTrackDefaultHeight; - // loop through tracks for maximum panel height - if (bottom_align) { - for (int i=-1;i>=video_track_limit;i--) { - panel_height += panel_timeline->GetTrackHeight(i); - } - } else { - for (int i=0;i<=audio_track_limit;i++) { - panel_height += panel_timeline->GetTrackHeight(i); - } + for (int i=0;iTrackCount();i++) { + panel_height += track_list_->TrackAt(i)->height() + 1; } - if (bottom_align) { + if (alignment_ == olive::timeline::kAlignmentBottom) { scrollBar->setMinimum(qMin(0, - panel_height + height())); } else { scrollBar->setMaximum(qMax(0, panel_height - height())); } - for (int i=0;iclips.size();i++) { - ClipPtr clip = olive::ActiveSequence->clips.at(i); - if (clip != nullptr && is_track_visible(clip->track())) { - QRect clip_rect(panel_timeline->getTimelineScreenPointFromFrame(clip->timeline_in()), getScreenPointFromTrack(clip->track()), getScreenPointFromFrame(panel_timeline->zoom, clip->length()), panel_timeline->GetTrackHeight(clip->track())); - QRect text_rect(clip_rect.left() + olive::timeline::kClipTextPadding, clip_rect.top() + olive::timeline::kClipTextPadding, clip_rect.width() - olive::timeline::kClipTextPadding - 1, clip_rect.height() - olive::timeline::kClipTextPadding - 1); + int track_line = 0; + + for (int i=0;iTrackCount();i++) { + + Track* track = track_list_->TrackAt(i); + + for (int j=0;jClipCount();j++) { + Clip* clip = track->GetClip(j).get(); + + QRect clip_rect(ParentTimeline()->getTimelineScreenPointFromFrame(clip->timeline_in()), + getScreenPointFromTrack(clip->track()), + getScreenPointFromFrame(ParentTimeline()->zoom, clip->length()), + clip->track()->height()); + QRect text_rect(clip_rect.left() + olive::timeline::kClipTextPadding, + clip_rect.top() + olive::timeline::kClipTextPadding, + clip_rect.width() - olive::timeline::kClipTextPadding - 1, + clip_rect.height() - olive::timeline::kClipTextPadding - 1); if (clip_rect.left() < width() && clip_rect.right() >= 0 && clip_rect.top() < height() && clip_rect.bottom() >= 0) { QRect actual_clip_rect = clip_rect; if (actual_clip_rect.x() < 0) actual_clip_rect.setX(0); @@ -2993,18 +2957,18 @@ void TimelineView::paintEvent(QPaintEvent*) { // draw thumbnail/waveform long media_length = clip->media_length(); - if (clip->track() < 0) { + if (clip->type() == Track::kTypeVideo) { // draw thumbnail int thumb_y = p.fontMetrics().height()+olive::timeline::kClipTextPadding+olive::timeline::kClipTextPadding; if (thumb_x < width() && thumb_y < height()) { int space_for_thumb = clip_rect.width()-1; if (clip->opening_transition != nullptr) { - int ot_width = getScreenPointFromFrame(panel_timeline->zoom, clip->opening_transition->get_true_length()); + int ot_width = getScreenPointFromFrame(ParentTimeline()->zoom, clip->opening_transition->get_true_length()); thumb_x += ot_width; space_for_thumb -= ot_width; } if (clip->closing_transition != nullptr) { - space_for_thumb -= getScreenPointFromFrame(panel_timeline->zoom, clip->closing_transition->get_true_length()); + space_for_thumb -= getScreenPointFromFrame(ParentTimeline()->zoom, clip->closing_transition->get_true_length()); } int thumb_height = clip_rect.height()-thumb_y; int thumb_width = qRound(thumb_height*(double(ms->video_preview.width())/double(ms->video_preview.height()))); @@ -3028,14 +2992,14 @@ void TimelineView::paintEvent(QPaintEvent*) { } if (clip->timeline_out() - clip->timeline_in() + clip->clip_in() > clip->media_length()) { draw_checkerboard = true; - checkerboard_rect.setLeft(panel_timeline->getTimelineScreenPointFromFrame(clip->media_length() + clip->timeline_in() - clip->clip_in())); + checkerboard_rect.setLeft(ParentTimeline()->getTimelineScreenPointFromFrame(clip->media_length() + clip->timeline_in() - clip->clip_in())); } } else if (clip_rect.height() > olive::timeline::kTrackMinHeight) { // draw waveform p.setPen(QColor(80, 80, 80)); int waveform_start = -qMin(clip_rect.x(), 0); - int waveform_limit = qMin(clip_rect.width(), getScreenPointFromFrame(panel_timeline->zoom, media_length - clip->clip_in())); + int waveform_limit = qMin(clip_rect.width(), getScreenPointFromFrame(ParentTimeline()->zoom, media_length - clip->clip_in())); if ((clip_rect.x() + waveform_limit) > width()) { waveform_limit -= (clip_rect.x() + waveform_limit - width()); @@ -3044,7 +3008,7 @@ void TimelineView::paintEvent(QPaintEvent*) { if (waveform_limit > 0) checkerboard_rect.setLeft(checkerboard_rect.left() + waveform_limit); } - draw_waveform(clip, ms, media_length, &p, clip_rect, waveform_start, waveform_limit, panel_timeline->zoom); + draw_waveform(clip, ms, media_length, &p, clip_rect, waveform_start, waveform_limit, ParentTimeline()->zoom); } } if (draw_checkerboard) { @@ -3086,9 +3050,9 @@ void TimelineView::paintEvent(QPaintEvent*) { // 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); + int marker_x = ParentTimeline()->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); + Marker::Draw(p, marker_x, clip_rect.bottom()-p.fontMetrics().height(), clip_rect.bottom(), false); } } p.setBrush(Qt::NoBrush); @@ -3112,7 +3076,7 @@ void TimelineView::paintEvent(QPaintEvent*) { } if (clip->linked.size() > 0) { int underline_y = olive::timeline::kClipTextPadding + p.fontMetrics().height() + clip_rect.top(); - int underline_width = qMin(text_rect.width() - 1, p.fontMetrics().width(clip->name())); + int underline_width = qMin(text_rect.width() - 1, p.fontMetrics().width(clip->name())); p.drawLine(text_rect.x(), underline_y, text_rect.x() + underline_width, underline_y); } QString name = clip->name(); @@ -3130,22 +3094,22 @@ void TimelineView::paintEvent(QPaintEvent*) { if (clip_rect.bottom() >= 0 && clip_rect.bottom() < height()) p.drawLine(QPoint(qMax(0, clip_rect.left()), clip_rect.bottom()), QPoint(qMin(width(), clip_rect.right()), clip_rect.bottom())); // draw transition tool - if (panel_timeline->tool == TIMELINE_TOOL_TRANSITION) { + if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_TRANSITION) { - bool shared_transition = (panel_timeline->transition_tool_open_clip > -1 - && panel_timeline->transition_tool_close_clip > -1); + bool shared_transition = (ParentTimeline()->transition_tool_open_clip != nullptr + && ParentTimeline()->transition_tool_close_clip != nullptr); QRect transition_tool_rect = clip_rect; bool draw_transition_tool_rect = false; - if (panel_timeline->transition_tool_open_clip == i) { + if (ParentTimeline()->transition_tool_open_clip == clip) { if (shared_transition) { transition_tool_rect.setWidth(TRANSITION_BETWEEN_RANGE); } else { transition_tool_rect.setWidth(transition_tool_rect.width()>>2); } draw_transition_tool_rect = true; - } else if (panel_timeline->transition_tool_close_clip == i) { + } else if (ParentTimeline()->transition_tool_close_clip == clip) { if (shared_transition) { transition_tool_rect.setLeft(transition_tool_rect.right() - TRANSITION_BETWEEN_RANGE); } else { @@ -3168,87 +3132,101 @@ void TimelineView::paintEvent(QPaintEvent*) { } } } - } - // Draw recording clip if recording if valid - if (panel_sequence_viewer->is_recording_cued() && is_track_visible(panel_sequence_viewer->recording_track)) { - int rec_track_x = panel_timeline->getTimelineScreenPointFromFrame(panel_sequence_viewer->recording_start); - int rec_track_y = getScreenPointFromTrack(panel_sequence_viewer->recording_track); - int rec_track_height = panel_timeline->GetTrackHeight(panel_sequence_viewer->recording_track); - if (panel_sequence_viewer->recording_start != panel_sequence_viewer->recording_end) { - QRect rec_rect( + // Draw recording clip if recording if valid + if (panel_sequence_viewer->is_recording_cued() && panel_sequence_viewer->recording_track == track) { + int rec_track_x = ParentTimeline()->getTimelineScreenPointFromFrame(panel_sequence_viewer->recording_start); + int rec_track_y = getScreenPointFromTrack(panel_sequence_viewer->recording_track); + int rec_track_height = track->height(); + if (panel_sequence_viewer->recording_start != panel_sequence_viewer->recording_end) { + QRect rec_rect( + rec_track_x, + rec_track_y, + getScreenPointFromFrame(ParentTimeline()->zoom, panel_sequence_viewer->recording_end - panel_sequence_viewer->recording_start), + rec_track_height + ); + p.setPen(QPen(QColor(96, 96, 96), 2)); + p.fillRect(rec_rect, QColor(192, 192, 192)); + p.drawRect(rec_rect); + } + QRect active_rec_rect( rec_track_x, rec_track_y, - getScreenPointFromFrame(panel_timeline->zoom, panel_sequence_viewer->recording_end - panel_sequence_viewer->recording_start), + getScreenPointFromFrame(ParentTimeline()->zoom, panel_sequence_viewer->seq->playhead - panel_sequence_viewer->recording_start), rec_track_height ); - p.setPen(QPen(QColor(96, 96, 96), 2)); - p.fillRect(rec_rect, QColor(192, 192, 192)); - p.drawRect(rec_rect); - } - QRect active_rec_rect( - rec_track_x, - rec_track_y, - getScreenPointFromFrame(panel_timeline->zoom, panel_sequence_viewer->seq->playhead - panel_sequence_viewer->recording_start), - rec_track_height - ); - p.setPen(QPen(QColor(192, 0, 0), 2)); - p.fillRect(active_rec_rect, QColor(255, 96, 96)); - p.drawRect(active_rec_rect); + p.setPen(QPen(QColor(192, 0, 0), 2)); + p.fillRect(active_rec_rect, QColor(255, 96, 96)); + p.drawRect(active_rec_rect); - p.setPen(Qt::NoPen); + p.setPen(Qt::NoPen); - if (!panel_sequence_viewer->playing) { - int rec_marker_size = 6; - int rec_track_midY = rec_track_y + (rec_track_height >> 1); - p.setBrush(Qt::white); - QPoint cue_marker[3] = { - QPoint(rec_track_x, rec_track_midY - rec_marker_size), - QPoint(rec_track_x + rec_marker_size, rec_track_midY), - QPoint(rec_track_x, rec_track_midY + rec_marker_size) - }; - p.drawPolygon(cue_marker, 3); - } - } - - // Draw track lines - if (olive::CurrentConfig.show_track_lines) { - p.setPen(QColor(0, 0, 0, 96)); - audio_track_limit++; - if (video_track_limit == 0) video_track_limit--; - - if (bottom_align) { - // only draw lines for video tracks - for (int i=video_track_limit;i<0;i++) { - int line_y = getScreenPointFromTrack(i) - 1; - p.drawLine(0, line_y, rect().width(), line_y); - } - } else { - // only draw lines for audio tracks - for (int i=0;iGetTrackHeight(i); - p.drawLine(0, line_y, rect().width(), line_y); + if (!panel_sequence_viewer->playing) { + int rec_marker_size = 6; + int rec_track_midY = rec_track_y + (rec_track_height >> 1); + p.setBrush(Qt::white); + QPoint cue_marker[3] = { + QPoint(rec_track_x, rec_track_midY - rec_marker_size), + QPoint(rec_track_x + rec_marker_size, rec_track_midY), + QPoint(rec_track_x, rec_track_midY + rec_marker_size) + }; + p.drawPolygon(cue_marker, 3); } } - } - // Draw selections - for (int i=0;iselections.size();i++) { - const Selection& s = olive::ActiveSequence->selections.at(i); - if (is_track_visible(s.track)) { - int selection_y = getScreenPointFromTrack(s.track); - int selection_x = panel_timeline->getTimelineScreenPointFromFrame(s.in); + // Draw selections + QVector selections = track->Selections(); + for (int j=0;jgetTimelineScreenPointFromFrame(s.in()); p.setPen(Qt::NoPen); p.setBrush(Qt::NoBrush); - p.fillRect(selection_x, selection_y, panel_timeline->getTimelineScreenPointFromFrame(s.out) - selection_x, panel_timeline->GetTrackHeight(s.track), QColor(0, 0, 0, 64)); + p.fillRect(selection_x, + track_line, + ParentTimeline()->getTimelineScreenPointFromFrame(s.out()) - selection_x, + s.track()->height(), + QColor(0, 0, 0, 64)); } + + // Draw splitting cursor + if (ParentTimeline()->splitting && ParentTimeline()->split_tracks.contains(track)) { + int cursor_x = ParentTimeline()->getTimelineScreenPointFromFrame(ParentTimeline()->drag_frame_start); + + p.setPen(QColor(64, 64, 64)); + p.drawLine(cursor_x, + track_line, + cursor_x, + track_line + track->height()); + } + + // Draw edit cursor + if (current_tool_shows_cursor() && ParentTimeline()->cursor_track == track) { + int cursor_x = ParentTimeline()->getTimelineScreenPointFromFrame(ParentTimeline()->cursor_frame); + + p.setPen(Qt::gray); + p.drawLine(cursor_x, + track_line, + cursor_x, + track_line + track->height()); + } + + // Draw track's line + track_line += track->height(); + if (track_line >= 0 && track_line < height()) { + p.setPen(QColor(0, 0, 0, 96)); + p.drawLine(0, track_line, rect().width(), track_line); + } + track_line++; + + } // draw rectangle select - if (panel_timeline->rect_select_proc) { - QRect rect_select = panel_timeline->rect_select_rect; + if (ParentTimeline()->rect_select_proc) { + QRect rect_select = ParentTimeline()->rect_select_rect; - if (bottom_align) { + if (alignment_ == olive::timeline::kAlignmentBottom) { rect_select.translate(0, height()); } @@ -3256,17 +3234,17 @@ void TimelineView::paintEvent(QPaintEvent*) { } // Draw ghosts - if (!panel_timeline->ghosts.isEmpty()) { + if (!ParentTimeline()->ghosts.isEmpty()) { QVector insert_points; long first_ghost = LONG_MAX; - for (int i=0;ighosts.size();i++) { - const Ghost& g = panel_timeline->ghosts.at(i); + for (int i=0;ighosts.size();i++) { + const Ghost& g = ParentTimeline()->ghosts.at(i); first_ghost = qMin(first_ghost, g.in); - if (is_track_visible(g.track)) { - int ghost_x = panel_timeline->getTimelineScreenPointFromFrame(g.in); + if (g.track->type() == track_list_->type()) { + int ghost_x = ParentTimeline()->getTimelineScreenPointFromFrame(g.in); int ghost_y = getScreenPointFromTrack(g.track); - int ghost_width = panel_timeline->getTimelineScreenPointFromFrame(g.out) - ghost_x - 1; - int ghost_height = panel_timeline->GetTrackHeight(g.track) - 1; + int ghost_width = ParentTimeline()->getTimelineScreenPointFromFrame(g.out) - ghost_x - 1; + int ghost_height = g.track->height() - 1; insert_points.append(ghost_y + (ghost_height>>1)); @@ -3278,10 +3256,10 @@ void TimelineView::paintEvent(QPaintEvent*) { } // draw insert indicator - if (panel_timeline->move_insert && !insert_points.isEmpty()) { + if (ParentTimeline()->move_insert && !insert_points.isEmpty()) { p.setBrush(Qt::white); p.setPen(Qt::NoPen); - int insert_x = panel_timeline->getTimelineScreenPointFromFrame(first_ghost); + int insert_x = ParentTimeline()->getTimelineScreenPointFromFrame(first_ghost); int tri_size = olive::timeline::kTrackMinHeight>>2; for (int i=0;isplitting) { - for (int i=0;isplit_tracks.size();i++) { - if (is_track_visible(panel_timeline->split_tracks.at(i))) { - int cursor_x = panel_timeline->getTimelineScreenPointFromFrame(panel_timeline->drag_frame_start); - int cursor_y = getScreenPointFromTrack(panel_timeline->split_tracks.at(i)); - - p.setPen(QColor(64, 64, 64)); - p.drawLine(cursor_x, cursor_y, cursor_x, cursor_y + panel_timeline->GetTrackHeight(panel_timeline->split_tracks.at(i))); - } - } - } - // Draw playhead p.setPen(Qt::red); - int playhead_x = panel_timeline->getTimelineScreenPointFromFrame(olive::ActiveSequence->playhead); + int playhead_x = ParentTimeline()->getTimelineScreenPointFromFrame(sequence()->playhead); p.drawLine(playhead_x, rect().top(), playhead_x, rect().bottom()); // Draw single frame highlight - int playhead_frame_width = panel_timeline->getTimelineScreenPointFromFrame(olive::ActiveSequence->playhead+1) - playhead_x; + int playhead_frame_width = ParentTimeline()->getTimelineScreenPointFromFrame(sequence()->playhead+1) - playhead_x; if (playhead_frame_width > 5){ //hardcoded for now, maybe better way to do this? - QRectF singleFrameRect(playhead_x, rect().top(), playhead_frame_width, rect().bottom()); - p.fillRect(singleFrameRect, QColor(255,255,255,15)); + QRectF singleFrameRect(playhead_x, rect().top(), playhead_frame_width, rect().bottom()); + p.fillRect(singleFrameRect, QColor(255,255,255,15)); } // draw border p.setPen(QColor(0, 0, 0, 64)); - int edge_y = (bottom_align) ? rect().height()-1 : 0; + int edge_y = 0; + p.drawLine(0, edge_y, rect().width(), edge_y); + edge_y = rect().height()-1; p.drawLine(0, edge_y, rect().width(), edge_y); // draw snap point - if (panel_timeline->snapped) { + if (olive::timeline::snapped) { p.setPen(Qt::white); - int snap_x = panel_timeline->getTimelineScreenPointFromFrame(panel_timeline->snap_point); + int snap_x = ParentTimeline()->getTimelineScreenPointFromFrame(olive::timeline::snap_point); p.drawLine(snap_x, 0, snap_x, height()); } - - // Draw edit cursor - if (current_tool_shows_cursor() && is_track_visible(panel_timeline->cursor_track)) { - int cursor_x = panel_timeline->getTimelineScreenPointFromFrame(panel_timeline->cursor_frame); - int cursor_y = getScreenPointFromTrack(panel_timeline->cursor_track); - - p.setPen(Qt::gray); - p.drawLine(cursor_x, cursor_y, cursor_x, cursor_y + panel_timeline->GetTrackHeight(panel_timeline->cursor_track)); - } } } @@ -3348,81 +3305,50 @@ void TimelineView::resizeEvent(QResizeEvent *) { scrollBar->setPageStep(height()); } -bool TimelineView::is_track_visible(int track) { - return (bottom_align == (track < 0)); -} - // ************************************** // screen point <-> frame/track functions // ************************************** -int TimelineView::getTrackFromScreenPoint(int y) { - int track_candidate = 0; - +Track *TimelineView::getTrackFromScreenPoint(int y) { y += scroll; - if (bottom_align) { - y -= height(); - } + int heights = 0; + for (int i=0;iTrackCount();i++) { + int new_heights = heights + track_list_->TrackAt(i)->height() + 1; - if (y < 0) { - track_candidate--; - } - - int compounded_heights = 0; - - while (true) { - int track_height = panel_timeline->GetTrackHeight(track_candidate); - if (olive::CurrentConfig.show_track_lines) track_height++; - if (y < 0) { - track_height = -track_height; + if (y >= heights && y < new_heights) { + return track_list_->TrackAt(i); } - int next_compounded_height = compounded_heights + track_height; - - - if (y >= qMin(next_compounded_height, compounded_heights) && y < qMax(next_compounded_height, compounded_heights)) { - return track_candidate; - } - - compounded_heights = next_compounded_height; - - if (y < 0) { - track_candidate--; - } else { - track_candidate++; - } + heights = new_heights; } + + return nullptr; } -int TimelineView::getScreenPointFromTrack(int track) { +int TimelineView::getScreenPointFromTrack(Track *track) { int point = 0; - - int start = (track < 0) ? -1 : 0; - int interval = (track < 0) ? -1 : 1; - - if (track < 0) track--; - - for (int i=start;i!=track;i+=interval) { - point += panel_timeline->GetTrackHeight(i); - if (olive::CurrentConfig.show_track_lines) point++; - } - - if (bottom_align) { - return height() - point - scroll; - } else { - return point - scroll; + for (int i=0;iTrackCount();i++) { + if (track == track_list_->TrackAt(i)) { + return point; + } + point += track_list_->TrackAt(i)->height() + 1; } + return point - scroll; } -int TimelineView::getClipIndexFromCoords(long frame, int track) { - for (int i=0;iclips.size();i++) { - ClipPtr c = olive::ActiveSequence->clips.at(i); - if (c != nullptr && c->track() == track && frame >= c->timeline_in() && frame < c->timeline_out()) { - return i; - } +Timeline *TimelineView::ParentTimeline() +{ + return timeline_; +} + +Sequence *TimelineView::sequence() +{ + if (track_list_ == nullptr) { + return nullptr; } - return -1; + + return track_list_->GetParent(); } void TimelineView::setScroll(int s) { @@ -3431,5 +3357,5 @@ void TimelineView::setScroll(int s) { } void TimelineView::reveal_media() { - panel_project->reveal_media(rc_reveal_media); + panel_project.first()->reveal_media(rc_reveal_media); } diff --git a/ui/timelineview.h b/ui/timelineview.h index 6cbf22773..3e743b92b 100644 --- a/ui/timelineview.h +++ b/ui/timelineview.h @@ -30,23 +30,25 @@ #include "timeline/sequence.h" #include "timeline/clip.h" +#include "timeline/timelinetools.h" +#include "timeline/timelinefunctions.h" #include "project/footage.h" #include "project/media.h" #include "undo/undo.h" -#include "timelinetools.h" class Timeline; -bool same_sign(int a, int b); -void draw_waveform(ClipPtr clip, const FootageStream *ms, long media_length, QPainter* p, const QRect& clip_rect, int waveform_start, int waveform_limit, double zoom); +void draw_waveform(Clip* clip, const FootageStream *ms, long media_length, QPainter* p, const QRect& clip_rect, int waveform_start, int waveform_limit, double zoom); class TimelineView : public QWidget { Q_OBJECT public: - explicit TimelineView(QWidget *parent = nullptr); + explicit TimelineView(Timeline *parent); + + void SetAlignment(olive::timeline::Alignment alignment); + void SetTrackList(TrackList* tl); QScrollBar* scrollBar; - bool bottom_align; public slots: @@ -70,18 +72,29 @@ protected: private: void init_ghosts(); void update_ghosts(const QPoint& mouse_pos, bool lock_frame); - bool is_track_visible(int track); - int getTrackFromScreenPoint(int y); - int getScreenPointFromTrack(int track); - int getClipIndexFromCoords(long frame, int track); + Track* getTrackFromScreenPoint(int y); + int getScreenPointFromTrack(Track* track); + Timeline* ParentTimeline(); + Sequence* sequence(); + void delete_area_under_ghosts(ComboAction* ca, Sequence *s); + void insert_clips(ComboAction* ca, Sequence *s); + bool current_tool_shows_cursor(); + void draw_transition(QPainter& p, Clip *c, const QRect& clip_rect, QRect& text_rect, int transition_type); + Clip* GetClipAtCursor(); + void VerifyTransitionsAfterCreating(ComboAction* ca, Clip* open, Clip* close, long transition_start, long transition_end); void VerifyTransitionHelper(); - bool track_resizing; - int track_target; + Timeline* timeline_; - QVector pre_clips; - QVector post_clips; + olive::timeline::Alignment alignment_; + TrackList* track_list_; + + bool track_resizing; + Track* track_target; + + QVector pre_clips; + QVector post_clips; Media* rc_reveal_media; @@ -92,7 +105,6 @@ private: int scroll; - SetSelectionsCommand* selection_command; signals: public slots: diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index a6ce74f59..b773de2ec 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -146,7 +146,7 @@ void ViewerWidget::show_context_menu() { connect(&zoom_menu, SIGNAL(triggered(QAction*)), this, SLOT(set_menu_zoom(QAction*))); menu.addMenu(&zoom_menu); - if (!viewer->is_main_sequence()) { + if (viewer->mode() != Viewer::kTimelineMode) { menu.addAction(tr("Close Media"), viewer, SLOT(close_media())); } @@ -338,7 +338,12 @@ void ViewerWidget::move_gizmos(QMouseEvent *event, bool done) { int x_movement = qRound((event->pos().x() - drag_start_x)*multiplier); int y_movement = qRound((event->pos().y() - drag_start_y)*multiplier); - gizmos->gizmo_move(selected_gizmo, x_movement, y_movement, get_timecode(gizmos->parent_clip, gizmos->parent_clip->sequence->playhead), done); + gizmos->gizmo_move(selected_gizmo, + x_movement, + y_movement, + get_timecode(gizmos->parent_clip, + gizmos->parent_clip->track()->sequence()->playhead), + done); gizmo_x_mvmt += x_movement; gizmo_y_mvmt += y_movement; @@ -351,7 +356,7 @@ void ViewerWidget::move_gizmos(QMouseEvent *event, bool done) { void ViewerWidget::mousePressEvent(QMouseEvent* event) { if (waveform) { seek_from_click(event->x()); - } else if (event->buttons() & Qt::MiddleButton || panel_timeline->tool == TIMELINE_TOOL_HAND) { + } else if (event->buttons() & Qt::MiddleButton || olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_HAND) { container->dragScrollPress(event->pos()*container->zoom); } else if (event->buttons() & Qt::LeftButton) { drag_start_x = event->pos().x(); @@ -367,13 +372,13 @@ void ViewerWidget::mousePressEvent(QMouseEvent* event) { void ViewerWidget::mouseMoveEvent(QMouseEvent* event) { unsetCursor(); - if (panel_timeline->tool == TIMELINE_TOOL_HAND) { + if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_HAND) { setCursor(Qt::OpenHandCursor); } if (dragging) { if (waveform) { seek_from_click(event->x()); - } else if (event->buttons() & Qt::MiddleButton || panel_timeline->tool == TIMELINE_TOOL_HAND) { + } else if (event->buttons() & Qt::MiddleButton || olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_HAND) { container->dragScrollMove(event->pos()*container->zoom); } else if (event->buttons() & Qt::LeftButton) { if (gizmos == nullptr) { @@ -397,7 +402,7 @@ void ViewerWidget::mouseReleaseEvent(QMouseEvent *event) { if (dragging && gizmos != nullptr && event->button() == Qt::LeftButton - && panel_timeline->tool != TIMELINE_TOOL_HAND) { + && olive::timeline::current_tool != olive::timeline::TIMELINE_TOOL_HAND) { move_gizmos(event, true); } dragging = false; @@ -431,7 +436,7 @@ void ViewerWidget::draw_waveform_func() { wr.setX(wr.x() - waveform_scroll); p.setPen(Qt::green); - draw_waveform(waveform_clip, waveform_ms, waveform_clip->timeline_out(), &p, wr, waveform_scroll, width()+waveform_scroll, waveform_zoom); + draw_waveform(waveform_clip.get(), waveform_ms, waveform_clip->timeline_out(), &p, wr, waveform_scroll, width()+waveform_scroll, waveform_zoom); p.setPen(Qt::red); int playhead_x = getScreenPointFromFrame(waveform_zoom, viewer->seq->playhead) - waveform_scroll; p.drawLine(playhead_x, 0, playhead_x, height()); @@ -452,16 +457,16 @@ void ViewerWidget::draw_title_safe_area() { matrix.ortho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f); // adjust the horizontal center cross by the aspect ratio to appear "square" - if (olive::CurrentConfig.use_custom_title_safe_ratio && olive::CurrentConfig.custom_title_safe_ratio > 0) { - if (ar > olive::CurrentConfig.custom_title_safe_ratio) { - matrix.translate(((ar - olive::CurrentConfig.custom_title_safe_ratio) / 2.0) / ar, 0.0f); - matrix.scale(olive::CurrentConfig.custom_title_safe_ratio / ar, 1.0f); + if (olive::config.use_custom_title_safe_ratio && olive::config.custom_title_safe_ratio > 0) { + if (ar > olive::config.custom_title_safe_ratio) { + matrix.translate(((ar - olive::config.custom_title_safe_ratio) / 2.0) / ar, 0.0f); + matrix.scale(olive::config.custom_title_safe_ratio / ar, 1.0f); } else { - matrix.translate(0.0f, (((olive::CurrentConfig.custom_title_safe_ratio - ar) / 2.0) / olive::CurrentConfig.custom_title_safe_ratio)); - matrix.scale(1.0f, ar / olive::CurrentConfig.custom_title_safe_ratio); + matrix.translate(0.0f, (((olive::config.custom_title_safe_ratio - ar) / 2.0) / olive::config.custom_title_safe_ratio)); + matrix.scale(1.0f, ar / olive::config.custom_title_safe_ratio); } - horizontal_cross_size *= ar/olive::CurrentConfig.custom_title_safe_ratio; + horizontal_cross_size *= ar/olive::config.custom_title_safe_ratio; } float adjusted_cross_x1 = 0.5f - horizontal_cross_size; @@ -745,7 +750,7 @@ void ViewerWidget::paintGL() { f->glBindTexture(GL_TEXTURE_2D, 0); // draw title/action safe area - if (olive::CurrentConfig.show_title_safe_area) { + if (olive::config.show_title_safe_area) { draw_title_safe_area(); } diff --git a/undo/undo.cpp b/undo/undo.cpp index e562f7e77..dd603d652 100644 --- a/undo/undo.cpp +++ b/undo/undo.cpp @@ -38,11 +38,11 @@ #include "ui/labelslider.h" #include "ui/viewerwidget.h" #include "project/media.h" -#include "project/clipboard.h" +#include "global/clipboard.h" #include "project/previewgenerator.h" #include "ui/mainwindow.h" -MoveClipAction::MoveClipAction(Clip *c, long iin, long iout, long iclip_in, int itrack, bool irelative) : +MoveClipAction::MoveClipAction(ClipPtr c, long iin, long iout, long iclip_in, Track* itrack, bool irelative) : clip(c), old_in(c->timeline_in()), old_out(c->timeline_out()), @@ -63,13 +63,12 @@ void MoveClipAction::doUndo() { clip->set_timeline_in (clip->timeline_in() - new_in); clip->set_timeline_out (clip->timeline_out() - new_out); clip->set_clip_in (clip->clip_in() - new_clip_in); - clip->set_track (clip->track() - new_track); } else { clip->set_timeline_in(old_in); clip->set_timeline_out(old_out); clip->set_clip_in(old_clip_in); - clip->set_track(old_track); } + clip->set_track(old_track); done = false; } @@ -79,13 +78,12 @@ void MoveClipAction::doRedo() { clip->set_timeline_in(clip->timeline_in() + new_in); clip->set_timeline_out(clip->timeline_out() + new_out); clip->set_clip_in(clip->clip_in() + new_clip_in); - clip->set_track(clip->track() + new_track); } else { clip->set_timeline_in(new_in); clip->set_timeline_out(new_out); clip->set_clip_in(new_clip_in); - clip->set_track(new_track); } + new_track->AddClip(clip); done = true; } } @@ -98,15 +96,13 @@ DeleteClipAction::DeleteClipAction(Clip *clip) } void DeleteClipAction::doUndo() { - // restore ref to clip - seq->clips[index] = ref; + // restore clip to this track + clip_->track()->AddClip(clip_); // restore links to this clip - for (int i=linkClipIndex.size()-1;i>=0;i--) { - seq->clips.at(linkClipIndex.at(i))->linked.insert(linkLinkIndex.at(i), index); + for (int i=0;itrack()->RemoveClip(clip_.get()); // delete link to this clip - QVector clips = clip_->track()-> - linkClipIndex.clear(); - linkLinkIndex.clear(); - for (int i=0;iclips.size();i++) { - ClipPtr c = seq->clips.at(i); - if (c != nullptr) { - for (int j=0;jlinked.size();j++) { - if (c->linked.at(j) == index) { - linkClipIndex.append(i); - linkLinkIndex.append(j); - c->linked.removeAt(j); - } + QVector clips = clip_->track()->sequence()->GetAllClips(); + for (int i=0;ilinked.size();j++) { + if (c->linked.at(j) == clip_.get()) { + c->linked.removeAt(j); + clips_linked_to_this_one_.append(c); + break; } } } } -ChangeSequenceAction::ChangeSequenceAction(SequencePtr s) { - new_sequence = s; -} - -void ChangeSequenceAction::doUndo() { - olive::Global->set_sequence(old_sequence); -} - -void ChangeSequenceAction::doRedo() { - old_sequence = olive::ActiveSequence; - olive::Global->set_sequence(new_sequence); -} - SetTimelineInOutCommand::SetTimelineInOutCommand(Sequence* s, bool enabled, long in, long out) { seq = s; new_enabled = enabled; @@ -162,7 +142,7 @@ void SetTimelineInOutCommand::doUndo() { // footage viewer functions if (seq->wrapper_sequence) { - Footage* m = seq->clips.at(0)->media()->to_footage(); + Footage* m = seq->GetAllClips().first()->media()->to_footage(); m->using_inout = old_enabled; m->in = old_in; m->out = old_out; @@ -180,7 +160,7 @@ void SetTimelineInOutCommand::doRedo() { // footage viewer functions if (seq->wrapper_sequence) { - Footage* m = seq->clips.at(0)->media()->to_footage(); + Footage* m = seq->GetAllClips().first()->media()->to_footage(); m->using_inout = new_enabled; m->in = new_in; m->out = new_out; @@ -351,10 +331,8 @@ void DeleteMediaCommand::doRedo() { olive::project_model.removeChild(parent, item.get()); } -AddClipCommand::AddClipCommand(Sequence *s, QVector& add) : - link_offset_(0), - seq(s), - clips(add), +AddClipCommand::AddClipCommand(const QVector &add) : + clips_(add), done_(false) { doRedo(); @@ -365,26 +343,21 @@ void AddClipCommand::doUndo() { panel_graph_editor->set_row(nullptr); panel_effect_controls->Clear(true); - for (int i=0;iclips.last(); + for (int i=0;ilinked.size();j++) { - c->linked[j] -= link_offset_; - } + + c->track()->RemoveClip(c.get()); // deselect the area occupied by this clip - panel_timeline->deselect_area(c->timeline_in(), c->timeline_out(), c->track()); + c->track()->DeselectArea(c->timeline_in(), c->timeline_out()); // if the clip is open, close it if (c->IsOpen()) { c->Close(true); } } - - // remove it from the sequence - seq->clips.removeLast(); } done_ = false; @@ -392,54 +365,52 @@ void AddClipCommand::doUndo() { void AddClipCommand::doRedo() { if (!done_) { - link_offset_ = seq->clips.size(); - for (int i=0;ilinked.size();j++) { - original->linked[j] += link_offset_; - } - - } - - seq->clips.append(original); + original->track()->AddClip(original); + } } done_ = true; } } -LinkCommand::LinkCommand() { - link = true; +LinkCommand::LinkCommand(const QVector& clips, bool link) : + clips_(clips), + link_(link) +{ } void LinkCommand::doUndo() { - for (int i=0;iclips.at(clips.at(i)); - if (link) { + for (int i=0;ilinked.clear(); } else { - c->linked = old_links.at(i); + c->linked = old_links_.at(i); } } } void LinkCommand::doRedo() { - old_links.clear(); - for (int i=0;iclips.at(clips.at(i)); - if (link) { - for (int j=0;jlinked.append(clips.at(j)); + c->linked.append(clips_.at(j)); } } + } else { - old_links.append(c->linked); + + old_links_.append(c->linked); c->linked.clear(); + } } } @@ -472,12 +443,14 @@ ReplaceMediaCommand::ReplaceMediaCommand(MediaPtr i, QString s) { void ReplaceMediaCommand::replace(QString& filename) { // close any clips currently using this media - QVector all_sequences = panel_project->list_all_project_sequences(); + QVector all_sequences = olive::project_model.GetAllSequences(); for (int i=0;ito_sequence().get(); - for (int j=0;jclips.size();j++) { - ClipPtr c = s->clips.at(j); - if (c != nullptr && c->media() == item.get() && c->IsOpen()) { + + QVector sequence_clips = all_sequences.at(i)->to_sequence()->GetAllClips(); + + for (int j=0;jmedia() == item.get() && c->IsOpen()) { c->Close(true); c->replaced = true; } @@ -487,7 +460,7 @@ void ReplaceMediaCommand::replace(QString& filename) { // replace media QStringList files; files.append(filename); - panel_project->process_file_list(files, false, item, nullptr); + olive::project_model.process_file_list(files, false, item, nullptr); PreviewGenerator::AnalyzeMedia(item.get()); } @@ -513,7 +486,7 @@ void ReplaceClipMediaCommand::replace(bool undo) { } for (int i=0;iIsOpen()) { c->Close(true); } @@ -806,20 +779,25 @@ void SetBool::doRedo() { *boolean = new_setting; } -SetSelectionsCommand::SetSelectionsCommand(Sequence *s) { - seq = s; - done = true; +SetSelectionsCommand::SetSelectionsCommand(Sequence *s, + const QVector &old_data, + const QVector &new_data) : + old_data_(old_data), + new_data_(new_data), + done_(true) +{ + } void SetSelectionsCommand::doUndo() { - seq->selections = old_data; - done = false; + seq_->SetSelections(old_data_); + done_ = false; } void SetSelectionsCommand::doRedo() { - if (!done) { - seq->selections = new_data; - done = true; + if (!done_) { + seq_->SetSelections(new_data_); + done_ = true; } } @@ -858,15 +836,12 @@ void EditSequenceCommand::update() { // Update sequence's tooltip item->update_tooltip(); - for (int i=0;iclips.size();i++) { - if (seq->clips.at(i) != nullptr) { - seq->clips.at(i)->refresh(); + QVector all_clips = seq->GetAllClips(); + for (int i=0;irefresh(); } } - - if (olive::ActiveSequence == seq) { - olive::Global->set_sequence(seq); - } } SetInt::SetInt(int* pointer, int new_value) { @@ -904,7 +879,11 @@ void CloseAllClipsCommand::doUndo() { } void CloseAllClipsCommand::doRedo() { - olive::ActiveSequence->Close(); + QVector sequences = olive::project_model.GetAllSequences(); + + for (int i=0;ito_sequence()->Close(); + } } UpdateFootageTooltip::UpdateFootageTooltip(Media *i) { @@ -938,13 +917,13 @@ RemoveClipsFromClipboard::RemoveClipsFromClipboard(int index) { RemoveClipsFromClipboard::~RemoveClipsFromClipboard() {} void RemoveClipsFromClipboard::doUndo() { - clipboard.insert(pos, clip); + olive::clipboard.Insert(pos, clip); done = false; } void RemoveClipsFromClipboard::doRedo() { - clip = std::static_pointer_cast(clipboard.at(pos)); - clipboard.removeAt(pos); + clip = std::static_pointer_cast(olive::clipboard.Get(pos)); + olive::clipboard.RemoveAt(pos); done = true; } @@ -985,7 +964,7 @@ void ReloadEffectsCommand::doRedo() { panel_effect_controls->Reload(); } -RippleAction::RippleAction(Sequence *is, long ipoint, long ilength, const QVector &iignore) : +RippleAction::RippleAction(Sequence *is, long ipoint, long ilength, const QVector &iignore) : s(is), point(ipoint), length(ilength), @@ -1000,13 +979,21 @@ void RippleAction::doUndo() { void RippleAction::doRedo() { ca = new ComboAction(); - for (int i=0;iclips.size();i++) { - if (!ignore.contains(i)) { - ClipPtr c = s->clips.at(i); - if (c != nullptr) { - if (c->timeline_in() >= point) { - c->move(ca, length, length, 0, 0, true, true); - } + + QVector all_clips = s->GetAllClips(); + + for (int i=0;itimeline_in() >= point) { + s->MoveClip(c, + ca, + length, + length, + 0, + c->track(), + true, + true); } } } @@ -1092,8 +1079,9 @@ void SetIsKeyframing::doRedo() { row->SetKeyframingInternal(b); } -RefreshClips::RefreshClips(Media *m) { - media = m; +RefreshClips::RefreshClips(Media *m) : + media(m) +{ } void RefreshClips::doUndo() { @@ -1102,12 +1090,14 @@ void RefreshClips::doUndo() { void RefreshClips::doRedo() { // close any clips currently using this media - QVector all_sequences = panel_project->list_all_project_sequences(); + QVector all_sequences = olive::project_model.GetAllSequences(); for (int i=0;ito_sequence().get(); - for (int j=0;jclips.size();j++) { - Clip* c = s->clips.at(j).get(); - if (c != nullptr && c->media() == media) { + + QVector sequence_clips = all_sequences.at(i)->to_sequence().get()->GetAllClips(); + + for (int j=0;jmedia() == media || media == nullptr) { c->replaced = true; c->refresh(); } diff --git a/undo/undo.h b/undo/undo.h index cb58f304a..21a50113e 100644 --- a/undo/undo.h +++ b/undo/undo.h @@ -77,21 +77,21 @@ private: class MoveClipAction : public OliveAction { public: - MoveClipAction(Clip* c, long iin, long iout, long iclip_in, int itrack, bool irelative); + MoveClipAction(ClipPtr c, long iin, long iout, long iclip_in, Track* itrack, bool irelative); virtual void doUndo() override; virtual void doRedo() override; private: - Clip* clip; + ClipPtr clip; long old_in; long old_out; long old_clip_in; - int old_track; + Track* old_track; long new_in; long new_out; long new_clip_in; - int new_track; + Track* new_track; bool relative; @@ -100,14 +100,14 @@ private: class RippleAction : public OliveAction { public: - RippleAction(Sequence* is, long ipoint, long ilength, const QVector& iignore); + RippleAction(Sequence* is, long ipoint, long ilength, const QVector &iignore); virtual void doUndo() override; virtual void doRedo() override; private: Sequence* s; long point; long length; - QVector ignore; + QVector ignore; ComboAction* ca; }; @@ -118,20 +118,9 @@ public: virtual void doRedo() override; private: ClipPtr clip_; - QVector clips_linked_to_this_one_; }; -class ChangeSequenceAction : public OliveAction { -public: - ChangeSequenceAction(SequencePtr s); - virtual void doUndo() override; - virtual void doRedo() override; -private: - SequencePtr old_sequence; - SequencePtr new_sequence; -}; - class AddEffectCommand : public OliveAction { public: AddEffectCommand(Clip* c, EffectPtr e, const EffectMeta* m, int insert_pos = -1); @@ -223,26 +212,24 @@ private: class AddClipCommand : public OliveAction { public: - AddClipCommand(Sequence* s, QVector& add); + AddClipCommand(const QVector& add); virtual void doUndo() override; virtual void doRedo() override; private: - Sequence* seq; - QVector clips; - int link_offset_; + Track* track_; + QVector clips_; bool done_; }; class LinkCommand : public OliveAction { public: - LinkCommand(); + LinkCommand(const QVector &clips, bool link); virtual void doUndo() override; virtual void doRedo() override; - Sequence* s; - QVector clips; - bool link; private: - QVector< QVector > old_links; + QVector clips_; + bool link_; + QVector< QVector > old_links_; }; class CheckboxCommand : public OliveAction { @@ -274,7 +261,7 @@ public: ReplaceClipMediaCommand(Media *, Media *, bool); virtual void doUndo() override; virtual void doRedo() override; - QVector clips; + QVector clips; private: Media* old_media; Media* new_media; @@ -423,14 +410,14 @@ private: class SetSelectionsCommand : public OliveAction { public: - SetSelectionsCommand(Sequence* s); + SetSelectionsCommand(Sequence* s, const QVector& old_data, const QVector& new_data); virtual void doUndo() override; virtual void doRedo() override; - QVector old_data; - QVector new_data; private: - Sequence* seq; - bool done; + QVector old_data_; + QVector new_data_; + Sequence* seq_; + bool done_; }; class EditSequenceCommand : public OliveAction { diff --git a/undo/undostack.cpp b/undo/undostack.cpp index 5eb605390..7fa229777 100644 --- a/undo/undostack.cpp +++ b/undo/undostack.cpp @@ -20,4 +20,4 @@ #include "undostack.h" -QUndoStack olive::UndoStack; +QUndoStack olive::undo_stack; diff --git a/undo/undostack.h b/undo/undostack.h index f876dd8b8..35bc92584 100644 --- a/undo/undostack.h +++ b/undo/undostack.h @@ -27,7 +27,7 @@ namespace olive { /** * @brief Global undo stack object */ -extern QUndoStack UndoStack; +extern QUndoStack undo_stack; } #endif // UNDOSTACK_H