diff --git a/dialogs/advancedvideodialog.cpp b/dialogs/advancedvideodialog.cpp index 757d3da8f..91a0428e2 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 249134b51..122812f56 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 7fa0b460e..051befafa 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 2c0ddfad7..66de17963 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 dc4127cda..198ca3651 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...")); @@ -45,36 +45,19 @@ LoadDialog::LoadDialog(QWidget *parent, const QString& fn, bool autorecovery, bo bar->setValue(0); layout->addWidget(bar); - cancel_button = new QPushButton(tr("Cancel"), this); - connect(cancel_button, SIGNAL(clicked(bool)), this, SLOT(cancel())); + 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(); 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(); +void LoadDialog::setValue(int i) +{ + bar->setValue(i); } diff --git a/dialogs/loaddialog.h b/dialogs/loaddialog.h index 96bb9ef1a..0638c682b 100644 --- a/dialogs/loaddialog.h +++ b/dialogs/loaddialog.h @@ -28,20 +28,47 @@ #include "project/projectelements.h" #include "project/loadthread.h" +/** + * @brief The LoadDialog class + * + * Shows a modal dialog for loading a project. Designed to be connected to a LoadThread object. + */ 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. + */ + LoadDialog(QWidget* parent); + +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(); - void die(); - void thread_done(); private: + /** + * @brief Progress bar widget + */ QProgressBar* bar; - QPushButton* cancel_button; - QHBoxLayout* hboxLayout; - LoadThread* lt; }; #endif // LOADDIALOG_H diff --git a/dialogs/mediapropertiesdialog.h b/dialogs/mediapropertiesdialog.h index c153e826a..330192cb3 100644 --- a/dialogs/mediapropertiesdialog.h +++ b/dialogs/mediapropertiesdialog.h @@ -31,19 +31,62 @@ #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 public: + /** + * @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: + /** + * @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; + QComboBox* color_management; private slots: + /** + * @brief Overrided accept function for saving the properties back to the Media class + */ void accept(); }; diff --git a/dialogs/newsequencedialog.cpp b/dialogs/newsequencedialog.cpp index dfe53177b..8f6c18621 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) { @@ -280,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/newsequencedialog.h b/dialogs/newsequencedialog.h index 7b456db80..b5e5f6709 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; }; diff --git a/dialogs/preferencesdialog.cpp b/dialogs/preferencesdialog.cpp index 10f336829..d2db861b2 100644 --- a/dialogs/preferencesdialog.cpp +++ b/dialogs/preferencesdialog.cpp @@ -83,9 +83,12 @@ PreferencesDialog::PreferencesDialog(QWidget *parent) : { setWindowTitle(tr("Preferences")); setup_ui(); -} -PreferencesDialog::~PreferencesDialog() {} + recordingComboBox->setCurrentIndex(olive::CurrentConfig.recording_mode - 1); + imgSeqFormatEdit->setText(olive::CurrentConfig.img_seq_formats); + + setup_kbd_shortcuts(olive::MainWindow->menuBar()); +} void PreferencesDialog::setup_kbd_shortcut_worker(QMenu* menu, QTreeWidgetItem* parent) { QList actions = menu->actions(); @@ -255,7 +258,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; @@ -448,7 +451,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) @@ -1025,6 +1028,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/dialogs/preferencesdialog.h b/dialogs/preferencesdialog.h index 437ec28ac..da03290ed 100644 --- a/dialogs/preferencesdialog.h +++ b/dialogs/preferencesdialog.h @@ -40,38 +40,86 @@ namespace OCIO = OCIO_NAMESPACE::v1; #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; + + /** + * @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 Delete all previews (waveform and thumbnail cache) + */ void delete_all_previews(); // Browse for file functionns + /** + * @brief Show a file dialog to browse for an external CSS file to load for styling the application. + */ void browse_css_file(); void browse_ocio_config(); @@ -83,7 +131,37 @@ private slots: #endif 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); enum PreviewDeleteTypes { @@ -143,4 +221,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/effects/effect.cpp b/effects/effect.cpp index b58f42a91..77ae3b223 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -122,7 +122,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 @@ -507,6 +508,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); @@ -895,15 +906,30 @@ GLuint Effect::process_superimpose(double timecode) { tex_width_ = img.width(); tex_height_ = img.height(); + // create texture object + f->glGenTextures(1, &texture); + + f->glBindTexture(GL_TEXTURE_2D, texture); + + // set texture filtering to bilinear + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + f->glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, tex_width_, tex_height_, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.constBits() ); + f->glBindTexture(GL_TEXTURE_2D, 0); + redrew_image = false; } if (redrew_image) { + f->glBindTexture(GL_TEXTURE_2D, texture); + f->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_width_, tex_height_, GL_RGBA, GL_UNSIGNED_BYTE, img.constBits()); + + f->glBindTexture(GL_TEXTURE_2D, 0); } return texture; diff --git a/effects/effect.h b/effects/effect.h index e9bf5c00c..71d456589 100644 --- a/effects/effect.h +++ b/effects/effect.h @@ -153,6 +153,7 @@ public: int gizmo_count(); bool IsEnabled(); + bool IsExpanded(); virtual void refresh(); @@ -212,6 +213,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/global/global.cpp b/global/global.cpp index e7d89af22..1ca317fec 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, 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"), @@ -308,7 +344,6 @@ void OliveGlobal::open_preferences() { panel_footage_viewer->pause(); PreferencesDialog pd(olive::MainWindow); - pd.setup_kbd_shortcuts(olive::MainWindow->menuBar()); pd.exec(); } @@ -323,9 +358,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 6cbe2d0e9..af44a786a 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/effectcontrols.cpp b/panels/effectcontrols.cpp index f03930ee1..d83e6639d 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -46,6 +46,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" @@ -374,8 +375,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 13b031f31..0898f3fb7 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(); @@ -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()) { @@ -724,7 +727,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); } @@ -868,7 +871,7 @@ 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 = std::make_shared(); @@ -891,7 +894,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); } } @@ -1046,27 +1049,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 753b46908..fab8bccf1 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.cpp b/project/loadthread.cpp index 0269f0734..e4ce8665f 100644 --- a/project/loadthread.cpp +++ b/project/loadthread.cpp @@ -605,6 +605,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(); @@ -657,15 +673,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 5bb8d43f6..cf8445dc1 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); @@ -75,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 2fbce1165..847ed2a56 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 85fa14528..e56ac34b8 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 2fbfad9e4..40eee7b0a 100644 --- a/project/projectfilter.h +++ b/project/projectfilter.h @@ -28,29 +28,29 @@ class ProjectFilter : public QSortFilterProxyModel { public: ProjectFilter(QObject *parent = nullptr); - // are sequences visible + // are sequences visible bool get_show_sequences(); public slots: - // set whether sequences are visible + // 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 + // 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 ab09e2da2..a0282de90 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/project/sourcescommon.cpp b/project/sourcescommon.cpp index 190c26bae..46c8e1dea 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( diff --git a/ui/collapsiblewidget.cpp b/ui/collapsiblewidget.cpp index f71073b6b..078ef0ef5 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 277e3409e..3ef0657ad 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 e26a35c4c..bc790a67c 100644 --- a/ui/effectui.cpp +++ b/ui/effectui.cpp @@ -88,6 +88,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); diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index ed7516040..8da6a4ee8 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -61,8 +61,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) { @@ -424,25 +422,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); } } } @@ -470,7 +509,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); diff --git a/undo/undo.cpp b/undo/undo.cpp index 67a7edcec..ba073b3fa 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 da8fa46b2..3e05dc1b7 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 {