From 3e74d3dccbf8d3b566df6156f95bb49b7721c5a4 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 21 Mar 2019 20:54:27 +1100 Subject: [PATCH 1/8] moved load project functions from project panel to global --- dialogs/advancedvideodialog.cpp | 2 +- dialogs/advancedvideodialog.h | 20 +++- dialogs/exportdialog.cpp | 22 ++-- dialogs/exportdialog.h | 171 +++++++++++++++++++++++++++++++- dialogs/loaddialog.cpp | 28 +----- dialogs/loaddialog.h | 30 +++++- global/global.cpp | 52 ++++++++-- global/global.h | 43 +++++++- panels/project.cpp | 25 +---- panels/project.h | 2 - project/loadthread.h | 1 + ui/mainwindow.cpp | 2 +- 12 files changed, 318 insertions(+), 80 deletions(-) diff --git a/dialogs/advancedvideodialog.cpp b/dialogs/advancedvideodialog.cpp index 15309695b..c4e910d9d 100644 --- a/dialogs/advancedvideodialog.cpp +++ b/dialogs/advancedvideodialog.cpp @@ -33,7 +33,7 @@ extern "C" { } AdvancedVideoDialog::AdvancedVideoDialog(QWidget *parent, - int encoding_codec, + AVCodecID encoding_codec, VideoCodecParams &iparams) : QDialog(parent), params_(iparams) diff --git a/dialogs/advancedvideodialog.h b/dialogs/advancedvideodialog.h index e393c062d..0ff8c1fae 100644 --- a/dialogs/advancedvideodialog.h +++ b/dialogs/advancedvideodialog.h @@ -36,11 +36,29 @@ class AdvancedVideoDialog : public QDialog { Q_OBJECT public: + /** + * @brief AdvancedVideoDialog Constructor + * + * @param parent + * + * QWidget parent. Usually ExportDialog. + * + * @param encoding_codec + * + * The AVCodecID of the selected export codec. + * + * @param iparams + * + * A VideoCodecParams struct containing the extra codec data. + */ AdvancedVideoDialog(QWidget* parent, - int encoding_codec, + AVCodecID encoding_codec, VideoCodecParams& iparams); public slots: + /** + * @brief Overrided accept for saving the UI data into the provided VideoCodecParams struct. + */ virtual void accept() override; private: /** diff --git a/dialogs/exportdialog.cpp b/dialogs/exportdialog.cpp index 51180a7ea..b983eca15 100644 --- a/dialogs/exportdialog.cpp +++ b/dialogs/exportdialog.cpp @@ -330,16 +330,16 @@ void ExportDialog::format_changed(int index) { audioGroupbox->setEnabled(audio_enabled); } -void ExportDialog::render_thread_finished() { +void ExportDialog::export_thread_finished() { // Determine if the export succeeded bool succeeded = (progressBar->value() == 100); // If it failed and we didn't cancel it, it must have errored out. Show an error message. - if (!succeeded && !et->WasInterrupted()) { + if (!succeeded && !export_thread_->WasInterrupted()) { QMessageBox::critical( this, tr("Export Failed"), - tr("Export failed - %1").arg(et->GetError()), + tr("Export failed - %1").arg(export_thread_->GetError()), QMessageBox::Ok ); } @@ -358,10 +358,10 @@ void ExportDialog::render_thread_finished() { update_ui(false); // Disconnect cancel button from export thread - disconnect(renderCancel, SIGNAL(clicked(bool)), et, SLOT(Interrupt())); + disconnect(renderCancel, SIGNAL(clicked(bool)), export_thread_, SLOT(Interrupt())); // Free the export thread - et->deleteLater(); + export_thread_->deleteLater(); // If the export succeeded, close the dialog if (succeeded) { @@ -562,12 +562,12 @@ void ExportDialog::StartExport() { } // Create export thread - et = new ExportThread(params, vcodec_params, this); + export_thread_ = new ExportThread(params, vcodec_params, this); // Connect export thread signals/slots - connect(et, SIGNAL(finished()), this, SLOT(render_thread_finished())); - connect(et, SIGNAL(ProgressChanged(int, qint64)), this, SLOT(update_progress_bar(int, qint64))); - connect(renderCancel, SIGNAL(clicked(bool)), et, SLOT(Interrupt())); + connect(export_thread_, SIGNAL(finished()), this, SLOT(export_thread_finished())); + connect(export_thread_, SIGNAL(ProgressChanged(int, qint64)), this, SLOT(update_progress_bar(int, qint64))); + connect(renderCancel, SIGNAL(clicked(bool)), export_thread_, SLOT(Interrupt())); // Close all currently open clips close_active_clips(olive::ActiveSequence.get()); @@ -580,7 +580,7 @@ void ExportDialog::StartExport() { total_export_time_start = QDateTime::currentMSecsSinceEpoch(); - et->start(); + export_thread_->start(); } } @@ -667,7 +667,7 @@ void ExportDialog::comp_type_changed(int) { } void ExportDialog::open_advanced_video_dialog() { - AdvancedVideoDialog avd(this, vcodecCombobox->currentData().toInt(), vcodec_params); + AdvancedVideoDialog avd(this, static_cast(vcodecCombobox->currentData().toInt()), vcodec_params); avd.exec(); } diff --git a/dialogs/exportdialog.h b/dialogs/exportdialog.h index b2ee2e14c..c39c8af2a 100644 --- a/dialogs/exportdialog.h +++ b/dialogs/exportdialog.h @@ -68,42 +68,205 @@ private slots: * Asks the user for the file to save to. */ void StartExport(); + + /** + * @brief Slot for the export thread to update the progress bar's value + * + * @param value + * + * An value between 0 - 100. A percentage of the Sequence that has been exported so far. + * + * @param remaining_ms + * + * The estimated time in milliseconds that it will take to complete the rest of the Sequence. + */ void update_progress_bar(int value, qint64 remaining_ms); - void render_thread_finished(); + + /** + * @brief Slot for the export thread completing (both succeeding and failing) + * + * Runs whenever the thread has finished. Determines whether the thread succeeded or not (and shows an error message + * if not), cleans up the ExportThread object, sets the UI state back to normal. + * + * Connect to ExportThread::finished(). + */ + void export_thread_finished(); + + /** + * @brief Slot for when the video codec changes + * + * Some video codecs require different settings. In the case of that, this function sorts through those. + * + * @param index + * + * Current vcodecCombobox index - its item data contains the AVCodecID. + */ void vcodec_changed(int index); + + /** + * @brief Slot for when the compression type changes + * + * Different UI objects should be displayed for different compression types. + * + * @param index + * + * Unused. + */ void comp_type_changed(int index); + + /** + * @brief Slot to open the Advanced Video Dialog + * + * Opens a dialog for setting more advanced video settings and passes a reference to vcodec_params to it. + */ void open_advanced_video_dialog(); private: + /** + * @brief Function to create UI objects. + */ void setup_ui(); + + /** + * @brief Enables/disables certain UI objects based on the exporting state. + * + * Some UI controls don't need to be set while exporting. This function enables/disables them appropriately. + * + * @param r + * + * TRUE if we're exporting, FALSE if we finished. + */ void prep_ui_for_render(bool r); - QVector format_strings; - ExportThread* et; - + /** + * @brief Retrieves the human-readable name of an AVCodecID and adds it to a QComboBox + * + * Also sets that item's data to the AVCodecID so it can be retrieved directly from the QComboBox. + * + * @param box + * + * The QComboBox to add the item to. + * + * @param codec + * + * The codec to add to the QComboBox. + */ void add_codec_to_combobox(QComboBox* box, enum AVCodecID codec); + /** + * @brief Internal array of human-readable names corresponding to enum ExportFormats + */ + QVector format_strings; + + /** + * @brief Pointer to an ExportThread + * + * Set when exporting starts, and deleted by export_thread_finished() when the thread is complete. + */ + ExportThread* export_thread_; + + /** + * @brief Struct for advanced video codec parameters. + * + * More advanced video encoding parameters to be sent to the ExportThread. These variables are not directly editable + * in this dialog, instead calling open_advanced_video_dialog() will open an AdvancedVideoDialog for setting these + * values directly. vcodec_changed() should also set these to the defaults for that codec where appropriate. + */ VideoCodecParams vcodec_params; + /** + * @brief ComboBox for selecting the time range of the Sequence to export + */ QComboBox* rangeCombobox; + + /** + * @brief SpinBox for the exported video's width + */ QSpinBox* widthSpinbox; + + /** + * @brief SpinBox for the exported video's bitrate + */ QDoubleSpinBox* videobitrateSpinbox; + + /** + * @brief Label for the exported video's bitrate - changes depending on the compression type + */ QLabel* videoBitrateLabel; + + /** + * @brief SpinBox for the exported video's frame rate + */ QDoubleSpinBox* framerateSpinbox; + + /** + * @brief ComboBox for the exported video codec + */ QComboBox* vcodecCombobox; + + /** + * @brief ComboBox for the exported audio's codec + */ QComboBox* acodecCombobox; + + /** + * @brief SpinBox for the exported audio's sample rate + */ QSpinBox* samplingRateSpinbox; + + /** + * @brief SpinBox for the exported audio's bitrate + */ QSpinBox* audiobitrateSpinbox; + + /** + * @brief Progress bar for visually showing the export progress + */ QProgressBar* progressBar; + + /** + * @brief ComboBox for the exported video's format + */ QComboBox* formatCombobox; + + /** + * @brief SpinBox for the exported video's height + */ QSpinBox* heightSpinbox; + + /** + * @brief Export button to trigger the start of an export + */ QPushButton* export_button; + + /** + * @brief Dialog cancel button to close this dialog + */ QPushButton* cancel_button; + + /** + * @brief Cancel button to abort the export before completion + */ QPushButton* renderCancel; + + /** + * @brief GroupBox containing all video-related UI objects + */ QGroupBox* videoGroupbox; + + /** + * @brief GroupBox containing all audio-related UI objects + */ QGroupBox* audioGroupbox; + + /** + * @brief ComboBox for the exported video compression type + */ QComboBox* compressionTypeCombobox; + /** + * @brief Time value set when exporting begins to determine the total duration of the export + */ qint64 total_export_time_start; }; diff --git a/dialogs/loaddialog.cpp b/dialogs/loaddialog.cpp index 92327eabb..d3399f4d5 100644 --- a/dialogs/loaddialog.cpp +++ b/dialogs/loaddialog.cpp @@ -31,7 +31,7 @@ #include "ui/sourcetable.h" #include "ui/mainwindow.h" -LoadDialog::LoadDialog(QWidget *parent, const QString& fn, bool autorecovery, bool clear) : +LoadDialog::LoadDialog(QWidget *parent) : QDialog(parent) { setWindowTitle(tr("Loading...")); @@ -46,7 +46,7 @@ LoadDialog::LoadDialog(QWidget *parent, const QString& fn, bool autorecovery, bo layout->addWidget(bar); cancel_button = new QPushButton(tr("Cancel"), this); - connect(cancel_button, SIGNAL(clicked(bool)), this, SLOT(cancel())); + connect(cancel_button, SIGNAL(clicked(bool)), this, SIGNAL(cancel())); hboxLayout = new QHBoxLayout(); hboxLayout->addStretch(); @@ -54,27 +54,9 @@ LoadDialog::LoadDialog(QWidget *parent, const QString& fn, bool autorecovery, bo hboxLayout->addStretch(); layout->addLayout(hboxLayout); - - update(); - - lt = new LoadThread(fn, autorecovery, clear); - QObject::connect(lt, SIGNAL(success()), this, SLOT(thread_done())); - QObject::connect(lt, SIGNAL(error()), this, SLOT(die())); - QObject::connect(lt, SIGNAL(report_progress(int)), bar, SLOT(setValue(int))); - lt->start(); } -void LoadDialog::cancel() { - lt->cancel(); - lt->wait(); - die(); -} - -void LoadDialog::die() { - olive::Global->new_project(); - reject(); -} - -void LoadDialog::thread_done() { - accept(); +QProgressBar *LoadDialog::progress_bar() +{ + return bar; } diff --git a/dialogs/loaddialog.h b/dialogs/loaddialog.h index 63586d226..f7b30798a 100644 --- a/dialogs/loaddialog.h +++ b/dialogs/loaddialog.h @@ -28,15 +28,37 @@ #include "project/projectelements.h" #include "project/loadthread.h" +/** + * @brief The LoadDialog class + * + * Shows a modal dialog for loading a project and creates a LoadThread to load it. + */ class LoadDialog : public QDialog { Q_OBJECT public: - LoadDialog(QWidget* parent, const QString& filename, bool autorecovery, bool clear); -private slots: + /** + * @brief LoadDialog Constructor + * + * @param parent + * + * QWidget parent. Usually MainWindow. + * + * @param filename + * + * URL of the project file to load. + * + * @param autorecovery + * + * TRUE if this is an autorecovery project + * + * @param clear + */ + LoadDialog(QWidget* parent); + + QProgressBar* progress_bar(); +signals: void cancel(); - void die(); - void thread_done(); private: QProgressBar* bar; QPushButton* cancel_button; diff --git a/global/global.cpp b/global/global.cpp index 668586dc9..5464ac30d 100644 --- a/global/global.cpp +++ b/global/global.cpp @@ -38,6 +38,8 @@ #include "dialogs/aboutdialog.h" #include "dialogs/speeddialog.h" #include "dialogs/actionsearch.h" +#include "dialogs/loaddialog.h" +#include "project/loadthread.h" #include "timeline/sequence.h" #include "ui/mediaiconservice.h" #include "ui/mainwindow.h" @@ -91,7 +93,7 @@ void OliveGlobal::check_for_autorecovery_file() { if (QFile::exists(autorecovery_filename)) { if (QMessageBox::question(nullptr, tr("Auto-recovery"), tr("Olive didn't close properly and an autorecovery file was detected. Would you like to open it?"), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) { enable_load_project_on_init = false; - open_project_worker(autorecovery_filename, true); + OpenProjectWorker(autorecovery_filename, true); } } autorecovery_timer.setInterval(60000); @@ -164,6 +166,33 @@ void OliveGlobal::SetNativeStyling(QWidget *w) #endif } +void OliveGlobal::LoadProject(const QString &fn, bool autorecovery, bool clear) +{ + // Normally, the user will be closing the previous project to load a new one, but just in case the user + // is importing a new project + + if (clear) { + new_project(); + } + + LoadDialog ld(olive::MainWindow); + + LoadThread* lt = new LoadThread(fn, autorecovery, clear); + connect(&ld, SIGNAL(cancel()), lt, SLOT(cancel())); + connect(lt, SIGNAL(success()), &ld, SLOT(accept())); + connect(lt, SIGNAL(error()), &ld, SLOT(reject())); + connect(lt, SIGNAL(error()), this, SLOT(new_project())); + connect(lt, SIGNAL(report_progress(int)), ld.progress_bar(), SLOT(setValue(int))); + lt->start(); + + ld.exec(); +} + +void OliveGlobal::ImportProject(const QString &fn) +{ + LoadProject(fn, false, false); +} + void OliveGlobal::new_project() { if (can_close_project()) { // clear graph editor @@ -172,8 +201,12 @@ void OliveGlobal::new_project() { // clear effects panel panel_effect_controls->Clear(true); + // clear existing project + olive::Global->set_sequence(nullptr); + panel_footage_viewer->set_media(nullptr); + // clear project contents (footage, sequences, etc.) - panel_project->new_project(); + panel_project->clear(); // clear undo stack olive::UndoStack.clear(); @@ -183,13 +216,16 @@ void OliveGlobal::new_project() { // full update of all panels update_ui(false); + + // set to unmodified + olive::Global->set_modified(false); } } -void OliveGlobal::open_project() { +void OliveGlobal::OpenProject() { QString fn = QFileDialog::getOpenFileName(olive::MainWindow, tr("Open Project..."), "", project_file_filter); if (!fn.isEmpty() && can_close_project()) { - open_project_worker(fn, false); + OpenProjectWorker(fn, false); } } @@ -205,7 +241,7 @@ void OliveGlobal::open_recent(int index) { panel_project->save_recent_projects(); } } else if (can_close_project()) { - open_project_worker(recent_url, false); + OpenProjectWorker(recent_url, false); } } @@ -269,7 +305,7 @@ void OliveGlobal::finished_initialize() { // if a project was set as a command line argument, we load it here if (QFileInfo::exists(olive::ActiveProjectFilename)) { - open_project_worker(olive::ActiveProjectFilename, false); + OpenProjectWorker(olive::ActiveProjectFilename, false); } else { QMessageBox::critical(olive::MainWindow, tr("Missing Project File"), @@ -323,9 +359,9 @@ void OliveGlobal::set_sequence(SequencePtr s) panel_timeline->setFocus(); } -void OliveGlobal::open_project_worker(const QString& fn, bool autorecovery) { +void OliveGlobal::OpenProjectWorker(const QString& fn, bool autorecovery) { update_project_filename(fn); - panel_project->load_project(fn, autorecovery, true); + LoadProject(fn, autorecovery, true); olive::UndoStack.clear(); } diff --git a/global/global.h b/global/global.h index 4c4cc0872..560295f7c 100644 --- a/global/global.h +++ b/global/global.h @@ -193,7 +193,18 @@ public slots: * Confirms whether the current project can be closed, and if so, shows an open file dialog to allow the user to * select a project file and then triggers a project load with it. */ - void open_project(); + void OpenProject(); + + /** + * @brief Import project from file + * + * Imports an Olive project into the current project, effectively merging them. + * + * @param fn + * + * The filename of the project to import. + */ + void ImportProject(const QString& fn); /** * @brief Open recent project from list @@ -327,7 +338,35 @@ private: * beside the original project file so that it does not overwrite the original and so that the user is not working * on the autorecovery project in Olive's application data directory. */ - void open_project_worker(const QString& fn, bool autorecovery); + void OpenProjectWorker(const QString& fn, bool autorecovery); + + /** + * @brief Create a LoadDialog and start a LoadThread to load data from a project + * + * Loads data from an Olive project file creating a LoadDialog to show visual information and a LoadThread to load + * outside of the main/GUI thread. + * + * All project loading functions eventually lead to this one and there's no reason to use it directly. Instead use + * one of the following functions: + * + * * OpenProject() - to check if the current project can be closed and prompt the user for the new project file + * * OpenProjectWorker() - if you already have the filename and wish to close the current project and open it + * * ImportProject() - to import a project file into this one, effectively merging them both + * + * @param fn + * + * The URL of the project file to open + * + * @param autorecovery + * + * TRUE if this file is an autorecovery file, in which case it's loaded slightly differently + * + * @param clear + * + * TRUE if the current project should be closed before opening, FALSE if the project should be imported into the + * currently open one. + */ + void LoadProject(const QString& fn, bool autorecovery, bool clear); /** * @brief File filter used for any file dialogs relating to Olive project files. diff --git a/panels/project.cpp b/panels/project.cpp index 2ef1ec72e..74e051941 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -111,7 +111,7 @@ Project::Project(QWidget *parent) : QPushButton* toolbar_open = new QPushButton(); toolbar_open->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/open.svg"))); toolbar_open->setToolTip("Open Project"); - connect(toolbar_open, SIGNAL(clicked(bool)), olive::Global.get(), SLOT(open_project())); + connect(toolbar_open, SIGNAL(clicked(bool)), olive::Global.get(), SLOT(OpenProject())); toolbar->addWidget(toolbar_open); QPushButton* toolbar_save = new QPushButton(); @@ -724,7 +724,7 @@ void Project::process_file_list(QStringList& files, bool recursive, MediaPtr rep QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { // load the project without clearing the current one - load_project(file, false, false); + olive::Global->ImportProject(file); } @@ -1041,27 +1041,6 @@ void Project::clear() { tree_view->update(); } -void Project::new_project() { - // clear existing project - olive::Global->set_sequence(nullptr); - panel_footage_viewer->set_media(nullptr); - clear(); - olive::Global->set_modified(false); -} - -void Project::load_project(const QString& filename, bool autorecovery, bool clear) { - - // Normally, the user will be closing the previous project to load a new one, but just in case the user - // is importing a new project - - if (clear) { - new_project(); - } - - LoadDialog ld(this, filename, autorecovery, clear); - ld.exec(); -} - void save_marker(QXmlStreamWriter& stream, const Marker& m) { stream.writeStartElement("marker"); stream.writeAttribute("frame", QString::number(m.frame)); diff --git a/panels/project.h b/panels/project.h index 4ee1d779f..ace9e4404 100644 --- a/panels/project.h +++ b/panels/project.h @@ -66,8 +66,6 @@ public: bool reveal_media(Media *media, QModelIndex parent = QModelIndex()); void add_recent_project(QString url); - void new_project(); - void load_project(const QString &filename, bool autorecovery, bool clear); void save_project(bool autorecovery); MediaPtr create_folder_internal(QString name); diff --git a/project/loadthread.h b/project/loadthread.h index 84badc682..be69b9e97 100644 --- a/project/loadthread.h +++ b/project/loadthread.h @@ -37,6 +37,7 @@ class LoadThread : public QThread public: LoadThread(const QString& filename, bool autorecovery, bool clear); void run(); +public slots: void cancel(); signals: void start_question(const QString &title, const QString &text, int buttons); diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index 32bbc81df..6a53d5ad0 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -453,7 +453,7 @@ void MainWindow::setup_menus() { new_menu = MenuHelper::create_submenu(file_menu); olive::MenuHelper.make_new_menu(new_menu); - open_project = MenuHelper::create_menu_action(file_menu, "openproj", olive::Global.get(), SLOT(open_project()), QKeySequence("Ctrl+O")); + open_project = MenuHelper::create_menu_action(file_menu, "openproj", olive::Global.get(), SLOT(OpenProject()), QKeySequence("Ctrl+O")); open_recent = MenuHelper::create_submenu(file_menu); From 926894f20f6fcf2fc22ce4d5699320554aa2894a Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 21 Mar 2019 21:12:44 +1100 Subject: [PATCH 2/8] finished documenting load dialog --- dialogs/loaddialog.cpp | 9 +++++---- dialogs/loaddialog.h | 35 ++++++++++++++++++++--------------- global/global.cpp | 2 +- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/dialogs/loaddialog.cpp b/dialogs/loaddialog.cpp index d3399f4d5..dfcbb7f5b 100644 --- a/dialogs/loaddialog.cpp +++ b/dialogs/loaddialog.cpp @@ -45,10 +45,11 @@ LoadDialog::LoadDialog(QWidget *parent) : bar->setValue(0); layout->addWidget(bar); - cancel_button = new QPushButton(tr("Cancel"), this); + QPushButton* cancel_button = new QPushButton(tr("Cancel"), this); connect(cancel_button, SIGNAL(clicked(bool)), this, SIGNAL(cancel())); - hboxLayout = new QHBoxLayout(); + // Wrap cancel button in a horizontal layout so it can be centered + QHBoxLayout* hboxLayout = new QHBoxLayout(); hboxLayout->addStretch(); hboxLayout->addWidget(cancel_button); hboxLayout->addStretch(); @@ -56,7 +57,7 @@ LoadDialog::LoadDialog(QWidget *parent) : layout->addLayout(hboxLayout); } -QProgressBar *LoadDialog::progress_bar() +void LoadDialog::setValue(int i) { - return bar; + bar->setValue(i); } diff --git a/dialogs/loaddialog.h b/dialogs/loaddialog.h index f7b30798a..5fa357155 100644 --- a/dialogs/loaddialog.h +++ b/dialogs/loaddialog.h @@ -31,7 +31,7 @@ /** * @brief The LoadDialog class * - * Shows a modal dialog for loading a project and creates a LoadThread to load it. + * Shows a modal dialog for loading a project. Designed to be connected to a LoadThread object. */ class LoadDialog : public QDialog { @@ -43,27 +43,32 @@ public: * @param parent * * QWidget parent. Usually MainWindow. - * - * @param filename - * - * URL of the project file to load. - * - * @param autorecovery - * - * TRUE if this is an autorecovery project - * - * @param clear */ LoadDialog(QWidget* parent); - QProgressBar* progress_bar(); +public slots: + /** + * @brief Set the progress bar value + * + * Ideally, connect this to LoadThread::report_progress(). + * + * @param i + * + * Should be a value between 0-100. + */ + void setValue(int i); signals: + /** + * @brief Signal emitted when the cancel button is clicked. + * + * Ideally, connect this to LoadThread::cancel(); + */ void cancel(); private: + /** + * @brief Progress bar widget + */ QProgressBar* bar; - QPushButton* cancel_button; - QHBoxLayout* hboxLayout; - LoadThread* lt; }; #endif // LOADDIALOG_H diff --git a/global/global.cpp b/global/global.cpp index 5464ac30d..65ec8036e 100644 --- a/global/global.cpp +++ b/global/global.cpp @@ -182,7 +182,7 @@ void OliveGlobal::LoadProject(const QString &fn, bool autorecovery, bool clear) connect(lt, SIGNAL(success()), &ld, SLOT(accept())); connect(lt, SIGNAL(error()), &ld, SLOT(reject())); connect(lt, SIGNAL(error()), this, SLOT(new_project())); - connect(lt, SIGNAL(report_progress(int)), ld.progress_bar(), SLOT(setValue(int))); + connect(lt, SIGNAL(report_progress(int)), &ld, SLOT(setValue(int))); lt->start(); ld.exec(); From 9b29758b7f6be59d367056c20de1b9ac412e1a4b Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 21 Mar 2019 21:38:00 +1100 Subject: [PATCH 3/8] more documentation --- dialogs/mediapropertiesdialog.h | 60 ++++++++++++++++++---- dialogs/newsequencedialog.cpp | 14 ++++-- dialogs/newsequencedialog.h | 88 +++++++++++++++++++++++++++++++-- 3 files changed, 145 insertions(+), 17 deletions(-) diff --git a/dialogs/mediapropertiesdialog.h b/dialogs/mediapropertiesdialog.h index 8f24eee72..c13e2c1f6 100644 --- a/dialogs/mediapropertiesdialog.h +++ b/dialogs/mediapropertiesdialog.h @@ -31,19 +31,61 @@ #include "project/footage.h" #include "project/media.h" +/** + * @brief The MediaPropertiesDialog class + * + * A dialog for setting properties on Media. + */ class MediaPropertiesDialog : public QDialog { - Q_OBJECT + Q_OBJECT public: - MediaPropertiesDialog(QWidget *parent, Media* i); + /** + * @brief MediaPropertiesDialog Constructor + * + * @param parent + * + * QWidget parent. Usually MainWindow or Project panel. + * + * @param i + * + * Media object to set properties for. + */ + MediaPropertiesDialog(QWidget *parent, Media* i); private: - QComboBox* interlacing_box; - QLineEdit* name_box; - Media* item; - QListWidget* track_list; - QDoubleSpinBox* conform_fr; - QCheckBox* premultiply_alpha_setting; + /** + * @brief ComboBox for interlacing setting + */ + QComboBox* interlacing_box; + + /** + * @brief Media name text field + */ + QLineEdit* name_box; + + /** + * @brief Internal pointer to Media object (set in constructor) + */ + Media* item; + + /** + * @brief A list widget for listing the tracks in Media + */ + QListWidget* track_list; + + /** + * @brief Frame rate to conform to + */ + QDoubleSpinBox* conform_fr; + + /** + * @brief Setting for associated/premultiplied alpha + */ + QCheckBox* premultiply_alpha_setting; private slots: - void accept(); + /** + * @brief Overrided accept function for saving the properties back to the Media class + */ + void accept(); }; #endif // MEDIAPROPERTIESDIALOG_H diff --git a/dialogs/newsequencedialog.cpp b/dialogs/newsequencedialog.cpp index 47ead1336..466a431b8 100644 --- a/dialogs/newsequencedialog.cpp +++ b/dialogs/newsequencedialog.cpp @@ -76,15 +76,15 @@ NewSequenceDialog::NewSequenceDialog(QWidget *parent, Media *existing) : } } -NewSequenceDialog::~NewSequenceDialog() -{} - void NewSequenceDialog::set_sequence_name(const QString& s) { sequence_name_edit->setText(s); } -void NewSequenceDialog::create() { +void NewSequenceDialog::accept() { if (existing_sequence == nullptr) { + + // The dialog wasn't given an existing Sequence object, so we'll make a new one + SequencePtr s = std::make_shared(); s->name = sequence_name_edit->text(); @@ -97,7 +97,11 @@ void NewSequenceDialog::create() { ComboAction* ca = new ComboAction(); panel_project->create_sequence_internal(ca, s, true, nullptr); olive::UndoStack.push(ca); + } else { + + // The dialog was given an existing Sequence object, so we'll apply the changes to it + ComboAction* ca = new ComboAction(); double multiplier = frame_rate_combobox->currentData().toDouble() / existing_sequence->frame_rate; @@ -121,7 +125,7 @@ void NewSequenceDialog::create() { olive::UndoStack.push(ca); } - accept(); + QDialog::accept(); } void NewSequenceDialog::preset_changed(int index) { diff --git a/dialogs/newsequencedialog.h b/dialogs/newsequencedialog.h index b71bdc099..4acd69853 100644 --- a/dialogs/newsequencedialog.h +++ b/dialogs/newsequencedialog.h @@ -30,33 +30,115 @@ #include "project/media.h" #include "timeline/sequence.h" +/** + * @brief The NewSequenceDialog class + * + * A dialog that creates a new (or edits an existing) Sequence object. + */ class NewSequenceDialog : public QDialog { Q_OBJECT - public: + /** + * @brief NewSequenceDialog constructor + * + * @param parent + * + * QWidget parent. Usually MainWindow. + * + * @param existing + * + * Set this to a Sequence object (wrapped in a Media object) to edit an existing Sequence, + * or leave as nullptr to create a new one. + */ explicit NewSequenceDialog(QWidget *parent = nullptr, Media* existing = nullptr); - ~NewSequenceDialog(); + /** + * @brief Set the name for the new Sequence + * + * If creating a new Sequence, use this function before calling exec() to set what the new Sequence's + * name will be. + * + * The primary use of this is to set a unique default name (i.e. one that doesn't exist + * in the Sequence already) which is done by Project panel. This is usually "Sequence" followed by a number. + * + * @param s + * + * The name to set the new Sequence. + */ void set_sequence_name(const QString& s); private slots: - void create(); + /** + * @brief Override accept function to create/edit a Sequence + */ + virtual void accept() override; + + /** + * @brief Slot when the user changes the preset + * + * Sets all values according to the preset chosen. + * + * @param index + * + * Currently selected index of preset_combobox; + */ void preset_changed(int index); private: + /** + * @brief Internal reference to an existing Sequence (if one was provided to the constructor) + */ SequencePtr existing_sequence; + + /** + * @brief Internal reference to an existing Media wrapper (if one was provided to the constructor) + */ Media* existing_item; + /** + * @brief Internal function to create the dialog's UI + */ void setup_ui(); + /** + * @brief ComboBox to set the preset + */ QComboBox* preset_combobox; + + /** + * @brief SpinBox to set the Sequence height + */ QSpinBox* height_numeric; + + /** + * @brief SpinBox to set the Sequence width + */ QSpinBox* width_numeric; + + /** + * @brief ComboBox to set the pixel aspect ratio + */ QComboBox* par_combobox; + + /** + * @brief ComboBox to set the interlacing mode + */ QComboBox* interlacing_combobox; + + /** + * @brief ComboBox to set the frame rate + */ QComboBox* frame_rate_combobox; + + /** + * @brief ComboBox to set the audio frequence + */ QComboBox* audio_frequency_combobox; + + /** + * @brief Line edit to set the Sequence's name + */ QLineEdit* sequence_name_edit; }; From f6a4e2c5d7079f13865262d5ee0f3d50de1d2bb0 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 21 Mar 2019 23:38:34 +1100 Subject: [PATCH 4/8] started documentation of preferencesdialog --- dialogs/preferencesdialog.cpp | 4 ++-- dialogs/preferencesdialog.h | 45 +++++++++++++++++++++++------------ global/global.cpp | 1 - 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/dialogs/preferencesdialog.cpp b/dialogs/preferencesdialog.cpp index 1cd0566bb..da5164255 100644 --- a/dialogs/preferencesdialog.cpp +++ b/dialogs/preferencesdialog.cpp @@ -87,9 +87,9 @@ PreferencesDialog::PreferencesDialog(QWidget *parent) : fastSeekButton->setChecked(olive::CurrentConfig.fast_seeking); recordingComboBox->setCurrentIndex(olive::CurrentConfig.recording_mode - 1); imgSeqFormatEdit->setText(olive::CurrentConfig.img_seq_formats); -} -PreferencesDialog::~PreferencesDialog() {} + setup_kbd_shortcuts(olive::MainWindow->menuBar()); +} void PreferencesDialog::setup_kbd_shortcut_worker(QMenu* menu, QTreeWidgetItem* parent) { QList actions = menu->actions(); diff --git a/dialogs/preferencesdialog.h b/dialogs/preferencesdialog.h index 714912fa0..6a5bade56 100644 --- a/dialogs/preferencesdialog.h +++ b/dialogs/preferencesdialog.h @@ -36,30 +36,32 @@ #include "timeline/sequence.h" -class KeySequenceEditor : public QKeySequenceEdit { - Q_OBJECT -public: - KeySequenceEditor(QWidget *parent, QAction* a); - void set_action_shortcut(); - void reset_to_default(); - QString action_name(); - QString export_shortcut(); -private: - QAction* action; -}; +class KeySequenceEditor; +/** + * @brief The PreferencesDialog class + * + * A dialog for the global application settings. Mostly an interface for Config. + */ class PreferencesDialog : public QDialog { Q_OBJECT public: + /** + * @brief PreferencesDialog Constructor + * + * @param parent + * + * QWidget parent. Usually MainWindow. + */ explicit PreferencesDialog(QWidget *parent = nullptr); - ~PreferencesDialog(); - - void setup_kbd_shortcuts(QMenuBar* menu); private slots: - void save(); + /** + * @brief Override of accept to save preferences to Config. + */ + virtual void accept() override; void reset_default_shortcut(); void reset_all_shortcuts(); bool refine_shortcut_list(const QString &, QTreeWidgetItem* parent = nullptr); @@ -70,6 +72,7 @@ private slots: private: void setup_ui(); + void setup_kbd_shortcuts(QMenuBar* menu); void setup_kbd_shortcut_worker(QMenu* menu, QTreeWidgetItem* parent); // used to delete previews @@ -113,4 +116,16 @@ private: QVector key_shortcut_fields; }; +class KeySequenceEditor : public QKeySequenceEdit { + Q_OBJECT +public: + KeySequenceEditor(QWidget *parent, QAction* a); + void set_action_shortcut(); + void reset_to_default(); + QString action_name(); + QString export_shortcut(); +private: + QAction* action; +}; + #endif // PREFERENCESDIALOG_H diff --git a/global/global.cpp b/global/global.cpp index 65ec8036e..7bde452fa 100644 --- a/global/global.cpp +++ b/global/global.cpp @@ -344,7 +344,6 @@ void OliveGlobal::open_preferences() { panel_footage_viewer->pause(); PreferencesDialog pd(olive::MainWindow); - pd.setup_kbd_shortcuts(olive::MainWindow->menuBar()); pd.exec(); } From 81319764a79c2620436c263007ae264434ee5c54 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 21 Mar 2019 23:47:15 +1100 Subject: [PATCH 5/8] fixed #660 --- project/sourcescommon.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/project/sourcescommon.cpp b/project/sourcescommon.cpp index e516774e0..1833271ca 100644 --- a/project/sourcescommon.cpp +++ b/project/sourcescommon.cpp @@ -271,9 +271,6 @@ void SourcesCommon::dropEvent(QWidget* parent, const QModelIndexList& items) { const QMimeData* mimeData = event->mimeData(); MediaPtr m = project_parent->item_to_media_ptr(drop_item); - if (m == nullptr) { - return; - } if (mimeData->hasUrls()) { // drag files in from outside QList urls = mimeData->urls(); @@ -285,7 +282,7 @@ void SourcesCommon::dropEvent(QWidget* parent, bool replace = false; if (urls.size() == 1 && drop_item.isValid() - && m->get_type() == MEDIA_TYPE_FOOTAGE + && (m != nullptr && m->get_type() == MEDIA_TYPE_FOOTAGE) && !QFileInfo(paths.at(0)).isDir() && olive::CurrentConfig.drop_on_media_to_replace && QMessageBox::question( From 067eec0b90aea3e43c26f972177c21802d369b7f Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 22 Mar 2019 01:17:42 +1100 Subject: [PATCH 6/8] cleanups --- dialogs/newsequencedialog.cpp | 2 +- dialogs/preferencesdialog.cpp | 6 +-- panels/effectcontrols.cpp | 5 ++- panels/project.cpp | 21 ++++++---- project/loadthread.cpp | 26 ++++++++---- project/loadthread.h | 1 + project/media.cpp | 10 ++--- project/media.h | 2 +- project/projectfilter.h | 28 ++++++------- project/projectmodel.cpp | 25 ++++++++--- ui/mainwindow.cpp | 79 ++++++++++++++++++++++++++--------- undo/undo.cpp | 10 ++++- undo/undo.h | 1 + 13 files changed, 147 insertions(+), 69 deletions(-) diff --git a/dialogs/newsequencedialog.cpp b/dialogs/newsequencedialog.cpp index 466a431b8..f852e5253 100644 --- a/dialogs/newsequencedialog.cpp +++ b/dialogs/newsequencedialog.cpp @@ -284,6 +284,6 @@ void NewSequenceDialog::setup_ui() { verticalLayout->addWidget(buttonBox); connect(preset_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(preset_changed(int))); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(create())); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); } diff --git a/dialogs/preferencesdialog.cpp b/dialogs/preferencesdialog.cpp index da5164255..b8742926d 100644 --- a/dialogs/preferencesdialog.cpp +++ b/dialogs/preferencesdialog.cpp @@ -169,7 +169,7 @@ void PreferencesDialog::setup_kbd_shortcuts(QMenuBar* menubar) { } } -void PreferencesDialog::save() { +void PreferencesDialog::accept() { bool restart_after_saving = false; bool reinit_audio = false; bool reload_language = false; @@ -316,7 +316,7 @@ void PreferencesDialog::save() { olive::Global->load_translation_from_config(); } - accept(); + QDialog::accept(); if (restart_after_saving) { // since we already ran can_close_project(), bypass checking again by running set_modified(false) @@ -794,6 +794,6 @@ void PreferencesDialog::setup_ui() { verticalLayout->addWidget(buttonBox); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(save())); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); } diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index e27f8cbff..bb5e1ce9b 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -45,6 +45,7 @@ #include "panels/grapheditor.h" #include "ui/viewerwidget.h" #include "ui/menuhelper.h" +#include "ui/icons.h" #include "project/clipboard.h" #include "global/config.h" #include "ui/timelineheader.h" @@ -373,8 +374,8 @@ void EffectControls::setup_ui() { veHeaderLayout->setSpacing(0); veHeaderLayout->setMargin(0); - QIcon add_effect_icon(":/icons/add-effect.svg"); - QIcon add_transition_icon(":/icons/add-transition.svg"); + QIcon add_effect_icon = olive::icon::CreateIconFromSVG(":/icons/add-effect.svg", false); + QIcon add_transition_icon = olive::icon::CreateIconFromSVG(":/icons/add-transition.svg", false); btnAddVideoEffect = new QPushButton(); btnAddVideoEffect->setIcon(add_effect_icon); diff --git a/panels/project.cpp b/panels/project.cpp index 74e051941..47620459f 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -433,27 +433,30 @@ void Project::new_sequence() { } MediaPtr Project::create_sequence_internal(ComboAction *ca, SequencePtr s, bool open, Media* parent) { - if (parent == nullptr) { - parent = olive::project_model.get_root(); - } - MediaPtr item = std::make_shared(parent); + MediaPtr item = std::make_shared(); item->set_sequence(s); if (ca != nullptr) { + ca->append(new AddMediaCommand(item, parent)); if (open) { ca->append(new ChangeSequenceAction(s)); } + } else { + olive::project_model.appendChild(parent, item); if (open) { olive::Global->set_sequence(s); } + } + return item; + } QString Project::get_file_name_from_path(const QString& path) { @@ -700,14 +703,14 @@ void Project::process_file_list(QStringList& files, bool recursive, MediaPtr rep subdir_filenames.append(subdir_files.at(j).filePath()); } - process_file_list(subdir_filenames, true, nullptr, folder.get()); - if (create_undo_action) { ca->append(new AddMediaCommand(folder, parent)); } else { olive::project_model.appendChild(parent, folder); } + process_file_list(subdir_filenames, true, nullptr, folder.get()); + imported = true; } else if (!files.at(i).isEmpty()) { @@ -868,10 +871,10 @@ void Project::process_file_list(QStringList& files, bool recursive, MediaPtr rep if (replace != nullptr) { item = replace; } else { - item = std::make_shared(parent); + item = std::make_shared(); } - m = FootagePtr(new Footage()); + m = std::make_shared(); m->using_inout = false; m->url = file; @@ -886,7 +889,7 @@ void Project::process_file_list(QStringList& files, bool recursive, MediaPtr rep if (create_undo_action) { ca->append(new AddMediaCommand(item, parent)); } else { - parent->appendChild(item); + olive::project_model.appendChild(parent, item); } } diff --git a/project/loadthread.cpp b/project/loadthread.cpp index 052a28406..578ac11c9 100644 --- a/project/loadthread.cpp +++ b/project/loadthread.cpp @@ -283,7 +283,7 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) { int folder = 0; MediaPtr item = std::make_shared(); - FootagePtr f(new Footage()); + FootagePtr f = std::make_shared(); f->using_inout = false; @@ -608,6 +608,22 @@ Media* LoadThread::find_loaded_folder_by_id(int id) { return nullptr; } +void LoadThread::OrganizeFolders(int folder) { + qDebug() << "starting with" << folder; + + for (int i=0;itemp_id2; + + if (parent_id == folder) { + olive::project_model.appendChild(find_loaded_folder_by_id(parent_id), item); + + OrganizeFolders(parent_id); + } + + } +} + void LoadThread::run() { mutex.lock(); @@ -660,15 +676,11 @@ void LoadThread::run() { cont = load_worker(file, stream, MEDIA_TYPE_FOLDER); } - // load media if (cont) { // since folders loaded correctly, organize them appropriately - for (int i=0;itemp_id2; - olive::project_model.appendChild(find_loaded_folder_by_id(parent), folder); - } + OrganizeFolders(); + // load media cont = load_worker(file, stream, MEDIA_TYPE_FOOTAGE); } diff --git a/project/loadthread.h b/project/loadthread.h index be69b9e97..cdf63ae69 100644 --- a/project/loadthread.h +++ b/project/loadthread.h @@ -76,6 +76,7 @@ private: QVector loaded_clips; QVector loaded_sequences; Media* find_loaded_folder_by_id(int id); + void OrganizeFolders(int folder = 0); int current_element_count; int total_element_count; diff --git a/project/media.cpp b/project/media.cpp index 4a1762fac..70d0cb35c 100644 --- a/project/media.cpp +++ b/project/media.cpp @@ -61,10 +61,10 @@ QString get_channel_layout_name(int channels, uint64_t layout) { } } -Media::Media(Media* iparent) { - parent = iparent; - root = false; - type = -1; +Media::Media() : + root(false), + type(-1) +{ } Footage* Media::to_footage() { @@ -341,7 +341,7 @@ QVariant Media::data(int column, int role) { } int Media::row() const { - if (parent) { + if (parent != nullptr) { for (int i=0;ichildren.size();i++) { if (parent->children.at(i).get() == this) { return i; diff --git a/project/media.h b/project/media.h index 77d96519b..05d60bfe4 100644 --- a/project/media.h +++ b/project/media.h @@ -45,7 +45,7 @@ using MediaPtr = std::shared_ptr; class Media { public: - Media(Media* iparent = nullptr); + Media(); Footage *to_footage(); SequencePtr to_sequence(); diff --git a/project/projectfilter.h b/project/projectfilter.h index b03865cc8..7550d5ebc 100644 --- a/project/projectfilter.h +++ b/project/projectfilter.h @@ -24,33 +24,33 @@ #include class ProjectFilter : public QSortFilterProxyModel { - Q_OBJECT + Q_OBJECT public: - ProjectFilter(QObject *parent = nullptr); + ProjectFilter(QObject *parent = nullptr); - // are sequences visible - bool get_show_sequences(); + // are sequences visible + bool get_show_sequences(); public slots: - // set whether sequences are visible - void set_show_sequences(bool b); + // set whether sequences are visible + void set_show_sequences(bool b); - // update search filter - void update_search_filter(const QString& s); + // update search filter + void update_search_filter(const QString& s); protected: - // function that filters whether rows are displayed or not - virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const; + // function that filters whether rows are displayed or not + virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const; private: - // internal variable for whether to show sequences - bool show_sequences; + // internal variable for whether to show sequences + bool show_sequences; - // search filter variable - QString search_filter; + // search filter variable + QString search_filter; }; diff --git a/project/projectmodel.cpp b/project/projectmodel.cpp index 8c4c66f34..80e87c8d0 100644 --- a/project/projectmodel.cpp +++ b/project/projectmodel.cpp @@ -43,8 +43,12 @@ void ProjectModel::make_root() { } void ProjectModel::destroy_root() { - if (panel_sequence_viewer != nullptr) panel_sequence_viewer->viewer_widget->delete_function(); - if (panel_footage_viewer != nullptr) panel_footage_viewer->viewer_widget->delete_function(); + if (panel_sequence_viewer != nullptr) { + panel_sequence_viewer->viewer_widget->delete_function(); + } + if (panel_footage_viewer != nullptr) { + panel_footage_viewer->viewer_widget->delete_function(); + } root_item_ = std::make_shared(); } @@ -64,7 +68,9 @@ QVariant ProjectModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); - return static_cast(index.internalPointer())->data(index.column(), role); + Media* media = static_cast(index.internalPointer()); + + return media->data(index.column(), role); } Qt::ItemFlags ProjectModel::flags(const QModelIndex &index) const { @@ -191,11 +197,20 @@ void ProjectModel::set_icon(Media* m, const QIcon &ico) { } void ProjectModel::appendChild(Media* parent, MediaPtr child) { + QModelIndex row_start; + if (parent == nullptr) { + parent = get_root(); + row_start = QModelIndex(); + + } else { + + row_start = createIndex(parent->row(), 0, parent); + } - beginInsertRows(parent == get_root() ? - QModelIndex() : createIndex(parent->row(), 0, parent), parent->childCount(), parent->childCount()); + + beginInsertRows(row_start, parent->childCount(), parent->childCount()); parent->appendChild(child); endInsertRows(); } diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index 6a53d5ad0..76fc7f584 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -60,8 +60,6 @@ MainWindow* olive::MainWindow; -#define DEFAULT_CSS "QPushButton::checked { background: rgb(25, 25, 25); }" - void MainWindow::setup_layout(bool reset) { // load panels from file if (!reset) { @@ -407,25 +405,66 @@ void MainWindow::Restyle() } else { // set default palette - QPalette darkPalette; - darkPalette.setColor(QPalette::Window, QColor(53,53,53)); - darkPalette.setColor(QPalette::WindowText, Qt::white); - darkPalette.setColor(QPalette::Base, QColor(25,25,25)); - darkPalette.setColor(QPalette::AlternateBase, QColor(53,53,53)); - darkPalette.setColor(QPalette::ToolTipBase, QColor(25,25,25)); - darkPalette.setColor(QPalette::ToolTipText, Qt::white); - darkPalette.setColor(QPalette::Text, Qt::white); - darkPalette.setColor(QPalette::Button, QColor(53,53,53)); - darkPalette.setColor(QPalette::ButtonText, Qt::white); - darkPalette.setColor(QPalette::BrightText, Qt::red); - darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(128, 128, 128)); - darkPalette.setColor(QPalette::Link, QColor(42, 130, 218)); - darkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218)); - darkPalette.setColor(QPalette::HighlightedText, Qt::black); - qApp->setPalette(darkPalette); + QPalette palette; + + if (olive::CurrentConfig.style == olive::styling::kOliveDefaultLight) { + + palette.setColor(QPalette::Window, QColor(208, 208, 208)); + palette.setColor(QPalette::WindowText, Qt::black); + palette.setColor(QPalette::Base, QColor(240, 240, 240)); + palette.setColor(QPalette::AlternateBase, QColor(208, 208, 208)); + palette.setColor(QPalette::ToolTipBase, QColor(255, 255, 255)); + palette.setColor(QPalette::ToolTipText, Qt::black); + palette.setColor(QPalette::Text, Qt::black); + palette.setColor(QPalette::Button, QColor(208, 208, 208)); + palette.setColor(QPalette::ButtonText, Qt::black); + palette.setColor(QPalette::BrightText, Qt::red); + palette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(208, 208, 208)); + palette.setColor(QPalette::Link, QColor(42, 130, 218)); + palette.setColor(QPalette::Highlight, QColor(42, 130, 218)); + palette.setColor(QPalette::HighlightedText, Qt::white); + + /* Olive Mid + palette.setColor(QPalette::Window, QColor(128, 128, 128)); + palette.setColor(QPalette::WindowText, Qt::black); + palette.setColor(QPalette::Base, QColor(192, 192, 192)); + palette.setColor(QPalette::AlternateBase, QColor(128, 128, 128)); + palette.setColor(QPalette::ToolTipBase, QColor(192, 192, 192)); + palette.setColor(QPalette::ToolTipText, Qt::black); + palette.setColor(QPalette::Text, Qt::black); + palette.setColor(QPalette::Button, QColor(128, 128, 128)); + palette.setColor(QPalette::ButtonText, Qt::black); + palette.setColor(QPalette::BrightText, Qt::red); + palette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(128, 128, 128)); + palette.setColor(QPalette::Link, QColor(42, 130, 218)); + palette.setColor(QPalette::Highlight, QColor(42, 130, 218)); + palette.setColor(QPalette::HighlightedText, Qt::black); + */ + + } else { + + palette.setColor(QPalette::Window, QColor(53,53,53)); + palette.setColor(QPalette::WindowText, Qt::white); + palette.setColor(QPalette::Base, QColor(25,25,25)); + palette.setColor(QPalette::AlternateBase, QColor(53,53,53)); + palette.setColor(QPalette::ToolTipBase, QColor(25,25,25)); + palette.setColor(QPalette::ToolTipText, Qt::white); + palette.setColor(QPalette::Text, Qt::white); + palette.setColor(QPalette::Button, QColor(53,53,53)); + palette.setColor(QPalette::ButtonText, Qt::white); + palette.setColor(QPalette::BrightText, Qt::red); + palette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(128, 128, 128)); + palette.setColor(QPalette::Link, QColor(42, 130, 218)); + palette.setColor(QPalette::Highlight, QColor(42, 130, 218)); + palette.setColor(QPalette::HighlightedText, Qt::white); + + // set default CSS + setStyleSheet("QPushButton::checked { background: rgb(25, 25, 25); }"); + + } + + qApp->setPalette(palette); - // set default CSS - setStyleSheet(DEFAULT_CSS); } } } diff --git a/undo/undo.cpp b/undo/undo.cpp index 5b34ffa14..895ec49a9 100644 --- a/undo/undo.cpp +++ b/undo/undo.cpp @@ -316,16 +316,22 @@ void DeleteTransitionCommand::doRedo() { AddMediaCommand::AddMediaCommand(MediaPtr iitem, Media *iparent) : item(iitem), - parent(iparent) + parent(iparent), + done_(false) { + doRedo(); } void AddMediaCommand::doUndo() { olive::project_model.removeChild(parent, item.get()); + done_ = false; } void AddMediaCommand::doRedo() { - olive::project_model.appendChild(parent, item); + if (!done_) { + olive::project_model.appendChild(parent, item); + done_ = true; + } } DeleteMediaCommand::DeleteMediaCommand(MediaPtr i) : diff --git a/undo/undo.h b/undo/undo.h index d55ed478d..b98ce7ea6 100644 --- a/undo/undo.h +++ b/undo/undo.h @@ -213,6 +213,7 @@ public: private: MediaPtr item; Media* parent; + bool done_; }; class DeleteMediaCommand : public OliveAction { From ff6848d1b619f3c805ef9c038e51e79010a06f35 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 22 Mar 2019 02:19:29 +1100 Subject: [PATCH 7/8] fixed #654 --- effects/effect.cpp | 13 ++++++++++++- effects/effect.h | 3 +++ ui/collapsiblewidget.cpp | 11 ++++++++--- ui/collapsiblewidget.h | 3 ++- ui/effectui.cpp | 3 +++ 5 files changed, 28 insertions(+), 5 deletions(-) diff --git a/effects/effect.cpp b/effects/effect.cpp index ec17cb84d..60d09f2a4 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -123,7 +123,8 @@ Effect::Effect(Clip* c, const EffectMeta *em) : isOpen(false), bound(false), iterations(1), - enabled_(true) + enabled_(true), + expanded_(true) { if (em != nullptr) { // set up UI from effect file @@ -508,6 +509,16 @@ bool Effect::IsEnabled() { return enabled_; } +bool Effect::IsExpanded() +{ + return expanded_; +} + +void Effect::SetExpanded(bool e) +{ + expanded_ = e; +} + void Effect::SetEnabled(bool b) { enabled_ = b; emit EnabledChanged(b); diff --git a/effects/effect.h b/effects/effect.h index b9571ea2f..77c42f51b 100644 --- a/effects/effect.h +++ b/effects/effect.h @@ -154,6 +154,7 @@ public: int gizmo_count(); bool IsEnabled(); + bool IsExpanded(); virtual void refresh(); @@ -214,6 +215,7 @@ public: public slots: void FieldChanged(); void SetEnabled(bool b); + void SetExpanded(bool e); signals: void EnabledChanged(bool); private slots: @@ -243,6 +245,7 @@ private: int iterations; bool enabled_; + bool expanded_; int flags_; diff --git a/ui/collapsiblewidget.cpp b/ui/collapsiblewidget.cpp index 21b719018..22dbab99b 100644 --- a/ui/collapsiblewidget.cpp +++ b/ui/collapsiblewidget.cpp @@ -87,6 +87,13 @@ bool CollapsibleWidget::IsExpanded() { return contents->isVisible(); } +void CollapsibleWidget::SetExpanded(bool s) +{ + contents->setVisible(s); + set_button_icon(s); + emit visibleChanged(s); +} + bool CollapsibleWidget::IsSelected() { return selected; @@ -116,9 +123,7 @@ void CollapsibleWidget::SetTitle(const QString &s) { } void CollapsibleWidget::on_visible_change() { - contents->setVisible(!contents->isVisible()); - set_button_icon(contents->isVisible()); - emit visibleChanged(); + SetExpanded(!IsExpanded()); } CollapsibleWidgetHeader::CollapsibleWidgetHeader(QWidget* parent) : QWidget(parent), selected(false) { diff --git a/ui/collapsiblewidget.h b/ui/collapsiblewidget.h index 3cc25c522..cd2153832 100644 --- a/ui/collapsiblewidget.h +++ b/ui/collapsiblewidget.h @@ -52,6 +52,7 @@ public: void SetTitle(const QString &); bool IsFocused(); bool IsExpanded(); + void SetExpanded(bool s); bool IsSelected(); protected: QCheckBox* enabled_check; @@ -68,7 +69,7 @@ private: signals: void deselect_others(QWidget*); - void visibleChanged(); + void visibleChanged(bool); private slots: void on_visible_change(); diff --git a/ui/effectui.cpp b/ui/effectui.cpp index feeb0334b..53da884fc 100644 --- a/ui/effectui.cpp +++ b/ui/effectui.cpp @@ -68,6 +68,9 @@ EffectUI::EffectUI(Effect* e) : QWidget* ui = new QWidget(this); SetContents(ui); + SetExpanded(e->IsExpanded()); + connect(this, SIGNAL(visibleChanged(bool)), e, SLOT(SetExpanded(bool))); + layout_ = new QGridLayout(ui); layout_->setSpacing(4); From b96d97aa07ef86eb5d4620f792c4ef2a9049f2d7 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 22 Mar 2019 02:39:54 +1100 Subject: [PATCH 8/8] further preferences dialog documentation --- dialogs/preferencesdialog.h | 78 ++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/dialogs/preferencesdialog.h b/dialogs/preferencesdialog.h index 6a5bade56..347212f4b 100644 --- a/dialogs/preferencesdialog.h +++ b/dialogs/preferencesdialog.h @@ -62,17 +62,93 @@ private slots: * @brief Override of accept to save preferences to Config. */ virtual void accept() override; + + /** + * @brief Reset all selected shortcuts in keyboard_tree to their defaults + */ void reset_default_shortcut(); + + /** + * @brief Reset all shortcuts indiscriminately to their defaults + * + * This is safe to call directly as it'll ask the user if they wish to do so before it resets. + */ void reset_all_shortcuts(); - bool refine_shortcut_list(const QString &, QTreeWidgetItem* parent = nullptr); + + /** + * @brief Shows/hides shortcut entries according to a shortcut query. + * + * This function can be directly connected to QLineEdit::textChanged() for simplicity. + * + * @param s + * + * The search query to compare shortcut names to. + * + * @param parent + * + * This is used as the function calls itself recursively to traverse the menu item hierarchy. This should be left as + * nullptr when called externally. + * + * @return + * + * Value used as function calls itself recursively to determine if a menu parent has any children that are not hidden. + * If so, TRUE is returned so the parent is shown too (even if it doesn't match the search query). If not, FALSE is + * returned so the parent is hidden. + */ + bool refine_shortcut_list(const QString &s, QTreeWidgetItem* parent = nullptr); + + /** + * @brief Show a file dialog to load an external shortcut preset from file + */ void load_shortcut_file(); + + /** + * @brief Show a file dialog to save an external shortcut preset from file + */ void save_shortcut_file(); + + /** + * @brief Show a file dialog to browse for an external CSS file to load for styling the application. + */ void browse_css_file(); + + /** + * @brief Delete all previews (waveform and thumbnail cache) + */ void delete_all_previews(); private: + + /** + * @brief Create and arrange all UI widgets + */ void setup_ui(); + + /** + * @brief Populate keyboard shortcut panel with keyboard shortcuts from the menu bar + * + * @param menu + * + * A reference to the main application's menu bar. Usually MainWindow::menuBar(). + */ void setup_kbd_shortcuts(QMenuBar* menu); + + /** + * @brief Internal function called by setup_kbd_shortcuts() to traverse down the menu bar's hierarchy and populate the + * shortcut panel. + * + * This function will call itself recursively as it finds submenus belong to the menu provided. It will also create + * QTreeWidgetItems as children of the parent item provided, either using them as parents themselves for submenus + * or attaching a KeySequenceEditor to them for shortcut editing. + * + * @param menu + * + * The current menu to traverse down. + * + * @param parent + * + * The parent item to add QTreeWidgetItems to. + */ void setup_kbd_shortcut_worker(QMenu* menu, QTreeWidgetItem* parent); // used to delete previews