diff --git a/dialogs/autocutsilencedialog.cpp b/dialogs/autocutsilencedialog.cpp
new file mode 100644
index 000000000..b1d801b99
--- /dev/null
+++ b/dialogs/autocutsilencedialog.cpp
@@ -0,0 +1,222 @@
+/***
+
+ 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 "autocutsilencedialog.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#include "timeline/sequence.h"
+#include "rendering/renderfunctions.h"
+#include "panels/panels.h"
+#include "panels/timeline.h"
+
+AutoCutSilenceDialog::AutoCutSilenceDialog(QWidget *parent, QVector clips) :
+ QDialog(parent),
+ clips_(clips)
+{
+ setWindowTitle(tr("Cut Silence"));
+
+ QVBoxLayout* main_layout = new QVBoxLayout(this);
+ QGridLayout* grid = new QGridLayout();
+ grid->setSpacing(6);
+
+ grid->addWidget(new QLabel(tr("Attack Threshold:"), this), 0, 0);
+ attack_threshold = new LabelSlider(this);
+ attack_threshold->SetDecimalPlaces(0);
+ grid->addWidget(attack_threshold, 0, 1);
+
+ grid->addWidget(new QLabel(tr("Attack Time:"), this), 1, 0);
+ attack_time = new LabelSlider(this);
+ attack_time->SetDecimalPlaces(0);
+ grid->addWidget(attack_time, 1, 1);
+
+ grid->addWidget(new QLabel(tr("Release Threshold:"), this), 2, 0);
+ release_threshold = new LabelSlider(this);
+ release_threshold->SetDecimalPlaces(0);
+ grid->addWidget(release_threshold, 2, 1);
+
+ grid->addWidget(new QLabel(tr("Release Time:"), this), 3, 0);
+ release_time = new LabelSlider(this);
+ release_time->SetDecimalPlaces(0);
+ grid->addWidget(release_time, 3, 1);
+
+ main_layout->addLayout(grid);
+
+ QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
+ buttonBox->setCenterButtons(true);
+ main_layout->addWidget(buttonBox);
+ connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+ connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+
+}
+
+int AutoCutSilenceDialog::exec()
+{
+ default_attack_threshold = 5;
+ current_attack_threshold = 5;
+ default_attack_time = 2;
+ current_attack_time = 2;
+ default_release_threshold = 2;
+ current_release_threshold = 2;
+ default_release_time = 5;
+ current_release_time = 5;
+
+ attack_threshold->SetMinimum(1);
+ attack_threshold->setEnabled(true);
+ attack_threshold->SetDefault(default_attack_threshold);
+ attack_threshold->SetValue(current_attack_threshold);
+
+ attack_time->SetMinimum(1);
+ attack_time->setEnabled(true);
+ attack_time->SetDefault(default_attack_time);
+ attack_time->SetValue(current_attack_time);
+
+ release_threshold->SetMinimum(1);
+ release_threshold->setEnabled(true);
+ release_threshold->SetDefault(default_release_threshold);
+ release_threshold->SetValue(current_release_threshold);
+
+ release_time->SetMinimum(1);
+ release_time->setEnabled(true);
+ release_time->SetDefault(default_release_time);
+ release_time->SetValue(current_release_time);
+
+ return QDialog::exec();
+}
+
+void AutoCutSilenceDialog::accept() {
+
+ current_attack_threshold = attack_threshold->value();
+ current_attack_time = attack_time->value();
+ current_release_threshold = release_threshold->value();
+ current_release_time = release_time->value();
+
+ cut_silence();
+
+ update_ui(true);
+ QDialog::accept();
+}
+
+void AutoCutSilenceDialog::cut_silence() {
+ // Loop over clips provided to this dialog
+ for (int j=0;jtrack() >= 0
+ && 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();
+ const FootageStream* ms = clip->media_stream();
+
+ long media_length = clip->media_length();
+ int preview_size = ms->audio_preview.length();
+ float chunk_size = (float)preview_size/media_length; // how many audio samples to read for each fotogram
+
+ int sample_size = qMax(current_attack_time, current_release_time)+1;
+
+ bool attack = false; // status flags
+ bool release = false;
+
+ QVector vols;
+ vols.resize(sample_size);
+ vols.fill(0);
+
+ // loop through the entire sequence
+ for (long i=clip_start;iaudio_preview.at(k)))));
+ }
+ vols[circular_index] = tmp;
+
+ //for debug:
+ //qInfo() << "i:" << i <<" - "<< i/30 <<":"<< i%30 << " - volume:" << vols[circular_index] <<"\n";
+
+ int overthreshold = 0;
+ int cut_idx = 0; //how much to cut (backwards)
+
+ // if current volume value is above threshold
+ if (vols[circular_index] >= current_attack_threshold && !attack){ // if we get one sample over the threshold
+ for(int k=0; k current_attack_threshold){
+ overthreshold++;
+ cut_idx = k+1;
+ }
+ }
+ // if we reached threshold over the set tolerance
+ if(overthreshold >= current_attack_time){
+ split_positions.append(i-cut_idx);
+ attack = true;
+ release = false;
+ //qInfo() << "\n\n Current vol: "<= current_release_time){ // must be <= sample_size
+ attack = false;
+ release = true;
+ split_positions.append(i);
+ //qInfo() << "\n\n Current vol: "<clips.size();i++) {
+ if (olive::ActiveSequence->clips.at(i).get() == clip) {
+ clip_index = i;
+ break;
+ }
+ }
+
+ Q_ASSERT(clip_index > -1);
+
+ panel_timeline->split_clip_at_positions(ca, clip_index, split_positions);
+ olive::UndoStack.push(ca);
+ }
+
+
+ }
+}
diff --git a/dialogs/autocutsilencedialog.h b/dialogs/autocutsilencedialog.h
new file mode 100644
index 000000000..32c572e16
--- /dev/null
+++ b/dialogs/autocutsilencedialog.h
@@ -0,0 +1,59 @@
+/***
+
+ 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 SILENCEDIALOG_H
+#define SILENCEDIALOG_H
+
+#include
+#include
+
+#include "timeline/clip.h"
+#include "ui/labelslider.h"
+
+class AutoCutSilenceDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ AutoCutSilenceDialog(QWidget* parent, QVector clips);
+public slots:
+ virtual int exec() override;
+private slots:
+ virtual void accept() override;
+private:
+ void cut_silence();
+
+ QVector clips_;
+
+ LabelSlider* attack_threshold;
+ LabelSlider* release_threshold;
+ LabelSlider* attack_time;
+ LabelSlider* release_time;
+
+ int default_attack_threshold;
+ int current_attack_threshold;
+ int default_release_threshold;
+ int current_release_threshold;
+ int default_attack_time;
+ int current_attack_time;
+ int default_release_time;
+ int current_release_time;
+};
+
+#endif // SILENCEDIALOG_H
diff --git a/dialogs/preferencesdialog.cpp b/dialogs/preferencesdialog.cpp
index a9b8d2d6d..74d262b45 100644
--- a/dialogs/preferencesdialog.cpp
+++ b/dialogs/preferencesdialog.cpp
@@ -20,13 +20,6 @@
#include "preferencesdialog.h"
-#include "global/global.h"
-#include "global/config.h"
-#include "global/path.h"
-#include "rendering/audio.h"
-#include "panels/panels.h"
-#include "ui/mainwindow.h"
-
#include
#include
#include
@@ -51,6 +44,14 @@
#include
#include
+#include "global/global.h"
+#include "global/config.h"
+#include "global/path.h"
+#include "rendering/audio.h"
+#include "panels/panels.h"
+#include "ui/columnedgridlayout.h"
+#include "ui/mainwindow.h"
+
KeySequenceEditor::KeySequenceEditor(QWidget* parent, QAction* a)
: QKeySequenceEdit(parent), action(a) {
setKeySequence(action->shortcut());
@@ -142,6 +143,15 @@ void PreferencesDialog::delete_previews(char type) {
}
}
+void PreferencesDialog::AddBoolPair(QCheckBox *ui, bool *value, bool restart_required)
+{
+ bool_ui.append(ui);
+ bool_value.append(value);
+ bool_restart_required.append(restart_required);
+
+ ui->setChecked(*value);
+}
+
void PreferencesDialog::setup_kbd_shortcuts(QMenuBar* menubar) {
QList menus = menubar->actions();
@@ -186,14 +196,20 @@ void PreferencesDialog::accept() {
reload_effects = true;
}
+ bool bool_requires_restart = false;
+ for (int i=0;iisChecked() != *bool_value.at(i)) {
+ bool_requires_restart = true;
+ break;
+ }
+ }
+
// Check if any settings will require a restart of Olive
- if (olive::CurrentConfig.use_software_fallback != use_software_fallbacks_checkbox->isChecked()
+ 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()
-#ifdef Q_OS_WIN32
- || olive::CurrentConfig.use_native_menu_styling != native_menus->isChecked()
-#endif
|| olive::CurrentConfig.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
@@ -241,22 +257,19 @@ void PreferencesDialog::accept() {
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::CurrentConfig.add_default_effects_to_clips = add_default_effects_to_clips->isChecked();
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::CurrentConfig.effect_textbox_lines = effect_textbox_lines_field->value();
- olive::CurrentConfig.use_software_fallback = use_software_fallbacks_checkbox->isChecked();
olive::CurrentConfig.language_file = language_combobox->currentData().toString();
- olive::CurrentConfig.style = static_cast(ui_style->currentData().toInt());
-#ifdef Q_OS_WIN
- olive::CurrentConfig.use_native_menu_styling = native_menus->isChecked();
-#endif
+ for (int i=0;iisChecked();
+ }
- olive::CurrentConfig.auto_seek_to_beginning = auto_seek_to_beginning->isChecked();
+ olive::CurrentConfig.style = static_cast(ui_style->currentData().toInt());
// Check if the thumbnail or waveform icon
if (olive::CurrentConfig.thumbnail_resolution != thumbnail_res_spinbox->value()
@@ -539,9 +552,8 @@ void PreferencesDialog::setup_ui() {
row++;
// General -> Use Software Fallbacks When Possible
- use_software_fallbacks_checkbox = new QCheckBox(general_tab);
- use_software_fallbacks_checkbox->setText(tr("Use Software Fallbacks When Possible"));
- use_software_fallbacks_checkbox->setChecked(olive::CurrentConfig.use_software_fallback);
+ QCheckBox* use_software_fallbacks_checkbox = new QCheckBox(tr("Use Software Fallbacks When Possible"));
+ AddBoolPair(use_software_fallbacks_checkbox, &olive::CurrentConfig.use_software_fallback, true);
general_layout->addWidget(use_software_fallbacks_checkbox, row, 0, 1, 4);
row++;
@@ -556,15 +568,72 @@ void PreferencesDialog::setup_ui() {
QWidget* behavior_tab = new QWidget(this);
tabWidget->addTab(behavior_tab, tr("Behavior"));
- QVBoxLayout* behavior_tab_layout = new QVBoxLayout(behavior_tab);
+ ColumnedGridLayout* behavior_tab_layout = new ColumnedGridLayout(behavior_tab, 2);
- add_default_effects_to_clips = new QCheckBox(tr("Add Default Effects to New Clips"));
- add_default_effects_to_clips->setChecked(olive::CurrentConfig.add_default_effects_to_clips);
- behavior_tab_layout->addWidget(add_default_effects_to_clips);
+ 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);
+ behavior_tab_layout->Add(add_default_effects_to_clips);
- auto_seek_to_beginning = new QCheckBox(tr("Automatically Seek to the Beginning When Playing at the End of a Sequence"));
- auto_seek_to_beginning->setChecked(olive::CurrentConfig.auto_seek_to_beginning);
- behavior_tab_layout->addWidget(auto_seek_to_beginning);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ behavior_tab_layout->Add(set_name_and_marker);
// Appearance
QWidget* appearance_tab = new QWidget(this);
@@ -590,8 +659,8 @@ void PreferencesDialog::setup_ui() {
#ifdef Q_OS_WIN
// Native menu styling is only available on Windows. Environments like Ubuntu and Mac use the native menu system by
// default
- native_menus = new QCheckBox(tr("Use Native Menu Styling"));
- native_menus->setChecked(olive::CurrentConfig.use_native_menu_styling);
+ QCheckBox* native_menus = new QCheckBox(tr("Use Native Menu Styling"));
+ AddBoolPair(native_menus, &olive::CurrentConfig.use_native_menu_styling);
appearance_layout->addWidget(native_menus, row, 0, 1, 3);
row++;
diff --git a/dialogs/preferencesdialog.h b/dialogs/preferencesdialog.h
index fa87c457b..38efcdf7e 100644
--- a/dialogs/preferencesdialog.h
+++ b/dialogs/preferencesdialog.h
@@ -208,11 +208,6 @@ private:
*/
QSpinBox* effect_textbox_lines_field;
- /**
- * @brief UI widget for enabling/disabling software fallbacks
- */
- QCheckBox* use_software_fallbacks_checkbox;
-
/**
* @brief UI widget for selecting the output audio device
*/
@@ -243,26 +238,10 @@ private:
*/
QSpinBox* waveform_res_spinbox;
- /**
- * @brief UI widget for enabling/disabling default effects
- */
- QCheckBox* add_default_effects_to_clips;
-
- /**
- * @brief UI widget for enabling/disabling Config::auto_seek_to_beginning
- */
- QCheckBox* auto_seek_to_beginning;
-
/**
* @brief UI widget for selecting the current UI style
*/
QComboBox* ui_style;
-#ifdef Q_OS_WIN
- /**
- * @brief UI widget for forcing native menu styling on Windows
- */
- QCheckBox* native_menus;
-#endif
/**
* @brief List of keyboard shortcut actions that can be triggered (links with key_shortcut_items and
@@ -281,6 +260,45 @@ private:
* key_shortcut_actions and key_shortcut_fields)
*/
QVector key_shortcut_fields;
+
+ /**
+ * @brief Add an automated QCheckBox+boolean value pair
+ *
+ * Many preferences are simple true/false (or on/off) options. Rather than adding a QCheckBox for each one and
+ * manually setting its checked value to the configuration setting (and vice versa when saving), this convenience
+ * function will add it to an automated set of checkboxes, automatically setting the checked state to the current
+ * setting, and then saving the new checked state back to the setting when the user accepts the changes (clicks OK).
+ *
+ * @param ui
+ *
+ * A valid QCheckBox item. This function does not take ownership of the QWidget or place it in a layout anywhere.
+ *
+ * @param value
+ *
+ * A pointer to the Boolean value this QCheckBox should be shared with. The QCheckBox widget's checked state will be
+ * set to the value of this pointer.
+ *
+ * @param restart_required
+ *
+ * Defaults to FALSE, set this to TRUE if changing this setting should prompt the user for a restart of Olive before
+ * the setting change takes effect.
+ */
+ void AddBoolPair(QCheckBox* ui, bool* value, bool restart_required = false);
+
+ /**
+ * @brief Internal array managed by AddBoolPair(). Do not access this directly.
+ */
+ QVector bool_ui;
+
+ /**
+ * @brief Internal array managed by AddBoolPair(). Do not access this directly.
+ */
+ QVector bool_value;
+
+ /**
+ * @brief Internal array managed by AddBoolPair(). Do not access this directly.
+ */
+ QVector bool_restart_required;
};
/**
diff --git a/global/config.cpp b/global/config.cpp
index 667b178a9..cc2e2b441 100644
--- a/global/config.cpp
+++ b/global/config.cpp
@@ -57,7 +57,7 @@ Config::Config()
hover_focus(false),
project_view_type(olive::PROJECT_VIEW_TREE),
set_name_with_marker(true),
- show_project_toolbar(false),
+ show_project_toolbar(true),
previous_queue_size(3),
previous_queue_type(olive::FRAME_QUEUE_TYPE_FRAMES),
upcoming_queue_size(0.5),
diff --git a/global/global.cpp b/global/global.cpp
index 8980721d9..048a57e9b 100644
--- a/global/global.cpp
+++ b/global/global.cpp
@@ -39,6 +39,7 @@
#include "dialogs/speeddialog.h"
#include "dialogs/actionsearch.h"
#include "dialogs/loaddialog.h"
+#include "dialogs/autocutsilencedialog.h"
#include "project/loadthread.h"
#include "timeline/sequence.h"
#include "ui/mediaiconservice.h"
@@ -301,12 +302,7 @@ bool OliveGlobal::can_close_project() {
}
void OliveGlobal::open_export_dialog() {
- if (olive::ActiveSequence == nullptr) {
- QMessageBox::information(olive::MainWindow,
- tr("No active sequence"),
- tr("Please open the sequence you wish to export."),
- QMessageBox::Ok);
- } else {
+ if (CheckForActiveSequence()) {
ExportDialog e(olive::MainWindow);
e.exec();
}
@@ -377,6 +373,22 @@ void OliveGlobal::OpenProjectWorker(const QString& fn, bool autorecovery) {
olive::UndoStack.clear();
}
+bool OliveGlobal::CheckForActiveSequence(bool show_msg)
+{
+ if (olive::ActiveSequence == nullptr) {
+
+ if (show_msg) {
+ QMessageBox::information(olive::MainWindow,
+ tr("No active sequence"),
+ tr("Please open the sequence to perform this action."),
+ QMessageBox::Ok);
+ }
+
+ return false;
+ }
+ return true;
+}
+
void OliveGlobal::undo() {
// workaround to prevent crash (and also users should never need to do this)
if (!panel_timeline->importing) {
@@ -426,6 +438,24 @@ void OliveGlobal::open_speed_dialog() {
}
}
+void OliveGlobal::open_autocut_silence_dialog() {
+ if (CheckForActiveSequence()) {
+
+ QVector selected_clips = olive::ActiveSequence->SelectedClips();
+
+ if (selected_clips.isEmpty()) {
+ QMessageBox::critical(olive::MainWindow,
+ tr("No clips selected"),
+ tr("Select the clips you wish to auto-cut"),
+ QMessageBox::Ok);
+ } else {
+ AutoCutSilenceDialog s(olive::MainWindow, selected_clips);
+ s.exec();
+ }
+
+ }
+}
+
void OliveGlobal::clear_undo_stack() {
olive::UndoStack.clear();
}
diff --git a/global/global.h b/global/global.h
index 17c88f535..ac05b21bf 100644
--- a/global/global.h
+++ b/global/global.h
@@ -275,6 +275,11 @@ public slots:
*/
void open_speed_dialog();
+ /**
+ * @brief Open the auto-cut silence dialog.
+ */
+ void open_autocut_silence_dialog();
+
/**
* @brief Open the Action Search overlay.
*/
@@ -340,6 +345,18 @@ private:
*/
void OpenProjectWorker(const 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
*
diff --git a/olive.pro b/olive.pro
index 2b4b15559..9adf6c8b9 100644
--- a/olive.pro
+++ b/olive.pro
@@ -174,7 +174,9 @@ SOURCES += \
effects/internal/richtexteffect.cpp \
ui/blur.cpp \
ui/menu.cpp \
- timeline/mediaimportdata.cpp
+ timeline/mediaimportdata.cpp \
+ dialogs/autocutsilencedialog.cpp \
+ ui/columnedgridlayout.cpp
HEADERS += \
ui/mainwindow.h \
@@ -302,7 +304,9 @@ HEADERS += \
effects/internal/richtexteffect.h \
ui/blur.h \
ui/menu.h \
- timeline/mediaimportdata.h
+ timeline/mediaimportdata.h \
+ dialogs/autocutsilencedialog.h \
+ ui/columnedgridlayout.h
FORMS +=
diff --git a/panels/timeline.cpp b/panels/timeline.cpp
index 75caf3148..977de2aa8 100644
--- a/panels/timeline.cpp
+++ b/panels/timeline.cpp
@@ -138,6 +138,53 @@ void Timeline::Retranslate() {
UpdateTitle();
}
+void Timeline::split_clip_at_positions(ComboAction* ca, int clip_index, QVector positions) {
+
+ QVector pre_splits;
+
+ // Add the clip and each of its links to the pre_splits array
+ Clip* clip = olive::ActiveSequence->clips.at(clip_index).get();
+ pre_splits.append(clip_index);
+ for (int i=0;ilinked.size();i++) {
+ pre_splits.append(clip->linked.at(i));
+ }
+
+ std::sort(positions.begin(), positions.end());
+
+ // Remove any duplicate positions
+ for (int i=1;i > post_splits(positions.size());
+
+ for (int i=positions.size()-1;i>=0;i--) {
+
+ post_splits[i].resize(pre_splits.size());
+
+ for (int j=0;jset_timeline_out(positions.at(i+1));
+ }
+ }
+ }
+
+ for (int i=0;iappend(new AddClipCommand(olive::ActiveSequence.get(), post_splits[i]));
+ }
+
+}
+
void Timeline::previous_cut() {
if (olive::ActiveSequence != nullptr
&& olive::ActiveSequence->playhead > 0) {
diff --git a/panels/timeline.h b/panels/timeline.h
index e1b103e6c..93260f377 100644
--- a/panels/timeline.h
+++ b/panels/timeline.h
@@ -117,6 +117,7 @@ public:
bool split_selection(ComboAction* ca);
bool split_all_clips_at_point(ComboAction *ca, long point);
bool split_clip_and_relink(ComboAction* ca, int clip, long frame, bool relink);
+ void split_clip_at_positions(ComboAction* ca, int clip_index, QVector positions);
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);
diff --git a/ui/columnedgridlayout.cpp b/ui/columnedgridlayout.cpp
new file mode 100644
index 000000000..6404e6c96
--- /dev/null
+++ b/ui/columnedgridlayout.cpp
@@ -0,0 +1,34 @@
+#include "columnedgridlayout.h"
+
+ColumnedGridLayout::ColumnedGridLayout(QWidget* parent,
+ int maximum_columns) :
+ QGridLayout (parent),
+ maximum_columns_(maximum_columns)
+{
+}
+
+void ColumnedGridLayout::Add(QWidget *widget)
+{
+ if (maximum_columns_ > 0) {
+
+ int row = count() / maximum_columns_;
+ int column = count() % maximum_columns_;
+
+ addWidget(widget, row, column);
+
+ } else {
+
+ addWidget(widget);
+
+ }
+}
+
+int ColumnedGridLayout::MaximumColumns() const
+{
+ return maximum_columns_;
+}
+
+void ColumnedGridLayout::SetMaximumColumns(int maximum_columns)
+{
+ maximum_columns_ = maximum_columns;
+}
diff --git a/ui/columnedgridlayout.h b/ui/columnedgridlayout.h
new file mode 100644
index 000000000..d62eaa6d7
--- /dev/null
+++ b/ui/columnedgridlayout.h
@@ -0,0 +1,27 @@
+#ifndef COLUMNEDGRIDLAYOUT_H
+#define COLUMNEDGRIDLAYOUT_H
+
+#include
+
+/**
+ * @brief The ColumnedGridLayout class
+ *
+ * A simple derivative of QGridLayout that provides a automatic row/column layout based on a specified maximum
+ * column count.
+ */
+class ColumnedGridLayout : public QGridLayout
+{
+ Q_OBJECT
+public:
+ ColumnedGridLayout(QWidget* parent = nullptr,
+ int maximum_columns = 0);
+
+ void Add(QWidget* widget);
+ int MaximumColumns() const;
+ void SetMaximumColumns(int maximum_columns);
+
+private:
+ int maximum_columns_;
+};
+
+#endif // COLUMNEDGRIDLAYOUT_H
diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp
index f7955e319..4f49058fd 100644
--- a/ui/mainwindow.cpp
+++ b/ui/mainwindow.cpp
@@ -760,61 +760,7 @@ void MainWindow::setup_menus() {
tools_menu->addSeparator();
- selecting_also_seeks = MenuHelper::create_menu_action(tools_menu, "selectingalsoseeks", &olive::MenuHelper, SLOT(toggle_bool_action()));
- selecting_also_seeks->setCheckable(true);
- selecting_also_seeks->setData(reinterpret_cast(&olive::CurrentConfig.select_also_seeks));
-
- edit_tool_also_seeks = MenuHelper::create_menu_action(tools_menu, "editalsoseeks", &olive::MenuHelper, SLOT(toggle_bool_action()));
- edit_tool_also_seeks->setCheckable(true);
- edit_tool_also_seeks->setData(reinterpret_cast(&olive::CurrentConfig.edit_tool_also_seeks));
-
- edit_tool_selects_links = MenuHelper::create_menu_action(tools_menu, "editselectslinks", &olive::MenuHelper, SLOT(toggle_bool_action()));
- edit_tool_selects_links->setCheckable(true);
- edit_tool_selects_links->setData(reinterpret_cast(&olive::CurrentConfig.edit_tool_selects_links));
-
- seek_also_selects = MenuHelper::create_menu_action(tools_menu, "seekalsoselects", &olive::MenuHelper, SLOT(toggle_bool_action()));
- seek_also_selects->setCheckable(true);
- seek_also_selects->setData(reinterpret_cast(&olive::CurrentConfig.seek_also_selects));
-
- seek_to_end_of_pastes = MenuHelper::create_menu_action(tools_menu, "seektoendofpastes", &olive::MenuHelper, SLOT(toggle_bool_action()));
- seek_to_end_of_pastes->setCheckable(true);
- seek_to_end_of_pastes->setData(reinterpret_cast(&olive::CurrentConfig.paste_seeks));
-
- scroll_wheel_zooms = MenuHelper::create_menu_action(tools_menu, "scrollwheelzooms", &olive::MenuHelper, SLOT(toggle_bool_action()));
- scroll_wheel_zooms->setCheckable(true);
- scroll_wheel_zooms->setData(reinterpret_cast(&olive::CurrentConfig.scroll_zooms));
-
- invert_timeline_scroll_axes = MenuHelper::create_menu_action(tools_menu, "inverttimelinescrollaxes", &olive::MenuHelper, SLOT(toggle_bool_action()));
- invert_timeline_scroll_axes->setCheckable(true);
- invert_timeline_scroll_axes->setData(reinterpret_cast(&olive::CurrentConfig.invert_timeline_scroll_axes));
-
- enable_drag_files_to_timeline = MenuHelper::create_menu_action(tools_menu, "enabledragfilestotimeline", &olive::MenuHelper, SLOT(toggle_bool_action()));
- enable_drag_files_to_timeline->setCheckable(true);
- enable_drag_files_to_timeline->setData(reinterpret_cast(&olive::CurrentConfig.enable_drag_files_to_timeline));
-
- autoscale_by_default = MenuHelper::create_menu_action(tools_menu, "autoscalebydefault", &olive::MenuHelper, SLOT(toggle_bool_action()));
- autoscale_by_default->setCheckable(true);
- autoscale_by_default->setData(reinterpret_cast(&olive::CurrentConfig.autoscale_by_default));
-
- enable_seek_to_import = MenuHelper::create_menu_action(tools_menu, "enableseektoimport", &olive::MenuHelper, SLOT(toggle_bool_action()));
- enable_seek_to_import->setCheckable(true);
- enable_seek_to_import->setData(reinterpret_cast(&olive::CurrentConfig.enable_seek_to_import));
-
- enable_audio_scrubbing = MenuHelper::create_menu_action(tools_menu, "audioscrubbing", &olive::MenuHelper, SLOT(toggle_bool_action()));
- enable_audio_scrubbing->setCheckable(true);
- enable_audio_scrubbing->setData(reinterpret_cast(&olive::CurrentConfig.enable_audio_scrubbing));
-
- enable_drop_on_media_to_replace = MenuHelper::create_menu_action(tools_menu, "enabledropmediareplace", &olive::MenuHelper, SLOT(toggle_bool_action()));
- enable_drop_on_media_to_replace->setCheckable(true);
- enable_drop_on_media_to_replace->setData(reinterpret_cast(&olive::CurrentConfig.drop_on_media_to_replace));
-
- enable_hover_focus = MenuHelper::create_menu_action(tools_menu, "hoverfocus", &olive::MenuHelper, SLOT(toggle_bool_action()));
- enable_hover_focus->setCheckable(true);
- enable_hover_focus->setData(reinterpret_cast(&olive::CurrentConfig.hover_focus));
-
- set_name_and_marker = MenuHelper::create_menu_action(tools_menu, "asknamemarkerset", &olive::MenuHelper, SLOT(toggle_bool_action()));
- set_name_and_marker->setCheckable(true);
- set_name_and_marker->setData(reinterpret_cast(&olive::CurrentConfig.set_name_with_marker));
+ autocut_silence_ = MenuHelper::create_menu_action(tools_menu, "autocutsilence", olive::Global.get(), SLOT(open_autocut_silence_dialog()));
tools_menu->addSeparator();
@@ -952,21 +898,7 @@ void MainWindow::Retranslate()
hand_tool_action->setText(tr("Hand Tool"));
transition_tool_action->setText(tr("Transition Tool"));
snap_toggle->setText(tr("Enable Snapping"));
- selecting_also_seeks->setText(tr("Selecting Also Seeks"));
- edit_tool_also_seeks->setText(tr("Edit Tool Also Seeks"));
- edit_tool_selects_links->setText(tr("Edit Tool Selects Links"));
- seek_also_selects->setText(tr("Seek Also Selects"));
- seek_to_end_of_pastes->setText(tr("Seek to the End of Pastes"));
- scroll_wheel_zooms->setText(tr("Scroll Wheel Zooms"));
- scroll_wheel_zooms->setToolTip(tr("Hold CTRL to toggle this setting"));
- invert_timeline_scroll_axes->setText(tr("Invert Timeline Scroll Axes"));
- enable_drag_files_to_timeline->setText(tr("Enable Drag Files to Timeline"));
- autoscale_by_default->setText(tr("Auto-Scale By Default"));
- enable_seek_to_import->setText(tr("Enable Seek to Import"));
- enable_audio_scrubbing->setText(tr("Audio Scrubbing"));
- enable_drop_on_media_to_replace->setText(tr("Enable Drop on Media to Replace"));
- enable_hover_focus->setText(tr("Enable Hover Focus"));
- set_name_and_marker->setText(tr("Ask For Name When Setting Marker"));
+ autocut_silence_->setText(tr("Auto-Cut Silence"));
no_autoscroll->setText(tr("No Auto-Scroll"));
page_autoscroll->setText(tr("Page Auto-Scroll"));
@@ -1173,6 +1105,8 @@ 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);
@@ -1208,22 +1142,6 @@ 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_bool_action_checked(selecting_also_seeks);
- olive::MenuHelper.set_bool_action_checked(edit_tool_also_seeks);
- olive::MenuHelper.set_bool_action_checked(edit_tool_selects_links);
- olive::MenuHelper.set_bool_action_checked(seek_to_end_of_pastes);
- olive::MenuHelper.set_bool_action_checked(scroll_wheel_zooms);
- olive::MenuHelper.set_bool_action_checked(invert_timeline_scroll_axes);
- olive::MenuHelper.set_bool_action_checked(rectified_waveforms);
- olive::MenuHelper.set_bool_action_checked(enable_drag_files_to_timeline);
- olive::MenuHelper.set_bool_action_checked(autoscale_by_default);
- olive::MenuHelper.set_bool_action_checked(enable_seek_to_import);
- olive::MenuHelper.set_bool_action_checked(enable_audio_scrubbing);
- olive::MenuHelper.set_bool_action_checked(enable_drop_on_media_to_replace);
- olive::MenuHelper.set_bool_action_checked(enable_hover_focus);
- olive::MenuHelper.set_bool_action_checked(set_name_and_marker);
- olive::MenuHelper.set_bool_action_checked(seek_also_selects);
-
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);
diff --git a/ui/mainwindow.h b/ui/mainwindow.h
index e06987228..e38410291 100644
--- a/ui/mainwindow.h
+++ b/ui/mainwindow.h
@@ -328,21 +328,8 @@ private:
QAction* hand_tool_action;
QAction* transition_tool_action;
QAction* snap_toggle;
- QAction* selecting_also_seeks;
- QAction* edit_tool_also_seeks;
- QAction* edit_tool_selects_links;
- QAction* seek_to_end_of_pastes;
- QAction* scroll_wheel_zooms;
- QAction* invert_timeline_scroll_axes;
QAction* rectified_waveforms;
- QAction* enable_drag_files_to_timeline;
- QAction* autoscale_by_default;
- QAction* enable_seek_to_import;
- QAction* enable_audio_scrubbing;
- QAction* enable_drop_on_media_to_replace;
- QAction* enable_hover_focus;
- QAction* set_name_and_marker;
- QAction* seek_also_selects;
+ QAction* autocut_silence_;
QAction* preferences_action_;
QAction* clear_undo_action_;
diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp
index 30b07e443..768a1a94f 100644
--- a/ui/timelinewidget.cpp
+++ b/ui/timelinewidget.cpp
@@ -118,11 +118,26 @@ void TimelineWidget::show_context_menu(const QPoint& pos) {
if (!selected_clips.isEmpty()) {
+ bool video_clips_are_selected = false;
+ bool audio_clips_are_selected = false;
+
+ for (int i=0;itrack() < 0) {
+ video_clips_are_selected = true;
+ } else {
+ audio_clips_are_selected = true;
+ }
+ }
+
menu.addSeparator();
menu.addAction(tr("&Speed/Duration"), olive::Global.get(), SLOT(open_speed_dialog()));
- QAction* autoscaleAction = menu.addAction(tr("Auto-s&cale"), this, SLOT(toggle_autoscale()));
+ if (audio_clips_are_selected) {
+ menu.addAction(tr("Auto-Cut Silence"), olive::Global.get(), SLOT(open_autocut_silence_dialog()));
+ }
+
+ QAction* autoscaleAction = menu.addAction(tr("Auto-S&cale"), this, SLOT(toggle_autoscale()));
autoscaleAction->setCheckable(true);
// set autoscale to the first selected clip
autoscaleAction->setChecked(selected_clips.at(0)->autoscaled());