From 56e3fd41e5c7d30281896bebca458160afd1256f Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 26 Sep 2019 03:49:49 +1000 Subject: [PATCH] various UI reimplementations from 0.1.x --- app/common/filefunctions.cpp | 20 + app/common/filefunctions.h | 6 + app/common/timecodefunctions.cpp | 7 + app/common/timecodefunctions.h | 2 + app/config/CMakeLists.txt | 1 + app/config/config.cpp | 152 +++ app/config/config.h | 30 +- app/core.cpp | 17 +- app/core.h | 5 + app/dialog/CMakeLists.txt | 1 + app/dialog/preferences/CMakeLists.txt | 26 + app/dialog/preferences/keysequenceeditor.cpp | 48 + app/dialog/preferences/keysequenceeditor.h | 100 ++ app/dialog/preferences/preferences.cpp | 951 +----------------- app/dialog/preferences/preferences.h | 340 +------ app/dialog/preferences/tabs/CMakeLists.txt | 36 + .../tabs/preferencesappearancetab.cpp | 51 + .../tabs/preferencesappearancetab.h | 37 + .../preferences/tabs/preferencesaudiotab.cpp | 93 ++ .../preferences/tabs/preferencesaudiotab.h | 39 + .../tabs/preferencesbehaviortab.cpp | 47 + .../preferences/tabs/preferencesbehaviortab.h | 22 + .../tabs/preferencescolormanagementtab.cpp | 213 ++++ .../tabs/preferencescolormanagementtab.h | 52 + .../tabs/preferencesgeneraltab.cpp | 110 ++ .../preferences/tabs/preferencesgeneraltab.h | 41 + .../tabs/preferenceskeyboardtab.cpp | 214 ++++ .../preferences/tabs/preferenceskeyboardtab.h | 115 +++ .../tabs/preferencesplaybacktab.cpp | 14 + .../preferences/tabs/preferencesplaybacktab.h | 20 + .../preferences/tabs/preferencestab.cpp | 6 + app/dialog/preferences/tabs/preferencestab.h | 16 + app/main.cpp | 2 + app/project/item/folder/folder.cpp | 6 +- app/project/item/folder/folder.h | 2 + app/project/item/footage/footage.cpp | 69 +- app/project/item/footage/footage.h | 2 + app/project/item/item.cpp | 10 - app/project/item/item.h | 5 +- app/project/item/sequence/sequence.cpp | 6 +- app/project/item/sequence/sequence.h | 2 + app/ui/icons/icons.cpp | 2 +- app/ui/style/olive-dark/olive-dark.qrc | 1 + app/ui/style/olive-dark/palette.ini | 18 + app/ui/style/olive-dark/style.css | 50 - app/ui/style/olive-light/olive-light.qrc | 1 + app/ui/style/olive-light/palette.ini | 17 + app/ui/style/olive-light/style.css | 50 - app/ui/style/style.cpp | 142 ++- app/ui/style/style.h | 42 +- app/widget/CMakeLists.txt | 1 + app/widget/columnedgridlayout/CMakeLists.txt | 22 + .../columnedgridlayout/columnedgridlayout.cpp | 34 + .../columnedgridlayout/columnedgridlayout.h | 27 + .../playbackcontrols/playbackcontrols.cpp | 57 +- .../playbackcontrols/playbackcontrols.h | 9 + .../projectexplorernavigation.cpp | 15 +- .../projectexplorernavigation.h | 2 + app/widget/projecttoolbar/projecttoolbar.cpp | 23 +- app/widget/projecttoolbar/projecttoolbar.h | 1 + app/widget/timelineview/timelineview.cpp | 1 + app/widget/timelineview/tool/import.cpp | 4 +- app/widget/timelineview/tool/pointer.cpp | 2 +- app/widget/timelineview/tool/slip.cpp | 2 +- app/widget/timeruler/timeruler.cpp | 4 +- app/widget/toolbar/toolbar.cpp | 54 +- app/widget/toolbar/toolbar.h | 9 +- app/widget/toolbar/toolbarbutton.cpp | 3 +- app/widget/toolbar/toolbarbutton.h | 6 +- app/window/mainwindow/mainmenu.cpp | 4 +- 70 files changed, 2056 insertions(+), 1483 deletions(-) create mode 100644 app/config/config.cpp create mode 100644 app/dialog/preferences/CMakeLists.txt create mode 100644 app/dialog/preferences/keysequenceeditor.cpp create mode 100644 app/dialog/preferences/keysequenceeditor.h create mode 100644 app/dialog/preferences/tabs/CMakeLists.txt create mode 100644 app/dialog/preferences/tabs/preferencesappearancetab.cpp create mode 100644 app/dialog/preferences/tabs/preferencesappearancetab.h create mode 100644 app/dialog/preferences/tabs/preferencesaudiotab.cpp create mode 100644 app/dialog/preferences/tabs/preferencesaudiotab.h create mode 100644 app/dialog/preferences/tabs/preferencesbehaviortab.cpp create mode 100644 app/dialog/preferences/tabs/preferencesbehaviortab.h create mode 100644 app/dialog/preferences/tabs/preferencescolormanagementtab.cpp create mode 100644 app/dialog/preferences/tabs/preferencescolormanagementtab.h create mode 100644 app/dialog/preferences/tabs/preferencesgeneraltab.cpp create mode 100644 app/dialog/preferences/tabs/preferencesgeneraltab.h create mode 100644 app/dialog/preferences/tabs/preferenceskeyboardtab.cpp create mode 100644 app/dialog/preferences/tabs/preferenceskeyboardtab.h create mode 100644 app/dialog/preferences/tabs/preferencesplaybacktab.cpp create mode 100644 app/dialog/preferences/tabs/preferencesplaybacktab.h create mode 100644 app/dialog/preferences/tabs/preferencestab.cpp create mode 100644 app/dialog/preferences/tabs/preferencestab.h create mode 100644 app/ui/style/olive-dark/palette.ini create mode 100644 app/ui/style/olive-light/palette.ini create mode 100644 app/widget/columnedgridlayout/CMakeLists.txt create mode 100644 app/widget/columnedgridlayout/columnedgridlayout.cpp create mode 100644 app/widget/columnedgridlayout/columnedgridlayout.h diff --git a/app/common/filefunctions.cpp b/app/common/filefunctions.cpp index 3ce46dace..9678da570 100644 --- a/app/common/filefunctions.cpp +++ b/app/common/filefunctions.cpp @@ -20,6 +20,7 @@ #include "filefunctions.h" +#include #include #include #include @@ -73,3 +74,22 @@ QString GetMediaCacheLocation() return media_cache_dir.absolutePath(); } + +QString GetConfigurationLocation() +{ + if (IsPortable()) { + return GetApplicationPath(); + } else { + return QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation); + } +} + +bool IsPortable() +{ + return QFileInfo::exists(QDir(GetApplicationPath()).filePath("portable")); +} + +QString GetApplicationPath() +{ + return QCoreApplication::applicationDirPath(); +} diff --git a/app/common/filefunctions.h b/app/common/filefunctions.h index f6b990555..d1f79abf9 100644 --- a/app/common/filefunctions.h +++ b/app/common/filefunctions.h @@ -23,6 +23,8 @@ #include +bool IsPortable(); + QString GetUniqueFileIdentifier(const QString& filename); QString GetMediaIndexLocation(); @@ -31,4 +33,8 @@ QString GetMediaIndexFilename(const QString& filename); QString GetMediaCacheLocation(); +QString GetConfigurationLocation(); + +QString GetApplicationPath(); + #endif // FILEFUNCTIONS_H diff --git a/app/common/timecodefunctions.cpp b/app/common/timecodefunctions.cpp index 1a4037e6f..5bed5ab3a 100644 --- a/app/common/timecodefunctions.cpp +++ b/app/common/timecodefunctions.cpp @@ -22,6 +22,8 @@ #include +#include "config/config.h" + QString padded(int arg, int padding) { return QString("%1").arg(arg, padding, 10, QChar('0')); } @@ -91,3 +93,8 @@ int64_t olive::time_to_timestamp(const rational &time, const rational &timebase) { return qRound64(time.toDouble() * timebase.flipped().toDouble()); } + +olive::TimecodeDisplay olive::CurrentTimecodeDisplay() +{ + return static_cast(Config::Current()["TimecodeDisplay"].toInt()); +} diff --git a/app/common/timecodefunctions.h b/app/common/timecodefunctions.h index 4afa189c1..4dcd2344f 100644 --- a/app/common/timecodefunctions.h +++ b/app/common/timecodefunctions.h @@ -34,6 +34,8 @@ enum TimecodeDisplay { kMilliseconds }; +TimecodeDisplay CurrentTimecodeDisplay(); + /** * @brief Convert a timestamp (according to a rational timebase) to a user-friendly string representation */ diff --git a/app/config/CMakeLists.txt b/app/config/CMakeLists.txt index 11783b764..755e1d3dd 100644 --- a/app/config/CMakeLists.txt +++ b/app/config/CMakeLists.txt @@ -17,5 +17,6 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} config/config.h + config/config.cpp PARENT_SCOPE ) diff --git a/app/config/config.cpp b/app/config/config.cpp new file mode 100644 index 000000000..e5d89b8bc --- /dev/null +++ b/app/config/config.cpp @@ -0,0 +1,152 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "core.h" +#include "common/filefunctions.h" + +Config Config::current_config_; + +Config::Config() +{ + SetDefaults(); +} + +QString Config::GetConfigFilePath() +{ + return QDir(GetConfigurationLocation()).filePath("config.xml"); +} + +Config &Config::Current() +{ + return current_config_; +} + +void Config::SetDefaults() +{ + config_map_.clear(); + config_map_["TimecodeDisplay"] = olive::kTimecodeFrames; + config_map_["DefaultStillLength"] = QVariant::fromValue(rational(2)); +} + +void Config::Load() +{ + QFile config_file(GetConfigFilePath()); + + if (!config_file.exists()) { + return; + } + + if (!config_file.open(QFile::ReadOnly)) { + qWarning() << QCoreApplication::translate("Config", "Failed to load application settings. This session will use " + "defaults."); + return; + } + + // Reset to defaults + current_config_.SetDefaults(); + + QXmlStreamReader reader(&config_file); + while (!reader.atEnd()) { + reader.readNext(); + + if (!reader.isStartElement()) { + continue; + } + + QString key = reader.name().toString(); + + reader.readNext(); + QString value = reader.text().toString(); + + if (key == "Configuration") { + // First element, ignore + } else if (key == "Version") { + if (!value.contains(".")) { + qDebug() << "This is a 0.1.x config file, upconvert"; + } + } else { + current_config_[key] = value; + } + } + + if (reader.hasError()) { + QMessageBox::critical(olive::core.main_window(), + QCoreApplication::translate("Config", "Error loading settings"), + QCoreApplication::translate("Config", "Failed to load application settings. This session will " + "use defaults."), + QMessageBox::Ok); + current_config_.SetDefaults(); + } + + config_file.close(); +} + +void Config::Save() +{ + QFile config_file(GetConfigFilePath()); + + if (!config_file.open(QFile::WriteOnly)) { + QMessageBox::critical(olive::core.main_window(), + QCoreApplication::translate("Config", "Error saving settings"), + QCoreApplication::translate("Config", "Failed to save application settings. The application " + "may lack write permissions to this location."), + QMessageBox::Ok); + return; + } + + QXmlStreamWriter writer(&config_file); + + writer.writeStartDocument(); + + writer.writeStartElement("Configuration"); + + // Anything after the hyphen is considered "unimportant" information + writer.writeTextElement("Version", QCoreApplication::applicationVersion().split('-').first()); + + QMapIterator iterator(current_config_.config_map_); + while (iterator.hasNext()) { + iterator.next(); + writer.writeTextElement(iterator.key(), iterator.value().toString()); + } + + writer.writeEndElement(); // Configuration + + writer.writeEndDocument(); + + config_file.close(); +} + +QVariant Config::operator[](const QString &key) const +{ + return config_map_[key]; +} + +QVariant &Config::operator[](const QString &key) +{ + return config_map_[key]; +} diff --git a/app/config/config.h b/app/config/config.h index d04c7a534..d7e99eadd 100644 --- a/app/config/config.h +++ b/app/config/config.h @@ -21,14 +21,34 @@ #ifndef CONFIG_H #define CONFIG_H +#include +#include +#include + #include "common/timecodefunctions.h" -/** - * @brief Temporary variables that will definitely be configurable but aren't yet - */ +class Config { +public: + static Config& Current(); -const olive::TimecodeDisplay kTimecodeDisplay = olive::kTimecodeFrames; + void SetDefaults(); -const rational kDefaultImageLength = 2; + static void Load(); + + static void Save(); + + QVariant operator[](const QString&) const; + + QVariant& operator[](const QString&); + +private: + Config(); + + QMap config_map_; + + static Config current_config_; + + static QString GetConfigFilePath(); +}; #endif // CONFIG_H diff --git a/app/core.cpp b/app/core.cpp index b4b3c0415..d4f735110 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -25,11 +25,14 @@ #include #include #include -#include #include +#include +#include +#include "config/config.h" #include "dialog/about/about.h" #include "dialog/sequence/sequence.h" +#include "dialog/preferences/preferences.h" #include "panel/panelmanager.h" #include "panel/project/project.h" #include "project/item/footage/footage.h" @@ -85,6 +88,9 @@ void Core::Start() // Declare custom types for Qt signal/slot syste DeclareTypesForQt(); + // Load application config + Config::Load(); + // // Start GUI (FIXME CLI mode) @@ -193,6 +199,12 @@ void Core::DialogImportShow() } } +void Core::DialogPreferencesShow() +{ + PreferencesDialog pd(main_window_, main_window_->menuBar()); + pd.exec(); +} + void Core::CreateNewFolder() { // Locate the most recently focused Project panel (assume that's the panel the user wants to import into) @@ -344,7 +356,8 @@ void Core::DeclareTypesForQt() void Core::StartGUI(bool full_screen) { // Set UI style - olive::style::AppSetDefault(); + qApp->setStyle(QStyleFactory::create("Fusion")); + StyleManager::SetStyle(StyleManager::DefaultStyle()); // Set up shared menus olive::menu_shared.Initialize(); diff --git a/app/core.h b/app/core.h index 769c557a7..88e1e0593 100644 --- a/app/core.h +++ b/app/core.h @@ -124,6 +124,11 @@ public slots: */ void DialogImportShow(); + /** + * @brief Show Preferences dialog + */ + void DialogPreferencesShow(); + /** * @brief Create a new folder in the currently active project */ diff --git a/app/dialog/CMakeLists.txt b/app/dialog/CMakeLists.txt index 010e47f7a..4c13cbc0c 100644 --- a/app/dialog/CMakeLists.txt +++ b/app/dialog/CMakeLists.txt @@ -16,6 +16,7 @@ add_subdirectory(about) add_subdirectory(actionsearch) +add_subdirectory(preferences) add_subdirectory(sequence) set(OLIVE_SOURCES diff --git a/app/dialog/preferences/CMakeLists.txt b/app/dialog/preferences/CMakeLists.txt new file mode 100644 index 000000000..82201b179 --- /dev/null +++ b/app/dialog/preferences/CMakeLists.txt @@ -0,0 +1,26 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2019 Olive Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +add_subdirectory(tabs) + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + dialog/preferences/keysequenceeditor.h + dialog/preferences/keysequenceeditor.cpp + dialog/preferences/preferences.h + dialog/preferences/preferences.cpp + PARENT_SCOPE +) diff --git a/app/dialog/preferences/keysequenceeditor.cpp b/app/dialog/preferences/keysequenceeditor.cpp new file mode 100644 index 000000000..92d4dea8f --- /dev/null +++ b/app/dialog/preferences/keysequenceeditor.cpp @@ -0,0 +1,48 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#include "keysequenceeditor.h" + +#include + +KeySequenceEditor::KeySequenceEditor(QWidget* parent, QAction* a) + : QKeySequenceEdit(parent), action(a) { + setKeySequence(action->shortcut()); +} + +void KeySequenceEditor::set_action_shortcut() { + action->setShortcut(keySequence()); +} + +void KeySequenceEditor::reset_to_default() { + setKeySequence(action->property("default").toString()); +} + +QString KeySequenceEditor::action_name() { + return action->property("id").toString(); +} + +QString KeySequenceEditor::export_shortcut() { + QString ks = keySequence().toString(); + if (ks != action->property("default")) { + return action->property("id").toString() + "\t" + ks; + } + return nullptr; +} diff --git a/app/dialog/preferences/keysequenceeditor.h b/app/dialog/preferences/keysequenceeditor.h new file mode 100644 index 000000000..bda946137 --- /dev/null +++ b/app/dialog/preferences/keysequenceeditor.h @@ -0,0 +1,100 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#ifndef KEYSEQUENCEEDITOR_H +#define KEYSEQUENCEEDITOR_H + +#include + +/** + * @brief The KeySequenceEditor class + * + * Simple derived class of QKeySequenceEdit that attaches to a QAction and provides functions for transferring + * keyboard shortcuts to and from it. + */ +class KeySequenceEditor : public QKeySequenceEdit { + Q_OBJECT +public: + /** + * @brief KeySequenceEditor Constructor + * + * @param parent + * + * QWidget parent. + * + * @param a + * + * The QAction to link to. This cannot be changed throughout the lifetime of a KeySequenceEditor. + */ + KeySequenceEditor(QWidget *parent, QAction* a); + + /** + * @brief Sets the attached QAction's shortcut to the shortcut entered in this field. + * + * This is not done automatically in case the user cancels out of the Preferences dialog, in which case the + * expectation is that the changes made will not be saved. Therefore, this needs to be triggered manually when + * PreferencesDialog saves. + */ + void set_action_shortcut(); + + /** + * @brief Set this shortcut back to the QAction's default shortcut + * + * Each QAction contains the default shortcut in its `property("default")` and can be used to restore the default + * "hard-coded" shortcut with this function. + * + * This function does not save the default shortcut back into the QAction, it simply loads the default shortcut from + * the QAction into this edit field. To save it into the QAction, it's necessary to call set_action_shortcut() after + * calling this function. + */ + void reset_to_default(); + + /** + * @brief Return attached QAction's unique ID + * + * Each of Olive's menu actions has a unique string ID (that, unlike the text, is not translated) for matching with + * an external shortcut configuration file. The ID is stored in the QAction's `property("id")`. This function returns + * that ID. + * + * @return + * + * The QAction's unique ID. + */ + QString action_name(); + + /** + * @brief Serialize this shortcut entry into a string that can be saved to a file + * + * @return + * + * A string serialization of this shortcut. The format is "[ID]\t[SEQUENCE]" where [ID] is the attached QAction's + * unique identifier and [SEQUENCE] is the current keyboard shortcut in the field (NOT necessarily the shortcut in + * the QAction). If the entered shortcut is the same as the QAction's default shortcut, the return value is empty + * because a default shortcut does not need to be saved to a file. + */ + QString export_shortcut(); +private: + /** + * @brief Internal reference to the linked QAction + */ + QAction* action; +}; + +#endif // KEYSEQUENCEEDITOR_H diff --git a/app/dialog/preferences/preferences.cpp b/app/dialog/preferences/preferences.cpp index 81eacefb3..8848210ec 100644 --- a/app/dialog/preferences/preferences.cpp +++ b/app/dialog/preferences/preferences.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2019 Olive Team This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,265 +18,54 @@ ***/ -#include "preferencesdialog.h" +#include "preferences.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include -#include "global/global.h" -#include "global/config.h" -#include "global/path.h" -#include "rendering/audio.h" -#include "rendering/pixelformats.h" -#include "panels/panels.h" -#include "ui/columnedgridlayout.h" -#include "ui/mainwindow.h" -#include "dialogs/newsequencedialog.h" +#include "config/config.h" +#include "tabs/preferencesgeneraltab.h" +#include "tabs/preferencesbehaviortab.h" +#include "tabs/preferencesappearancetab.h" +#include "tabs/preferencesplaybacktab.h" +#include "tabs/preferencesaudiotab.h" +#include "tabs/preferencescolormanagementtab.h" +#include "tabs/preferenceskeyboardtab.h" -KeySequenceEditor::KeySequenceEditor(QWidget* parent, QAction* a) - : QKeySequenceEdit(parent), action(a) { - setKeySequence(action->shortcut()); -} - -void KeySequenceEditor::set_action_shortcut() { - action->setShortcut(keySequence()); -} - -void KeySequenceEditor::reset_to_default() { - setKeySequence(action->property("default").toString()); -} - -QString KeySequenceEditor::action_name() { - return action->property("id").toString(); -} - -QString KeySequenceEditor::export_shortcut() { - QString ks = keySequence().toString(); - if (ks != action->property("default")) { - return action->property("id").toString() + "\t" + ks; - } - return nullptr; -} - -PreferencesDialog::PreferencesDialog(QWidget *parent) : +PreferencesDialog::PreferencesDialog(QWidget *parent, QMenuBar* main_menu_bar) : QDialog(parent) { setWindowTitle(tr("Preferences")); - setup_ui(); + QVBoxLayout* verticalLayout = new QVBoxLayout(this); + tab_widget_ = new QTabWidget(this); - setup_kbd_shortcuts(olive::MainWindow->menuBar()); + AddTab(new PreferencesGeneralTab(), tr("General")); + AddTab(new PreferencesAppearanceTab(), tr("Appearance")); + AddTab(new PreferencesBehaviorTab(), tr("Behavior")); + AddTab(new PreferencesColorManagementTab(), tr("Color Management")); + AddTab(new PreferencesPlaybackTab(), tr("Playback")); + AddTab(new PreferencesAudioTab(), tr("Audio")); + AddTab(new PreferencesKeyboardTab(main_menu_bar), tr("Keyboard")); + + verticalLayout->addWidget(tab_widget_); + + QDialogButtonBox* buttonBox = new QDialogButtonBox(this); + buttonBox->setOrientation(Qt::Horizontal); + buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); + + verticalLayout->addWidget(buttonBox); + + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); // set up default sequence - default_sequence.set_name(tr("Default Sequence")); + /*default_sequence.set_name(tr("Default Sequence")); default_sequence.set_width(olive::config.default_sequence_width); default_sequence.set_height(olive::config.default_sequence_height); default_sequence.set_frame_rate(olive::config.default_sequence_framerate); default_sequence.set_audio_frequency(olive::config.default_sequence_audio_frequency); - default_sequence.set_audio_layout(olive::config.default_sequence_audio_channel_layout); -} - -void PreferencesDialog::setup_kbd_shortcut_worker(QMenu* menu, QTreeWidgetItem* parent) { - QList actions = menu->actions(); - for (int i=0;iisSeparator() && a->property("keyignore").isNull()) { - QTreeWidgetItem* item = new QTreeWidgetItem(parent); - item->setText(0, a->text().replace("&", "")); - - parent->addChild(item); - - if (a->menu() != nullptr) { - item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); - setup_kbd_shortcut_worker(a->menu(), item); - } else { - key_shortcut_items.append(item); - key_shortcut_actions.append(a); - } - } - } -} - -void PreferencesDialog::delete_previews(PreviewDeleteTypes type) { - char delete_char = 0; - - switch (type) { - case DELETE_WAVEFORMS: - delete_char = 'w'; - break; - case DELETE_THUMBNAILS: - delete_char = 't'; - break; - case DELETE_BOTH: - delete_char = 1; - break; - case DELETE_NONE: - break; - } - - if (delete_char != 't' && delete_char != 'w' && delete_char != 1) return; - - QDir preview_path(get_data_path() + "/previews"); - - if (delete_char == 1) { - // indiscriminately delete everything - preview_path.removeRecursively(); - } else { - QStringList preview_file_list = preview_path.entryList(QDir::Files | QDir::NoDotAndDotDot); - for (int i=0;i= 0 - && preview_file_str.at(identifier_char_index) >= 48 - && preview_file_str.at(identifier_char_index) <= 57) { - identifier_char_index--; - } - - // thumbnails will have a 't' towards the end of the filenames, waveforms will have a 'w' - // if they match the type of preview we're deleting, remove them - if (preview_file_str.at(identifier_char_index) == delete_char) { - QFile::remove(preview_path.filePath(preview_file_str)); - } - } - } -} - -void PreferencesDialog::populate_ocio_menus(OCIO::ConstConfigRcPtr config) -{ - if (!config) { - - // Just clear everything - ocio_display->clear(); - ocio_default_input->clear(); - ocio_view->clear(); - ocio_look->clear(); - - } else { - - // Get input color spaces for setting the default input color space - ocio_default_input->clear(); - for (int i=0;igetNumColorSpaces();i++) { - QString colorspace = config->getColorSpaceNameByIndex(i); - - ocio_default_input->addItem(colorspace); - - if (colorspace == olive::config.ocio_default_input_colorspace) { - ocio_default_input->setCurrentIndex(i); - } - } - - // Get current display name (if the config is empty, get the current default display) - QString current_display = olive::config.ocio_display; - if (current_display.isEmpty()) { - current_display = config->getDefaultDisplay(); - } - - // Populate the display menu - ocio_display->clear(); - for (int i=0;igetNumDisplays();i++) { - ocio_display->addItem(config->getDisplay(i)); - - // Check if this index is the currently selected - if (config->getDisplay(i) == current_display) { - ocio_display->setCurrentIndex(i); - } - } - - update_ocio_view_menu(config); - - // Populate the look menu - ocio_look->clear(); - ocio_look->addItem(tr("(None)"), QString()); - for (int i=0;igetNumLooks();i++) { - const char* look = config->getLookNameByIndex(i); - - ocio_look->addItem(look, look); - - if (look == olive::config.ocio_look) { - ocio_look->setCurrentIndex(i+1); - } - } - - } -} - -OCIO::ConstConfigRcPtr PreferencesDialog::TestOCIOConfig(const QString &url) -{ - // Check whether OCIO can load it - OCIO::ConstConfigRcPtr config; - try { - config = OCIO::Config::CreateFromFile(url.toUtf8()); - } catch (OCIO::Exception& e) { - QMessageBox::critical(this, - tr("OpenColorIO Config Error"), - tr("Failed to set OpenColorIO configuration: %1").arg(e.what()), - QMessageBox::Ok); - } - return config; -} - -void PreferencesDialog::update_ocio_view_menu(OCIO::ConstConfigRcPtr config) -{ - - // Get views for the current display set in `ocio_display` - QString display = ocio_display->currentText(); - - // Get current view - QString current_view = olive::config.ocio_view; - if (current_view.isEmpty()) { - current_view = config->getDefaultView(display.toUtf8()); - } - - // Populate the view menu - int ocio_view_count = config->getNumViews(display.toUtf8()); - ocio_view->clear(); - for (int i=0;igetView(display.toUtf8(), i); - - ocio_view->addItem(view); - - if (current_view == view) { - ocio_view->setCurrentIndex(i); - } - } -} - -void PreferencesDialog::update_ocio_config(const QString &s) -{ - OCIO::ConstConfigRcPtr file_config; - - if (!s.isEmpty() && QFileInfo::exists(s)) { - file_config = TestOCIOConfig(s); - } - - populate_ocio_menus(file_config); + default_sequence.set_audio_layout(olive::config.default_sequence_audio_channel_layout);*/ } void PreferencesDialog::AddBoolPair(QCheckBox *ui, bool *value, bool restart_required) @@ -288,30 +77,15 @@ void PreferencesDialog::AddBoolPair(QCheckBox *ui, bool *value, bool restart_req ui->setChecked(*value); } -void PreferencesDialog::setup_kbd_shortcuts(QMenuBar* menubar) { - QList menus = menubar->actions(); - - for (int i=0;imenu(); - - QTreeWidgetItem* item = new QTreeWidgetItem(keyboard_tree); - item->setText(0, menu->title().replace("&", "")); - - keyboard_tree->addTopLevelItem(item); - - setup_kbd_shortcut_worker(menu, item); +void PreferencesDialog::accept() +{ + foreach (PreferencesTab* tab, tabs_) { + tab->Accept(); } - for (int i=0;iproperty("id").isNull()) { - KeySequenceEditor* editor = new KeySequenceEditor(keyboard_tree, key_shortcut_actions.at(i)); - keyboard_tree->setItemWidget(key_shortcut_items.at(i), 1, editor); - key_shortcut_fields.append(editor); - } - } -} + QDialog::accept(); -void PreferencesDialog::accept() { + /* bool restart_after_saving = false; bool reinit_audio = false; bool reload_language = false; @@ -415,12 +189,12 @@ void PreferencesDialog::accept() { olive::config.previous_queue_type = previous_queue_type->currentIndex(); // Audio settings may require the audio device to be re-initiated. - if (olive::config.preferred_audio_output != audio_output_devices->currentData().toString() + if (kUsingAudioOutput != audio_output_devices->currentData().toString() || olive::config.preferred_audio_input != audio_input_devices->currentData().toString() || olive::config.audio_rate != audio_sample_rate->currentData().toInt()) { reinit_audio = true; } - olive::config.preferred_audio_output = audio_output_devices->currentData().toString(); + kUsingAudioOutput = audio_output_devices->currentData().toString(); olive::config.preferred_audio_input = audio_input_devices->currentData().toString(); olive::config.audio_rate = audio_sample_rate->currentData().toInt(); @@ -553,645 +327,12 @@ void PreferencesDialog::accept() { } } + */ } -void PreferencesDialog::reset_default_shortcut() { - QList items = keyboard_tree->selectedItems(); - for (int i=0;iselectedItems().at(i); - static_cast(keyboard_tree->itemWidget(item, 1))->reset_to_default(); - } -} - -void PreferencesDialog::reset_all_shortcuts() { - if (QMessageBox::question( - this, - tr("Confirm Reset All Shortcuts"), - tr("Are you sure you wish to reset all keyboard shortcuts to their defaults?"), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - for (int i=0;ireset_to_default(); - } - } -} - -bool PreferencesDialog::refine_shortcut_list(const QString &s, QTreeWidgetItem* parent) { - if (parent == nullptr) { - for (int i=0;itopLevelItemCount();i++) { - refine_shortcut_list(s, keyboard_tree->topLevelItem(i)); - } - } else { - parent->setExpanded(!s.isEmpty()); - - bool all_children_are_hidden = !s.isEmpty(); - - for (int i=0;ichildCount();i++) { - QTreeWidgetItem* item = parent->child(i); - if (item->childCount() > 0) { - all_children_are_hidden = refine_shortcut_list(s, item); - } else { - item->setHidden(false); - if (s.isEmpty()) { - all_children_are_hidden = false; - } else { - QString shortcut; - if (keyboard_tree->itemWidget(item, 1) != nullptr) { - shortcut = static_cast(keyboard_tree->itemWidget(item, 1))->keySequence().toString(); - } - if (item->text(0).contains(s, Qt::CaseInsensitive) || shortcut.contains(s, Qt::CaseInsensitive)) { - all_children_are_hidden = false; - } else { - item->setHidden(true); - } - } - } - } - - if (parent->text(0).contains(s, Qt::CaseInsensitive)) all_children_are_hidden = false; - - parent->setHidden(all_children_are_hidden); - - return all_children_are_hidden; - } - return true; -} - -void PreferencesDialog::load_shortcut_file() { - QString fn = QFileDialog::getOpenFileName(this, tr("Import Keyboard Shortcuts")); - if (!fn.isEmpty()) { - QFile f(fn); - if (f.exists() && f.open(QFile::ReadOnly)) { - QByteArray ba = f.readAll(); - f.close(); - for (int i=0;iaction_name()); - if (index == 0 || (index > 0 && ba.at(index-1) == '\n')) { - while (index < ba.size() && ba.at(index) != '\t') index++; - QString ks; - index++; - while (index < ba.size() && ba.at(index) != '\n') { - ks.append(ba.at(index)); - index++; - } - key_shortcut_fields.at(i)->setKeySequence(ks); - } else { - key_shortcut_fields.at(i)->reset_to_default(); - } - } - } else { - QMessageBox::critical( - this, - tr("Error saving shortcuts"), - tr("Failed to open file for reading") - ); - } - } -} - -void PreferencesDialog::save_shortcut_file() { - QString fn = QFileDialog::getSaveFileName(this, tr("Export Keyboard Shortcuts")); - if (!fn.isEmpty()) { - QFile f(fn); - if (f.open(QFile::WriteOnly)) { - bool start = true; - for (int i=0;iexport_shortcut(); - if (!s.isEmpty()) { - if (!start) f.write("\n"); - f.write(s.toUtf8()); - start = false; - } - } - f.close(); - QMessageBox::information(this, tr("Export Shortcuts"), tr("Shortcuts exported successfully")); - } else { - QMessageBox::critical(this, tr("Error saving shortcuts"), tr("Failed to open file for writing")); - } - } -} - -void PreferencesDialog::browse_css_file() { - QString fn = QFileDialog::getOpenFileName(this, tr("Browse for CSS file")); - if (!fn.isEmpty()) { - custom_css_fn->setText(fn); - } -} - -void PreferencesDialog::browse_ocio_config() +void PreferencesDialog::AddTab(PreferencesTab *tab, const QString &title) { - QString fn = QFileDialog::getOpenFileName(this, tr("Browse for OpenColorIO configuration")); - if (!fn.isEmpty()) { - ocio_config_file->setText(fn); - enable_color_management->setChecked(true); - } -} + tab_widget_->addTab(tab, title); -void PreferencesDialog::update_ocio_view_menu() -{ - update_ocio_view_menu(OCIO::GetCurrentConfig()); -} - -void PreferencesDialog::delete_all_previews() { - if (QMessageBox::question(this, - tr("Delete All Previews"), - tr("Are you sure you want to delete all previews?"), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - delete_previews(DELETE_BOTH); - QMessageBox::information(this, - tr("Previews Deleted"), - tr("All previews deleted successfully. You may have to re-open your current project for " - "changes to take effect."), - QMessageBox::Ok); - } -} - -void PreferencesDialog::edit_default_sequence_settings() -{ - NewSequenceDialog nsd(this, nullptr, &default_sequence); - nsd.SetNameEditable(false); - nsd.exec(); -} - -void PreferencesDialog::setup_ui() { - QVBoxLayout* verticalLayout = new QVBoxLayout(this); - QTabWidget* tabWidget = new QTabWidget(this); - - // row counter used to ease adding new rows - int row = 0; - - // General - QWidget* general_tab = new QWidget(this); - QGridLayout* general_layout = new QGridLayout(general_tab); - - // General -> Language - general_layout->addWidget(new QLabel(tr("Language:")), row, 0); - - language_combobox = new QComboBox(); - - // add default language (en-US) - language_combobox->addItem(QLocale::languageToString(QLocale("en-US").language())); - - // add languages from file - QList translation_paths = get_language_paths(); - - // iterate through all language search paths - for (int j=0;jaddItem(QLocale(locale_str).nativeLanguageName(), locale_relative_path); - - if (olive::config.language_file == locale_relative_path) { - language_combobox->setCurrentIndex(language_combobox->count() - 1); - } - } - } - } - - general_layout->addWidget(language_combobox, row, 1, 1, 4); - - row++; - - // General -> Image Sequence Formats - general_layout->addWidget(new QLabel(tr("Image sequence formats:"), this), row, 0); - - imgSeqFormatEdit = new QLineEdit(general_tab); - imgSeqFormatEdit->setText(olive::config.img_seq_formats); - general_layout->addWidget(imgSeqFormatEdit, row, 1, 1, 4); - - row++; - - // General -> Thumbnail and Waveform Resolution - general_layout->addWidget(new QLabel(tr("Thumbnail Resolution:"), this), row, 0); - - thumbnail_res_spinbox = new QSpinBox(this); - thumbnail_res_spinbox->setMinimum(0); - thumbnail_res_spinbox->setMaximum(INT_MAX); - thumbnail_res_spinbox->setValue(olive::config.thumbnail_resolution); - general_layout->addWidget(thumbnail_res_spinbox, row, 1); - - general_layout->addWidget(new QLabel(tr("Waveform Resolution:"), this), row, 2); - - waveform_res_spinbox = new QSpinBox(this); - waveform_res_spinbox->setMinimum(0); - waveform_res_spinbox->setMaximum(INT_MAX); - waveform_res_spinbox->setValue(olive::config.waveform_resolution); - general_layout->addWidget(waveform_res_spinbox, row, 3); - - QPushButton* delete_preview_btn = new QPushButton(tr("Delete Previews")); - general_layout->addWidget(delete_preview_btn, row, 4); - connect(delete_preview_btn, SIGNAL(clicked(bool)), this, SLOT(delete_all_previews())); - - row++; - - QHBoxLayout* misc_general = new QHBoxLayout(); - - // General -> Use Software Fallbacks When Possible - QCheckBox* use_software_fallbacks_checkbox = new QCheckBox(tr("Use Software Fallbacks When Possible")); - AddBoolPair(use_software_fallbacks_checkbox, &olive::config.use_software_fallback, true); - misc_general->addWidget(use_software_fallbacks_checkbox); - - // General -> Don't Use Proxies When Exporting - QCheckBox* dont_use_proxies_when_exporting = new QCheckBox(tr("Don't Use Proxies When Exporting")); - dont_use_proxies_when_exporting->setToolTip(tr("Use originals instead of proxies when exporting")); - AddBoolPair(dont_use_proxies_when_exporting, &olive::config.dont_use_proxies_on_export); - misc_general->addWidget(dont_use_proxies_when_exporting); - - // General -> Default Sequence Settings - QPushButton* default_sequence_settings = new QPushButton(tr("Default Sequence Settings")); - connect(default_sequence_settings, SIGNAL(clicked(bool)), this, SLOT(edit_default_sequence_settings())); - misc_general->addWidget(default_sequence_settings); - - general_layout->addLayout(misc_general, row, 0, 1, 5); - - row++; - - tabWidget->addTab(general_tab, tr("General")); - - // Behavior - QWidget* behavior_tab = new QWidget(this); - tabWidget->addTab(behavior_tab, tr("Behavior")); - - ColumnedGridLayout* behavior_tab_layout = new ColumnedGridLayout(behavior_tab, 2); - - QCheckBox* add_default_effects_to_clips = new QCheckBox(tr("Add Default Effects to New Clips")); - AddBoolPair(add_default_effects_to_clips, &olive::config.add_default_effects_to_clips); - behavior_tab_layout->Add(add_default_effects_to_clips); - - QCheckBox* auto_seek_to_beginning = new QCheckBox(tr("Automatically Seek to the Beginning When Playing at the End of a Sequence")); - AddBoolPair(auto_seek_to_beginning, &olive::config.auto_seek_to_beginning); - behavior_tab_layout->Add(auto_seek_to_beginning); - - QCheckBox* selecting_also_seeks = new QCheckBox(tr("Selecting Also Seeks")); - AddBoolPair(selecting_also_seeks, &olive::config.select_also_seeks); - behavior_tab_layout->Add(selecting_also_seeks); - - QCheckBox* edit_tool_also_seeks = new QCheckBox(tr("Edit Tool Also Seeks")); - AddBoolPair(edit_tool_also_seeks, &olive::config.edit_tool_also_seeks); - behavior_tab_layout->Add(edit_tool_also_seeks); - - QCheckBox* edit_tool_selects_links = new QCheckBox(tr("Edit Tool Selects Links")); - AddBoolPair(edit_tool_selects_links, &olive::config.edit_tool_selects_links); - behavior_tab_layout->Add(edit_tool_selects_links); - - QCheckBox* seek_also_selects = new QCheckBox(tr("Seek Also Selects")); - AddBoolPair(seek_also_selects, &olive::config.seek_also_selects); - behavior_tab_layout->Add(seek_also_selects); - - QCheckBox* seek_to_end_of_pastes = new QCheckBox(tr("Seek to the End of Pastes")); - AddBoolPair(seek_to_end_of_pastes, &olive::config.paste_seeks); - behavior_tab_layout->Add(seek_to_end_of_pastes); - - QCheckBox* scroll_wheel_zooms = new QCheckBox(tr("Scroll Wheel Zooms")); - scroll_wheel_zooms->setToolTip(tr("Hold CTRL to toggle this setting")); - AddBoolPair(scroll_wheel_zooms, &olive::config.scroll_zooms); - behavior_tab_layout->Add(scroll_wheel_zooms); - - QCheckBox* invert_timeline_scroll_axes = new QCheckBox(tr("Invert Timeline Scroll Axes")); - AddBoolPair(invert_timeline_scroll_axes, &olive::config.invert_timeline_scroll_axes); - behavior_tab_layout->Add(invert_timeline_scroll_axes); - - QCheckBox* enable_drag_files_to_timeline = new QCheckBox(tr("Enable Drag Files to Timeline")); - AddBoolPair(enable_drag_files_to_timeline, &olive::config.enable_drag_files_to_timeline); - behavior_tab_layout->Add(enable_drag_files_to_timeline); - - QCheckBox* autoscale_by_default = new QCheckBox(tr("Auto-Scale By Default")); - AddBoolPair(autoscale_by_default, &olive::config.autoscale_by_default); - behavior_tab_layout->Add(autoscale_by_default); - - QCheckBox* enable_seek_to_import = new QCheckBox(tr("Auto-Seek to Imported Clips")); - AddBoolPair(enable_seek_to_import, &olive::config.enable_seek_to_import); - behavior_tab_layout->Add(enable_seek_to_import); - - QCheckBox* enable_audio_scrubbing = new QCheckBox(tr("Audio Scrubbing")); - AddBoolPair(enable_audio_scrubbing, &olive::config.enable_audio_scrubbing); - behavior_tab_layout->Add(enable_audio_scrubbing); - - QCheckBox* enable_drop_on_media_to_replace = new QCheckBox(tr("Drop Files on Media to Replace")); - AddBoolPair(enable_drop_on_media_to_replace, &olive::config.drop_on_media_to_replace); - behavior_tab_layout->Add(enable_drop_on_media_to_replace); - - QCheckBox* enable_hover_focus = new QCheckBox(tr("Enable Hover Focus")); - AddBoolPair(enable_hover_focus, &olive::config.hover_focus); - behavior_tab_layout->Add(enable_hover_focus); - - QCheckBox* set_name_and_marker = new QCheckBox(tr("Ask For Name When Setting Marker")); - AddBoolPair(set_name_and_marker, &olive::config.set_name_with_marker); - behavior_tab_layout->Add(set_name_and_marker); - - // Appearance - QWidget* appearance_tab = new QWidget(this); - tabWidget->addTab(appearance_tab, tr("Appearance")); - - row = 0; - - QGridLayout* appearance_layout = new QGridLayout(appearance_tab); - - // Appearance -> Theme - appearance_layout->addWidget(new QLabel(tr("Theme")), row, 0); - - ui_style = new QComboBox(); - ui_style->addItem(tr("Olive Dark (Default)"), olive::styling::kOliveDefaultDark); - ui_style->addItem(tr("Olive Light"), olive::styling::kOliveDefaultLight); - ui_style->addItem(tr("Native"), olive::styling::kNativeDarkIcons); - ui_style->addItem(tr("Native (Light Icons)"), olive::styling::kNativeLightIcons); - ui_style->setCurrentIndex(olive::config.style); - appearance_layout->addWidget(ui_style, row, 1, 1, 2); - - row++; - -#ifdef Q_OS_WIN - // Native menu styling is only available on Windows. Environments like Ubuntu and Mac use the native menu system by - // default - QCheckBox* native_menus = new QCheckBox(tr("Use Native Menu Styling")); - AddBoolPair(native_menus, &olive::config.use_native_menu_styling, true); - appearance_layout->addWidget(native_menus, row, 0, 1, 3); - - row++; -#endif - - // Appearance -> Custom CSS - appearance_layout->addWidget(new QLabel(tr("Custom CSS:"), this), row, 0); - - custom_css_fn = new QLineEdit(general_tab); - custom_css_fn->setText(olive::config.css_path); - appearance_layout->addWidget(custom_css_fn, row, 1); - - QPushButton* custom_css_browse = new QPushButton(tr("Browse"), general_tab); - connect(custom_css_browse, SIGNAL(clicked(bool)), this, SLOT(browse_css_file())); - appearance_layout->addWidget(custom_css_browse, row, 2); - - row++; - - // Appearance -> Effect Textbox Lines - appearance_layout->addWidget(new QLabel(tr("Effect Textbox Lines:"), this), row, 0); - - effect_textbox_lines_field = new QSpinBox(general_tab); - effect_textbox_lines_field->setMinimum(1); - effect_textbox_lines_field->setValue(olive::config.effect_textbox_lines); - appearance_layout->addWidget(effect_textbox_lines_field, row, 1, 1, 2); - - row++; - - // Playback - QWidget* playback_tab = new QWidget(this); - QVBoxLayout* playback_tab_layout = new QVBoxLayout(playback_tab); - - // Playback -> Memory Usage - QGroupBox* memory_usage_group = new QGroupBox(playback_tab); - memory_usage_group->setTitle(tr("Memory Usage")); - QGridLayout* memory_usage_layout = new QGridLayout(memory_usage_group); - memory_usage_layout->addWidget(new QLabel(tr("Upcoming Frame Queue:"), playback_tab), 0, 0); - upcoming_queue_spinbox = new QDoubleSpinBox(playback_tab); - upcoming_queue_spinbox->setValue(olive::config.upcoming_queue_size); - memory_usage_layout->addWidget(upcoming_queue_spinbox, 0, 1); - upcoming_queue_type = new QComboBox(playback_tab); - upcoming_queue_type->addItem(tr("frames")); - upcoming_queue_type->addItem(tr("seconds")); - upcoming_queue_type->setCurrentIndex(olive::config.upcoming_queue_type); - memory_usage_layout->addWidget(upcoming_queue_type, 0, 2); - memory_usage_layout->addWidget(new QLabel(tr("Previous Frame Queue:"), playback_tab), 1, 0); - previous_queue_spinbox = new QDoubleSpinBox(playback_tab); - previous_queue_spinbox->setValue(olive::config.previous_queue_size); - memory_usage_layout->addWidget(previous_queue_spinbox, 1, 1); - previous_queue_type = new QComboBox(playback_tab); - previous_queue_type->addItem(tr("frames")); - previous_queue_type->addItem(tr("seconds")); - previous_queue_type->setCurrentIndex(olive::config.previous_queue_type); - memory_usage_layout->addWidget(previous_queue_type, 1, 2); - playback_tab_layout->addWidget(memory_usage_group); - - tabWidget->addTab(playback_tab, tr("Playback")); - - // Audio - QWidget* audio_tab = new QWidget(this); - - QGridLayout* audio_tab_layout = new QGridLayout(audio_tab); - - row = 0; - - // Audio -> Output Device - - audio_tab_layout->addWidget(new QLabel(tr("Output Device:")), row, 0); - - audio_output_devices = new QComboBox(); - audio_output_devices->addItem(tr("Default"), ""); - - // list all available audio output devices - QList devs = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput); - bool found_preferred_device = false; - for (int i=0;iaddItem(devs.at(i).deviceName(), devs.at(i).deviceName()); - if (!found_preferred_device - && devs.at(i).deviceName() == olive::config.preferred_audio_output) { - audio_output_devices->setCurrentIndex(audio_output_devices->count()-1); - found_preferred_device = true; - } - } - - audio_tab_layout->addWidget(audio_output_devices, row, 1); - - row++; - - // Audio -> Input Device - - audio_tab_layout->addWidget(new QLabel(tr("Input Device:")), row, 0); - - audio_input_devices = new QComboBox(); - audio_input_devices->addItem(tr("Default"), ""); - - // list all available audio input devices - devs = QAudioDeviceInfo::availableDevices(QAudio::AudioInput); - found_preferred_device = false; - for (int i=0;iaddItem(devs.at(i).deviceName(), devs.at(i).deviceName()); - if (!found_preferred_device - && devs.at(i).deviceName() == olive::config.preferred_audio_input) { - audio_input_devices->setCurrentIndex(audio_input_devices->count()-1); - found_preferred_device = true; - } - } - - audio_tab_layout->addWidget(audio_input_devices, row, 1); - - row++; - - // Audio -> Sample Rate - - audio_tab_layout->addWidget(new QLabel(tr("Sample Rate:")), row, 0); - - audio_sample_rate = new QComboBox(); - combobox_audio_sample_rates(audio_sample_rate); - for (int i=0;icount();i++) { - if (audio_sample_rate->itemData(i).toInt() == olive::config.audio_rate) { - audio_sample_rate->setCurrentIndex(i); - break; - } - } - - audio_tab_layout->addWidget(audio_sample_rate, row, 1); - - row++; - - // Audio -> Audio Recording - audio_tab_layout->addWidget(new QLabel(tr("Audio Recording:"), this), row, 0); - - recordingComboBox = new QComboBox(general_tab); - recordingComboBox->addItem(tr("Mono")); - recordingComboBox->addItem(tr("Stereo")); - recordingComboBox->setCurrentIndex(olive::config.recording_mode - 1); - audio_tab_layout->addWidget(recordingComboBox, row, 1); - - row++; - - tabWidget->addTab(audio_tab, tr("Audio")); - - // - // COLOR MANAGEMENT - // - - QWidget* color_management_tab = new QWidget(); - - QGridLayout* color_management_layout = new QGridLayout(color_management_tab); - - row = 0; - - // COLOR MANAGEMENT -> Enable Color Management - enable_color_management = new QCheckBox(tr("Enable Color Management")); - enable_color_management->setChecked(olive::config.enable_color_management); - color_management_layout->addWidget(enable_color_management, row, 0); - - row++; - - QGroupBox* opencolorio_groupbox = new QGroupBox(); - QGridLayout* opencolorio_groupbox_layout = new QGridLayout(opencolorio_groupbox); - - // COLOR MANAGEMENT -> OpenColorIO Config File - opencolorio_groupbox_layout->addWidget(new QLabel(tr("OpenColorIO Config File:")), 0, 0); - - ocio_config_file = new QLineEdit(); - ocio_config_file->setText(olive::config.ocio_config_path); - connect(ocio_config_file, SIGNAL(textChanged(const QString &)), this, SLOT(update_ocio_config(const QString&))); - opencolorio_groupbox_layout->addWidget(ocio_config_file, 0, 1, 1, 4); - - QPushButton* ocio_config_browse_btn = new QPushButton(tr("Browse")); - connect(ocio_config_browse_btn, SIGNAL(clicked(bool)), this, SLOT(browse_ocio_config())); - opencolorio_groupbox_layout->addWidget(ocio_config_browse_btn, 0, 5); - - // COLOR MANAGEMENT -> Default Input Color Space - ocio_default_input = new QComboBox(); - opencolorio_groupbox_layout->addWidget(new QLabel(tr("Default Input Color Space:")), 1, 0); - opencolorio_groupbox_layout->addWidget(ocio_default_input, 1, 1, 1, 5); - - // COLOR MANAGEMENT -> Display - ocio_display = new QComboBox(); - connect(ocio_display, SIGNAL(currentIndexChanged(int)), this, SLOT(update_ocio_view_menu())); - opencolorio_groupbox_layout->addWidget(new QLabel(tr("Display:")), 2, 0); - opencolorio_groupbox_layout->addWidget(ocio_display, 2, 1); - - // COLOR MANAGEMENT -> View - ocio_view = new QComboBox(); - opencolorio_groupbox_layout->addWidget(new QLabel(tr("View:")), 2, 2); - opencolorio_groupbox_layout->addWidget(ocio_view, 2, 3); - - // COLOR MANAGEMENT -> Look - ocio_look = new QComboBox(); - opencolorio_groupbox_layout->addWidget(new QLabel(tr("Look:")), 2, 4); - opencolorio_groupbox_layout->addWidget(ocio_look, 2, 5); - - color_management_layout->addWidget(opencolorio_groupbox, row, 0); - - row++; - - // COLOR MANAGEMENT -> Bit Depth - QGroupBox* bit_depth_groupbox = new QGroupBox(tr("Bit Depth")); - QGridLayout* bit_depth_groupbox_layout = new QGridLayout(bit_depth_groupbox); - - // COLOR MANAGEMENT -> Bit Depth -> Playback - playback_bit_depth = new QComboBox(); - for (int i=0;iaddItem(olive::pixel_formats.at(i).name, i); - } - playback_bit_depth->setCurrentIndex(olive::config.playback_bit_depth); - bit_depth_groupbox_layout->addWidget(new QLabel(tr("Playback (Offline):")), 0, 0); - bit_depth_groupbox_layout->addWidget(playback_bit_depth, 0, 1); - - // COLOR MANAGEMENT -> Bit Depth -> Export - export_bit_depth = new QComboBox(); - for (int i=0;iaddItem(olive::pixel_formats.at(i).name, i); - } - export_bit_depth->setCurrentIndex(olive::config.export_bit_depth); - bit_depth_groupbox_layout->addWidget(new QLabel(tr("Export (Online):")), 0, 2); - bit_depth_groupbox_layout->addWidget(export_bit_depth, 0, 3); - - color_management_layout->addWidget(bit_depth_groupbox, row, 0); - - - - //row++; - - populate_ocio_menus(OCIO::GetCurrentConfig()); - - tabWidget->addTab(color_management_tab, tr("Color Management")); - - // Shortcuts - QWidget* shortcut_tab = new QWidget(this); - - QVBoxLayout* shortcut_layout = new QVBoxLayout(shortcut_tab); - - QLineEdit* key_search_line = new QLineEdit(shortcut_tab); - key_search_line->setPlaceholderText(tr("Search for action or shortcut")); - connect(key_search_line, SIGNAL(textChanged(const QString &)), this, SLOT(refine_shortcut_list(const QString &))); - - shortcut_layout->addWidget(key_search_line); - - keyboard_tree = new QTreeWidget(shortcut_tab); - QTreeWidgetItem* tree_header = keyboard_tree->headerItem(); - tree_header->setText(0, tr("Action")); - tree_header->setText(1, tr("Shortcut")); - shortcut_layout->addWidget(keyboard_tree); - - QHBoxLayout* reset_shortcut_layout = new QHBoxLayout(shortcut_tab); - - QPushButton* import_shortcut_button = new QPushButton(tr("Import"), shortcut_tab); - reset_shortcut_layout->addWidget(import_shortcut_button); - connect(import_shortcut_button, SIGNAL(clicked(bool)), this, SLOT(load_shortcut_file())); - - QPushButton* export_shortcut_button = new QPushButton(tr("Export"), shortcut_tab); - reset_shortcut_layout->addWidget(export_shortcut_button); - connect(export_shortcut_button, SIGNAL(clicked(bool)), this, SLOT(save_shortcut_file())); - - reset_shortcut_layout->addStretch(); - - QPushButton* reset_selected_shortcut_button = new QPushButton(tr("Reset Selected"), shortcut_tab); - reset_shortcut_layout->addWidget(reset_selected_shortcut_button); - connect(reset_selected_shortcut_button, SIGNAL(clicked(bool)), this, SLOT(reset_default_shortcut())); - - QPushButton* reset_all_shortcut_button = new QPushButton(tr("Reset All"), shortcut_tab); - reset_shortcut_layout->addWidget(reset_all_shortcut_button); - connect(reset_all_shortcut_button, SIGNAL(clicked(bool)), this, SLOT(reset_all_shortcuts())); - - shortcut_layout->addLayout(reset_shortcut_layout); - - tabWidget->addTab(shortcut_tab, tr("Keyboard")); - - verticalLayout->addWidget(tabWidget); - - QDialogButtonBox* buttonBox = new QDialogButtonBox(this); - buttonBox->setOrientation(Qt::Horizontal); - buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); - - verticalLayout->addWidget(buttonBox); - - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + tabs_.append(tab); } diff --git a/app/dialog/preferences/preferences.h b/app/dialog/preferences/preferences.h index 721a2b505..15d2fc4ca 100644 --- a/app/dialog/preferences/preferences.h +++ b/app/dialog/preferences/preferences.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2019 Olive Team This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,24 +21,12 @@ #ifndef PREFERENCESDIALOG_H #define PREFERENCESDIALOG_H -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -namespace OCIO = OCIO_NAMESPACE::v1; +#include +#include +#include -#include "timeline/sequence.h" - -class KeySequenceEditor; +#include "tabs/preferencestab.h" /** * @brief The PreferencesDialog class @@ -58,7 +46,7 @@ public: * * QWidget parent. Usually MainWindow. */ - explicit PreferencesDialog(QWidget *parent = nullptr); + explicit PreferencesDialog(QWidget *parent, QMenuBar* main_menu_bar); private slots: /** @@ -66,215 +54,12 @@ private slots: */ 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(); - - /** - * @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(); - - // OCIO function - void update_ocio_view_menu(); - void update_ocio_view_menu(OCIO::ConstConfigRcPtr config); - void update_ocio_config(const QString&); - - /** - * @brief Shows a NewSequenceDialog attached to default_sequence - */ - void edit_default_sequence_settings(); - private: + void AddTab(PreferencesTab* tab, const QString& title); - /** - * @brief Create and arrange all UI widgets - */ - void setup_ui(); + QTabWidget* tab_widget_; - /** - * @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 { - DELETE_NONE, - DELETE_THUMBNAILS, - DELETE_WAVEFORMS, - DELETE_BOTH - }; - - // used to delete previews - // type can be: 't' for thumbnails, 'w' for waveforms, or 1 for all - /** - * @brief Delete disk cached preview files (thumbnails, waveforms, etc.) - * - * @param type - * - * The types of previews to delete. - */ - void delete_previews(PreviewDeleteTypes type); - - void populate_ocio_menus(OCIO::ConstConfigRcPtr config); - - /** - * @brief UI widget for editing the CSS filename - */ - QLineEdit* custom_css_fn; - - /** - * @brief UI widget for editing the list of extensions to detect image sequences from - */ - QLineEdit* imgSeqFormatEdit; - - /** - * @brief UI widget for editing the recording channels - */ - QComboBox* recordingComboBox; - - - /** - * @brief UI widget for editing keyboard shortcuts - */ - QTreeWidget* keyboard_tree; - - /** - * @brief UI widget for editing the upcoming queue size - */ - QDoubleSpinBox* upcoming_queue_spinbox; - - /** - * @brief UI widget for editing the upcoming queue type - */ - QComboBox* upcoming_queue_type; - - /** - * @brief UI widget for editing the previous queue size - */ - QDoubleSpinBox* previous_queue_spinbox; - - /** - * @brief UI widget for editing the previous queue type - */ - QComboBox* previous_queue_type; - - /** - * @brief UI widget for editing the size of textboxes in the EffectControls panel - */ - QSpinBox* effect_textbox_lines_field; - - /** - * @brief UI widget for selecting the output audio device - */ - QComboBox* audio_output_devices; - - /** - * @brief UI widget for selecting the input audio device - */ - QComboBox* audio_input_devices; - - /** - * @brief UI widget for selecting the audio sampling rates - */ - QComboBox* audio_sample_rate; - - /** - * @brief UI widget for selecting the UI language - */ - QComboBox* language_combobox; - - /** - * @brief UI widget for selecting the resolution of the thumbnails to generate - */ - QSpinBox* thumbnail_res_spinbox; - - /** - * @brief UI widget for selecting the resolution of the waveforms to generate - */ - QSpinBox* waveform_res_spinbox; - - QCheckBox* enable_color_management; - QLineEdit* ocio_config_file; - QComboBox* ocio_default_input; - QComboBox* ocio_display; - QComboBox* ocio_view; - QComboBox* ocio_look; - QComboBox* playback_bit_depth; - QComboBox* export_bit_depth; - - /** - * @brief UI widget for selecting the current UI style - */ - QComboBox* ui_style; + QList tabs_; /** * @brief Stored default Sequence object @@ -282,38 +67,7 @@ private: * Default Sequence settings are loaded into an actual Sequence object that can be loaded into NewSequenceDialog * for the sake of familiarity with the user. */ - Sequence default_sequence; - - /** - * @brief List of keyboard shortcut actions that can be triggered (links with key_shortcut_items and - * key_shortcut_fields) - */ - QVector key_shortcut_actions; - - /** - * @brief List of keyboard shortcut items in keyboard_tree corresponding to existing actions (links with - * key_shortcut_actions and key_shortcut_fields) - */ - QVector key_shortcut_items; - - /** - * @brief List of keyboard shortcut editing fields in keyboard_tree corresponding to existing actions (links with - * key_shortcut_actions and key_shortcut_fields) - */ - QVector key_shortcut_fields; - - /** - * @brief Tests an OpenColorIO configuration file to determine whether it's valid and throws a messagebox if not - * - * @param url - * - * URL to the OpenColorIO configuration file. - * - * @return - * - * A OCIO::ConstConfigRcPtr config pointer if the configuration file is valid, nullptr if not. - */ - OCIO::ConstConfigRcPtr TestOCIOConfig(const QString& url); + //Sequence default_sequence; /** * @brief Add an automated QCheckBox+boolean value pair @@ -355,78 +109,4 @@ private: QVector bool_restart_required; }; -/** - * @brief The KeySequenceEditor class - * - * Simple derived class of QKeySequenceEdit that attaches to a QAction and provides functions for transferring - * keyboard shortcuts to and from it. - */ -class KeySequenceEditor : public QKeySequenceEdit { - Q_OBJECT -public: - /** - * @brief KeySequenceEditor Constructor - * - * @param parent - * - * QWidget parent. - * - * @param a - * - * The QAction to link to. This cannot be changed throughout the lifetime of a KeySequenceEditor. - */ - KeySequenceEditor(QWidget *parent, QAction* a); - - /** - * @brief Sets the attached QAction's shortcut to the shortcut entered in this field. - * - * This is not done automatically in case the user cancels out of the Preferences dialog, in which case the - * expectation is that the changes made will not be saved. Therefore, this needs to be triggered manually when - * PreferencesDialog saves. - */ - void set_action_shortcut(); - - /** - * @brief Set this shortcut back to the QAction's default shortcut - * - * Each QAction contains the default shortcut in its `property("default")` and can be used to restore the default - * "hard-coded" shortcut with this function. - * - * This function does not save the default shortcut back into the QAction, it simply loads the default shortcut from - * the QAction into this edit field. To save it into the QAction, it's necessary to call set_action_shortcut() after - * calling this function. - */ - void reset_to_default(); - - /** - * @brief Return attached QAction's unique ID - * - * Each of Olive's menu actions has a unique string ID (that, unlike the text, is not translated) for matching with - * an external shortcut configuration file. The ID is stored in the QAction's `property("id")`. This function returns - * that ID. - * - * @return - * - * The QAction's unique ID. - */ - QString action_name(); - - /** - * @brief Serialize this shortcut entry into a string that can be saved to a file - * - * @return - * - * A string serialization of this shortcut. The format is "[ID]\t[SEQUENCE]" where [ID] is the attached QAction's - * unique identifier and [SEQUENCE] is the current keyboard shortcut in the field (NOT necessarily the shortcut in - * the QAction). If the entered shortcut is the same as the QAction's default shortcut, the return value is empty - * because a default shortcut does not need to be saved to a file. - */ - QString export_shortcut(); -private: - /** - * @brief Internal reference to the linked QAction - */ - QAction* action; -}; - #endif // PREFERENCESDIALOG_H diff --git a/app/dialog/preferences/tabs/CMakeLists.txt b/app/dialog/preferences/tabs/CMakeLists.txt new file mode 100644 index 000000000..1d1f26e3b --- /dev/null +++ b/app/dialog/preferences/tabs/CMakeLists.txt @@ -0,0 +1,36 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2019 Olive Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + dialog/preferences/tabs/preferencesgeneraltab.h + dialog/preferences/tabs/preferencesgeneraltab.cpp + dialog/preferences/tabs/preferencesbehaviortab.h + dialog/preferences/tabs/preferencesbehaviortab.cpp + dialog/preferences/tabs/preferencesappearancetab.h + dialog/preferences/tabs/preferencesappearancetab.cpp + dialog/preferences/tabs/preferencesplaybacktab.h + dialog/preferences/tabs/preferencesplaybacktab.cpp + dialog/preferences/tabs/preferencesaudiotab.h + dialog/preferences/tabs/preferencesaudiotab.cpp + dialog/preferences/tabs/preferenceskeyboardtab.h + dialog/preferences/tabs/preferenceskeyboardtab.cpp + dialog/preferences/tabs/preferencescolormanagementtab.h + dialog/preferences/tabs/preferencescolormanagementtab.cpp + dialog/preferences/tabs/preferencestab.h + dialog/preferences/tabs/preferencestab.cpp + PARENT_SCOPE +) diff --git a/app/dialog/preferences/tabs/preferencesappearancetab.cpp b/app/dialog/preferences/tabs/preferencesappearancetab.cpp new file mode 100644 index 000000000..8bc2d08ed --- /dev/null +++ b/app/dialog/preferences/tabs/preferencesappearancetab.cpp @@ -0,0 +1,51 @@ +#include "preferencesappearancetab.h" + +#include +#include +#include +#include + +PreferencesAppearanceTab::PreferencesAppearanceTab() +{ + QVBoxLayout* layout = new QVBoxLayout(this); + + QGridLayout* appearance_layout = new QGridLayout(); + layout->addLayout(appearance_layout); + + int row = 0; + + // Appearance -> Theme + appearance_layout->addWidget(new QLabel(tr("Theme")), row, 0); + + style_ = new QComboBox(); + + style_list_ = StyleManager::ListInternal(); + + foreach (StyleDescriptor s, style_list_) { + style_->addItem(s.name(), s.path()); + + if (s.path() == Config::Current()["Style"]) { + style_->setCurrentIndex(style_->count()-1); + } + } + + appearance_layout->addWidget(style_, row, 1, 1, 2); + + row++; + + layout->addStretch(); +} + +void PreferencesAppearanceTab::Accept() +{ + QString style_path = style_->currentData().toString(); + StyleManager::SetStyle(style_path); + Config::Current()["Style"] = style_path; + + if (style_->currentIndex() < style_list_.size()) { + // This is an internal style, set accordingly + + } else { + StyleManager::SetStyle(style_->currentData().toString()); + } +} diff --git a/app/dialog/preferences/tabs/preferencesappearancetab.h b/app/dialog/preferences/tabs/preferencesappearancetab.h new file mode 100644 index 000000000..a8c46bc6b --- /dev/null +++ b/app/dialog/preferences/tabs/preferencesappearancetab.h @@ -0,0 +1,37 @@ +#ifndef PREFERENCESAPPEARANCETAB_H +#define PREFERENCESAPPEARANCETAB_H + +#include +#include + +#include "preferencestab.h" +#include "ui/style/style.h" + +class PreferencesAppearanceTab : public PreferencesTab +{ + Q_OBJECT +public: + PreferencesAppearanceTab(); + + virtual void Accept() override; + +private: + /** + * @brief Show a file dialog to browse for an external CSS file to load for styling the application. + */ + void BrowseForCSS(); + + /** + * @brief UI widget for selecting the current UI style + */ + QComboBox* style_; + + /** + * @brief List of internal styles + */ + QList style_list_; + + QString custom_style_path_; +}; + +#endif // PREFERENCESAPPEARANCETAB_H diff --git a/app/dialog/preferences/tabs/preferencesaudiotab.cpp b/app/dialog/preferences/tabs/preferencesaudiotab.cpp new file mode 100644 index 000000000..66d7ac317 --- /dev/null +++ b/app/dialog/preferences/tabs/preferencesaudiotab.cpp @@ -0,0 +1,93 @@ +#include "preferencesaudiotab.h" + +#include +#include +#include + +#include "config/config.h" + +PreferencesAudioTab::PreferencesAudioTab() +{ + QGridLayout* audio_tab_layout = new QGridLayout(this); + + int row = 0; + + // Audio -> Output Device + + audio_tab_layout->addWidget(new QLabel(tr("Output Device:")), row, 0); + + audio_output_devices = new QComboBox(); + audio_output_devices->addItem(tr("Default"), ""); + + // list all available audio output devices + QList devs = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput); + bool found_preferred_device = false; + for (int i=0;iaddItem(devs.at(i).deviceName(), devs.at(i).deviceName()); + if (!found_preferred_device + && devs.at(i).deviceName() == Config::Current()["AudioOutput"]) { + audio_output_devices->setCurrentIndex(audio_output_devices->count()-1); + found_preferred_device = true; + } + } + + audio_tab_layout->addWidget(audio_output_devices, row, 1); + + row++; + + // Audio -> Input Device + + audio_tab_layout->addWidget(new QLabel(tr("Input Device:")), row, 0); + + audio_input_devices = new QComboBox(); + audio_input_devices->addItem(tr("Default"), ""); + + // list all available audio input devices + devs = QAudioDeviceInfo::availableDevices(QAudio::AudioInput); + found_preferred_device = false; + for (int i=0;iaddItem(devs.at(i).deviceName(), devs.at(i).deviceName()); + if (!found_preferred_device + && devs.at(i).deviceName() == Config::Current()["AudioInput"]) { + audio_input_devices->setCurrentIndex(audio_input_devices->count()-1); + found_preferred_device = true; + } + } + + audio_tab_layout->addWidget(audio_input_devices, row, 1); + + row++; + + // Audio -> Sample Rate + + audio_tab_layout->addWidget(new QLabel(tr("Sample Rate:")), row, 0); + + audio_sample_rate = new QComboBox(); + /*combobox_audio_sample_rates(audio_sample_rate); + for (int i=0;icount();i++) { + if (audio_sample_rate->itemData(i).toInt() == olive::config.audio_rate) { + audio_sample_rate->setCurrentIndex(i); + break; + } + }*/ + + audio_tab_layout->addWidget(audio_sample_rate, row, 1); + + row++; + + // Audio -> Audio Recording + audio_tab_layout->addWidget(new QLabel(tr("Audio Recording:"), this), row, 0); + + recordingComboBox = new QComboBox(); + recordingComboBox->addItem(tr("Mono")); + recordingComboBox->addItem(tr("Stereo")); +// recordingComboBox->setCurrentIndex(olive::config.recording_mode - 1); + audio_tab_layout->addWidget(recordingComboBox, row, 1); + + row++; +} + +void PreferencesAudioTab::Accept() +{ + +} diff --git a/app/dialog/preferences/tabs/preferencesaudiotab.h b/app/dialog/preferences/tabs/preferencesaudiotab.h new file mode 100644 index 000000000..a7b4fde6b --- /dev/null +++ b/app/dialog/preferences/tabs/preferencesaudiotab.h @@ -0,0 +1,39 @@ +#ifndef PREFERENCESAUDIOTAB_H +#define PREFERENCESAUDIOTAB_H + +#include + +#include "preferencestab.h" + +class PreferencesAudioTab : public PreferencesTab +{ + Q_OBJECT +public: + PreferencesAudioTab(); + + virtual void Accept() override; + +private: + /** + * @brief UI widget for selecting the output audio device + */ + QComboBox* audio_output_devices; + + /** + * @brief UI widget for selecting the input audio device + */ + QComboBox* audio_input_devices; + + /** + * @brief UI widget for selecting the audio sampling rates + */ + QComboBox* audio_sample_rate; + + /** + * @brief UI widget for editing the recording channels + */ + QComboBox* recordingComboBox; + +}; + +#endif // PREFERENCESAUDIOTAB_H diff --git a/app/dialog/preferences/tabs/preferencesbehaviortab.cpp b/app/dialog/preferences/tabs/preferencesbehaviortab.cpp new file mode 100644 index 000000000..3d140965e --- /dev/null +++ b/app/dialog/preferences/tabs/preferencesbehaviortab.cpp @@ -0,0 +1,47 @@ +#include "preferencesbehaviortab.h" + +#include +#include + +PreferencesBehaviorTab::PreferencesBehaviorTab() +{ + QVBoxLayout* layout = new QVBoxLayout(this); + + behavior_tree_ = new QTreeWidget(); + layout->addWidget(behavior_tree_); + + behavior_tree_->setHeaderLabel(tr("Behavior")); + behavior_tree_->setRootIsDecorated(false); + + AddItem(tr("Add Default Effects to New Clips")); + AddItem(tr("Automatically Seek to the Beginning When Playing at the End of a Sequence")); + AddItem(tr("Selecting Also Seeks")); + AddItem(tr("Edit Tool Also Seeks")); + AddItem(tr("Edit Tool Selects Links")); + AddItem(tr("Seek Also Selects")); + AddItem(tr("Seek to the End of Pastes")); + AddItem(tr("Scroll Wheel Zooms")); + AddItem(tr("Invert Timeline Scroll Axes")); + AddItem(tr("Enable Drag Files to Timeline")); + AddItem(tr("Auto-Scale By Default")); + AddItem(tr("Auto-Seek to Imported Clips")); + AddItem(tr("Audio Scrubbing")); + AddItem(tr("Drop Files on Media to Replace")); + AddItem(tr("Enable Hover Focus")); + AddItem(tr("Ask For Name When Setting Marker")); + + //scroll_wheel_zooms->setToolTip(tr("Hold CTRL to toggle this setting")); +} + +void PreferencesBehaviorTab::Accept() +{ + +} + +void PreferencesBehaviorTab::AddItem(const QString &text, const QString& tooltip) +{ + QTreeWidgetItem* item = new QTreeWidgetItem({text}); + item->setToolTip(0, tooltip); + item->setCheckState(0, Qt::Unchecked); + behavior_tree_->addTopLevelItem(item); +} diff --git a/app/dialog/preferences/tabs/preferencesbehaviortab.h b/app/dialog/preferences/tabs/preferencesbehaviortab.h new file mode 100644 index 000000000..f0590e4a5 --- /dev/null +++ b/app/dialog/preferences/tabs/preferencesbehaviortab.h @@ -0,0 +1,22 @@ +#ifndef PREFERENCESBEHAVIORTAB_H +#define PREFERENCESBEHAVIORTAB_H + +#include + +#include "preferencestab.h" + +class PreferencesBehaviorTab : public PreferencesTab +{ + Q_OBJECT +public: + PreferencesBehaviorTab(); + + virtual void Accept() override; + +private: + void AddItem(const QString& text, const QString &tooltip = QString()); + + QTreeWidget* behavior_tree_; +}; + +#endif // PREFERENCESBEHAVIORTAB_H diff --git a/app/dialog/preferences/tabs/preferencescolormanagementtab.cpp b/app/dialog/preferences/tabs/preferencescolormanagementtab.cpp new file mode 100644 index 000000000..5e9ea1b95 --- /dev/null +++ b/app/dialog/preferences/tabs/preferencescolormanagementtab.cpp @@ -0,0 +1,213 @@ +#include "preferencescolormanagementtab.h" + +#include +#include +#include +#include +#include +#include +#include + +PreferencesColorManagementTab::PreferencesColorManagementTab() +{ + QGridLayout* color_management_layout = new QGridLayout(this); + + int row = 0; + + QGroupBox* opencolorio_groupbox = new QGroupBox(); + QGridLayout* opencolorio_groupbox_layout = new QGridLayout(opencolorio_groupbox); + + // COLOR MANAGEMENT -> OpenColorIO Config File + opencolorio_groupbox_layout->addWidget(new QLabel(tr("OpenColorIO Config File:")), 0, 0); + + ocio_config_file = new QLineEdit(); + // ocio_config_file->setText(olive::config.ocio_config_path); + connect(ocio_config_file, SIGNAL(textChanged(const QString &)), this, SLOT(update_ocio_config(const QString&))); + opencolorio_groupbox_layout->addWidget(ocio_config_file, 0, 1, 1, 4); + + QPushButton* ocio_config_browse_btn = new QPushButton(tr("Browse")); + connect(ocio_config_browse_btn, SIGNAL(clicked(bool)), this, SLOT(browse_ocio_config())); + opencolorio_groupbox_layout->addWidget(ocio_config_browse_btn, 0, 5); + + // COLOR MANAGEMENT -> Default Input Color Space + ocio_default_input = new QComboBox(); + opencolorio_groupbox_layout->addWidget(new QLabel(tr("Default Input Color Space:")), 1, 0); + opencolorio_groupbox_layout->addWidget(ocio_default_input, 1, 1, 1, 5); + + // COLOR MANAGEMENT -> Display + ocio_display = new QComboBox(); + connect(ocio_display, SIGNAL(currentIndexChanged(int)), this, SLOT(update_ocio_view_menu())); + opencolorio_groupbox_layout->addWidget(new QLabel(tr("Display:")), 2, 0); + opencolorio_groupbox_layout->addWidget(ocio_display, 2, 1); + + // COLOR MANAGEMENT -> View + ocio_view = new QComboBox(); + opencolorio_groupbox_layout->addWidget(new QLabel(tr("View:")), 2, 2); + opencolorio_groupbox_layout->addWidget(ocio_view, 2, 3); + + // COLOR MANAGEMENT -> Look + ocio_look = new QComboBox(); + opencolorio_groupbox_layout->addWidget(new QLabel(tr("Look:")), 2, 4); + opencolorio_groupbox_layout->addWidget(ocio_look, 2, 5); + + color_management_layout->addWidget(opencolorio_groupbox, row, 0); + + row++; + + // COLOR MANAGEMENT -> Bit Depth + QGroupBox* bit_depth_groupbox = new QGroupBox(tr("Bit Depth")); + QGridLayout* bit_depth_groupbox_layout = new QGridLayout(bit_depth_groupbox); + + // COLOR MANAGEMENT -> Bit Depth -> Playback + playback_bit_depth = new QComboBox(); + /*for (int i=0;iaddItem(olive::pixel_formats.at(i).name, i); + } + playback_bit_depth->setCurrentIndex(olive::config.playback_bit_depth);*/ + bit_depth_groupbox_layout->addWidget(new QLabel(tr("Playback (Offline):")), 0, 0); + bit_depth_groupbox_layout->addWidget(playback_bit_depth, 0, 1); + + // COLOR MANAGEMENT -> Bit Depth -> Export + export_bit_depth = new QComboBox(); + /*for (int i=0;iaddItem(olive::pixel_formats.at(i).name, i); + } + export_bit_depth->setCurrentIndex(olive::config.export_bit_depth);*/ + bit_depth_groupbox_layout->addWidget(new QLabel(tr("Export (Online):")), 0, 2); + bit_depth_groupbox_layout->addWidget(export_bit_depth, 0, 3); + + color_management_layout->addWidget(bit_depth_groupbox, row, 0); + + //row++; + + populate_ocio_menus(OCIO::GetCurrentConfig()); +} + +void PreferencesColorManagementTab::Accept() +{ + +} + +void PreferencesColorManagementTab::populate_ocio_menus(OCIO::ConstConfigRcPtr config) +{ + if (!config) { + + // Just clear everything + ocio_display->clear(); + ocio_default_input->clear(); + ocio_view->clear(); + ocio_look->clear(); + + } else { + + // Get input color spaces for setting the default input color space + ocio_default_input->clear(); + for (int i=0;igetNumColorSpaces();i++) { + QString colorspace = config->getColorSpaceNameByIndex(i); + + ocio_default_input->addItem(colorspace); + + /*if (colorspace == olive::config.ocio_default_input_colorspace) { + ocio_default_input->setCurrentIndex(i); + }*/ + } + + // Get current display name (if the config is empty, get the current default display) + /*QString current_display = olive::config.ocio_display; + if (current_display.isEmpty()) { + current_display = config->getDefaultDisplay(); + }*/ + + // Populate the display menu + ocio_display->clear(); + for (int i=0;igetNumDisplays();i++) { + ocio_display->addItem(config->getDisplay(i)); + + // Check if this index is the currently selected + /*if (config->getDisplay(i) == current_display) { + ocio_display->setCurrentIndex(i); + }*/ + } + + update_ocio_view_menu(config); + + // Populate the look menu + ocio_look->clear(); + ocio_look->addItem(tr("(None)"), QString()); + for (int i=0;igetNumLooks();i++) { + const char* look = config->getLookNameByIndex(i); + + ocio_look->addItem(look, look); + + /*if (look == olive::config.ocio_look) { + ocio_look->setCurrentIndex(i+1); + }*/ + } + + } +} + +OCIO::ConstConfigRcPtr PreferencesColorManagementTab::TestOCIOConfig(const QString &url) +{ + // Check whether OCIO can load it + OCIO::ConstConfigRcPtr config; + try { + config = OCIO::Config::CreateFromFile(url.toUtf8()); + } catch (OCIO::Exception& e) { + QMessageBox::critical(this, + tr("OpenColorIO Config Error"), + tr("Failed to set OpenColorIO configuration: %1").arg(e.what()), + QMessageBox::Ok); + } + return config; +} + +void PreferencesColorManagementTab::update_ocio_view_menu(OCIO::ConstConfigRcPtr config) +{ + + // Get views for the current display set in `ocio_display` + QString display = ocio_display->currentText(); + + // Get current view + /*QString current_view = olive::config.ocio_view; + if (current_view.isEmpty()) { + current_view = config->getDefaultView(display.toUtf8()); + }*/ + + // Populate the view menu + int ocio_view_count = config->getNumViews(display.toUtf8()); + ocio_view->clear(); + for (int i=0;igetView(display.toUtf8(), i); + + ocio_view->addItem(view); + + /*if (current_view == view) { + ocio_view->setCurrentIndex(i); + }*/ + } +} + +void PreferencesColorManagementTab::update_ocio_config(const QString &s) +{ + OCIO::ConstConfigRcPtr file_config; + + if (!s.isEmpty() && QFileInfo::exists(s)) { + file_config = TestOCIOConfig(s); + } + + populate_ocio_menus(file_config); +} + +void PreferencesColorManagementTab::browse_ocio_config() +{ + QString fn = QFileDialog::getOpenFileName(this, tr("Browse for OpenColorIO configuration")); + if (!fn.isEmpty()) { + ocio_config_file->setText(fn); + } +} + +void PreferencesColorManagementTab::update_ocio_view_menu() +{ + update_ocio_view_menu(OCIO::GetCurrentConfig()); +} diff --git a/app/dialog/preferences/tabs/preferencescolormanagementtab.h b/app/dialog/preferences/tabs/preferencescolormanagementtab.h new file mode 100644 index 000000000..99190082e --- /dev/null +++ b/app/dialog/preferences/tabs/preferencescolormanagementtab.h @@ -0,0 +1,52 @@ +#ifndef PREFERENCESCOLORMANAGEMENTTAB_H +#define PREFERENCESCOLORMANAGEMENTTAB_H + +#include +#include +#include +#include +namespace OCIO = OCIO_NAMESPACE::v1; + +#include "preferencestab.h" + +class PreferencesColorManagementTab : public PreferencesTab +{ + Q_OBJECT +public: + PreferencesColorManagementTab(); + + virtual void Accept() override; + +private slots: + // OCIO function + void browse_ocio_config(); + void update_ocio_view_menu(); + void update_ocio_view_menu(OCIO::ConstConfigRcPtr config); + void update_ocio_config(const QString&); + +private: + /** + * @brief Tests an OpenColorIO configuration file to determine whether it's valid and throws a messagebox if not + * + * @param url + * + * URL to the OpenColorIO configuration file. + * + * @return + * + * A OCIO::ConstConfigRcPtr config pointer if the configuration file is valid, nullptr if not. + */ + OCIO::ConstConfigRcPtr TestOCIOConfig(const QString& url); + + void populate_ocio_menus(OCIO::ConstConfigRcPtr config); + + QLineEdit* ocio_config_file; + QComboBox* ocio_default_input; + QComboBox* ocio_display; + QComboBox* ocio_view; + QComboBox* ocio_look; + QComboBox* playback_bit_depth; + QComboBox* export_bit_depth; +}; + +#endif // PREFERENCESCOLORMANAGEMENTTAB_H diff --git a/app/dialog/preferences/tabs/preferencesgeneraltab.cpp b/app/dialog/preferences/tabs/preferencesgeneraltab.cpp new file mode 100644 index 000000000..789882daa --- /dev/null +++ b/app/dialog/preferences/tabs/preferencesgeneraltab.cpp @@ -0,0 +1,110 @@ +#include "preferencesgeneraltab.h" + +#include +#include +#include +#include +#include + +PreferencesGeneralTab::PreferencesGeneralTab() +{ + QGridLayout* general_layout = new QGridLayout(this); + + int row = 0; + + // General -> Language + general_layout->addWidget(new QLabel(tr("Language:")), row, 0); + + language_combobox = new QComboBox(); + + // add default language (en-US) + language_combobox->addItem(QLocale::languageToString(QLocale("en-US").language())); + + /* + // add languages from file + QList translation_paths = get_language_paths(); + + // iterate through all language search paths + for (int j=0;jaddItem(QLocale(locale_str).nativeLanguageName(), locale_relative_path); + + if (olive::config.language_file == locale_relative_path) { + language_combobox->setCurrentIndex(language_combobox->count() - 1); + } + } + } + } + */ + + general_layout->addWidget(language_combobox, row, 1, 1, 4); + + row++; + + // General -> Thumbnail and Waveform Resolution + general_layout->addWidget(new QLabel(tr("Thumbnail Resolution:"), this), row, 0); + + thumbnail_res_spinbox = new QSpinBox(this); + thumbnail_res_spinbox->setMinimum(0); + thumbnail_res_spinbox->setMaximum(INT_MAX); + //thumbnail_res_spinbox->setValue(olive::config.thumbnail_resolution); + general_layout->addWidget(thumbnail_res_spinbox, row, 1); + + general_layout->addWidget(new QLabel(tr("Waveform Resolution:"), this), row, 2); + + waveform_res_spinbox = new QSpinBox(this); + waveform_res_spinbox->setMinimum(0); + waveform_res_spinbox->setMaximum(INT_MAX); + //waveform_res_spinbox->setValue(olive::config.waveform_resolution); + general_layout->addWidget(waveform_res_spinbox, row, 3); + + QPushButton* delete_preview_btn = new QPushButton(tr("Delete Previews")); + general_layout->addWidget(delete_preview_btn, row, 4); + //connect(delete_preview_btn, SIGNAL(clicked(bool)), this, SLOT(delete_all_previews())); + + row++; + + QHBoxLayout* misc_general = new QHBoxLayout(); + + // General -> Use Software Fallbacks When Possible + QCheckBox* use_software_fallbacks_checkbox = new QCheckBox(tr("Use Software Fallbacks When Possible")); + //AddBoolPair(use_software_fallbacks_checkbox, &olive::config.use_software_fallback, true); + misc_general->addWidget(use_software_fallbacks_checkbox); + + // General -> Don't Use Proxies When Exporting + QCheckBox* dont_use_proxies_when_exporting = new QCheckBox(tr("Don't Use Proxies When Exporting")); + dont_use_proxies_when_exporting->setToolTip(tr("Use originals instead of proxies when exporting")); + //AddBoolPair(dont_use_proxies_when_exporting, &olive::config.dont_use_proxies_on_export); + misc_general->addWidget(dont_use_proxies_when_exporting); + + // General -> Default Sequence Settings + QPushButton* default_sequence_settings = new QPushButton(tr("Default Sequence Settings")); + connect(default_sequence_settings, SIGNAL(clicked(bool)), this, SLOT(edit_default_sequence_settings())); + misc_general->addWidget(default_sequence_settings); + + general_layout->addLayout(misc_general, row, 0, 1, 5); + + row++; +} + +void PreferencesGeneralTab::Accept() +{ + +} + +void PreferencesGeneralTab::edit_default_sequence_settings() +{ + /*NewSequenceDialog nsd(this, nullptr, &default_sequence); + nsd.SetNameEditable(false); + nsd.exec();*/ +} diff --git a/app/dialog/preferences/tabs/preferencesgeneraltab.h b/app/dialog/preferences/tabs/preferencesgeneraltab.h new file mode 100644 index 000000000..c8364f863 --- /dev/null +++ b/app/dialog/preferences/tabs/preferencesgeneraltab.h @@ -0,0 +1,41 @@ +#ifndef PREFERENCESGENERALTAB_H +#define PREFERENCESGENERALTAB_H + +#include +#include + +#include "preferencestab.h" + +class PreferencesGeneralTab : public PreferencesTab +{ + Q_OBJECT +public: + PreferencesGeneralTab(); + + virtual void Accept() override; + +private slots: + /** + * @brief Shows a NewSequenceDialog attached to default_sequence + */ + void edit_default_sequence_settings(); + +private: + /** + * @brief UI widget for selecting the UI language + */ + QComboBox* language_combobox; + + /** + * @brief UI widget for selecting the resolution of the thumbnails to generate + */ + QSpinBox* thumbnail_res_spinbox; + + /** + * @brief UI widget for selecting the resolution of the waveforms to generate + */ + QSpinBox* waveform_res_spinbox; + +}; + +#endif // PREFERENCESGENERALTAB_H diff --git a/app/dialog/preferences/tabs/preferenceskeyboardtab.cpp b/app/dialog/preferences/tabs/preferenceskeyboardtab.cpp new file mode 100644 index 000000000..e6eb94dcf --- /dev/null +++ b/app/dialog/preferences/tabs/preferenceskeyboardtab.cpp @@ -0,0 +1,214 @@ +#include "preferenceskeyboardtab.h" + +#include +#include +#include +#include +#include +#include + +PreferencesKeyboardTab::PreferencesKeyboardTab(QMenuBar *menubar) +{ + QVBoxLayout* shortcut_layout = new QVBoxLayout(this); + + QLineEdit* key_search_line = new QLineEdit(); + key_search_line->setPlaceholderText(tr("Search for action or shortcut")); + connect(key_search_line, SIGNAL(textChanged(const QString &)), this, SLOT(refine_shortcut_list(const QString &))); + + shortcut_layout->addWidget(key_search_line); + + keyboard_tree = new QTreeWidget(); + QTreeWidgetItem* tree_header = keyboard_tree->headerItem(); + tree_header->setText(0, tr("Action")); + tree_header->setText(1, tr("Shortcut")); + shortcut_layout->addWidget(keyboard_tree); + + QHBoxLayout* reset_shortcut_layout = new QHBoxLayout(); + + QPushButton* import_shortcut_button = new QPushButton(tr("Import")); + reset_shortcut_layout->addWidget(import_shortcut_button); + connect(import_shortcut_button, SIGNAL(clicked(bool)), this, SLOT(load_shortcut_file())); + + QPushButton* export_shortcut_button = new QPushButton(tr("Export")); + reset_shortcut_layout->addWidget(export_shortcut_button); + connect(export_shortcut_button, SIGNAL(clicked(bool)), this, SLOT(save_shortcut_file())); + + reset_shortcut_layout->addStretch(); + + QPushButton* reset_selected_shortcut_button = new QPushButton(tr("Reset Selected")); + reset_shortcut_layout->addWidget(reset_selected_shortcut_button); + connect(reset_selected_shortcut_button, SIGNAL(clicked(bool)), this, SLOT(reset_default_shortcut())); + + QPushButton* reset_all_shortcut_button = new QPushButton(tr("Reset All")); + reset_shortcut_layout->addWidget(reset_all_shortcut_button); + connect(reset_all_shortcut_button, SIGNAL(clicked(bool)), this, SLOT(reset_all_shortcuts())); + + shortcut_layout->addLayout(reset_shortcut_layout); + + setup_kbd_shortcuts(menubar); +} + +void PreferencesKeyboardTab::Accept() +{ + +} + +void PreferencesKeyboardTab::setup_kbd_shortcuts(QMenuBar* menubar) { + QList menus = menubar->actions(); + + for (int i=0;imenu(); + + QTreeWidgetItem* item = new QTreeWidgetItem(keyboard_tree); + item->setText(0, menu->title().replace("&", "")); + + keyboard_tree->addTopLevelItem(item); + + setup_kbd_shortcut_worker(menu, item); + } + + for (int i=0;iproperty("id").isNull()) { + KeySequenceEditor* editor = new KeySequenceEditor(keyboard_tree, key_shortcut_actions.at(i)); + keyboard_tree->setItemWidget(key_shortcut_items.at(i), 1, editor); + key_shortcut_fields.append(editor); + } + } +} + +void PreferencesKeyboardTab::setup_kbd_shortcut_worker(QMenu* menu, QTreeWidgetItem* parent) { + QList actions = menu->actions(); + for (int i=0;iisSeparator() && a->property("keyignore").isNull()) { + QTreeWidgetItem* item = new QTreeWidgetItem(parent); + item->setText(0, a->text().replace("&", "")); + + parent->addChild(item); + + if (a->menu() != nullptr) { + item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); + setup_kbd_shortcut_worker(a->menu(), item); + } else { + key_shortcut_items.append(item); + key_shortcut_actions.append(a); + } + } + } +} + +void PreferencesKeyboardTab::reset_default_shortcut() { + QList items = keyboard_tree->selectedItems(); + for (int i=0;iselectedItems().at(i); + static_cast(keyboard_tree->itemWidget(item, 1))->reset_to_default(); + } +} + +void PreferencesKeyboardTab::reset_all_shortcuts() { + if (QMessageBox::question( + this, + tr("Confirm Reset All Shortcuts"), + tr("Are you sure you wish to reset all keyboard shortcuts to their defaults?"), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + for (int i=0;ireset_to_default(); + } + } +} + +bool PreferencesKeyboardTab::refine_shortcut_list(const QString &s, QTreeWidgetItem* parent) { + if (parent == nullptr) { + for (int i=0;itopLevelItemCount();i++) { + refine_shortcut_list(s, keyboard_tree->topLevelItem(i)); + } + } else { + parent->setExpanded(!s.isEmpty()); + + bool all_children_are_hidden = !s.isEmpty(); + + for (int i=0;ichildCount();i++) { + QTreeWidgetItem* item = parent->child(i); + if (item->childCount() > 0) { + all_children_are_hidden = refine_shortcut_list(s, item); + } else { + item->setHidden(false); + if (s.isEmpty()) { + all_children_are_hidden = false; + } else { + QString shortcut; + if (keyboard_tree->itemWidget(item, 1) != nullptr) { + shortcut = static_cast(keyboard_tree->itemWidget(item, 1))->keySequence().toString(); + } + if (item->text(0).contains(s, Qt::CaseInsensitive) || shortcut.contains(s, Qt::CaseInsensitive)) { + all_children_are_hidden = false; + } else { + item->setHidden(true); + } + } + } + } + + if (parent->text(0).contains(s, Qt::CaseInsensitive)) all_children_are_hidden = false; + + parent->setHidden(all_children_are_hidden); + + return all_children_are_hidden; + } + return true; +} + +void PreferencesKeyboardTab::load_shortcut_file() { + QString fn = QFileDialog::getOpenFileName(this, tr("Import Keyboard Shortcuts")); + if (!fn.isEmpty()) { + QFile f(fn); + if (f.exists() && f.open(QFile::ReadOnly)) { + QByteArray ba = f.readAll(); + f.close(); + for (int i=0;iaction_name()); + if (index == 0 || (index > 0 && ba.at(index-1) == '\n')) { + while (index < ba.size() && ba.at(index) != '\t') index++; + QString ks; + index++; + while (index < ba.size() && ba.at(index) != '\n') { + ks.append(ba.at(index)); + index++; + } + key_shortcut_fields.at(i)->setKeySequence(ks); + } else { + key_shortcut_fields.at(i)->reset_to_default(); + } + } + } else { + QMessageBox::critical( + this, + tr("Error saving shortcuts"), + tr("Failed to open file for reading") + ); + } + } +} + +void PreferencesKeyboardTab::save_shortcut_file() { + QString fn = QFileDialog::getSaveFileName(this, tr("Export Keyboard Shortcuts")); + if (!fn.isEmpty()) { + QFile f(fn); + if (f.open(QFile::WriteOnly)) { + bool start = true; + for (int i=0;iexport_shortcut(); + if (!s.isEmpty()) { + if (!start) f.write("\n"); + f.write(s.toUtf8()); + start = false; + } + } + f.close(); + QMessageBox::information(this, tr("Export Shortcuts"), tr("Shortcuts exported successfully")); + } else { + QMessageBox::critical(this, tr("Error saving shortcuts"), tr("Failed to open file for writing")); + } + } +} diff --git a/app/dialog/preferences/tabs/preferenceskeyboardtab.h b/app/dialog/preferences/tabs/preferenceskeyboardtab.h new file mode 100644 index 000000000..139525ad7 --- /dev/null +++ b/app/dialog/preferences/tabs/preferenceskeyboardtab.h @@ -0,0 +1,115 @@ +#ifndef PREFERENCESKEYBOARDTAB_H +#define PREFERENCESKEYBOARDTAB_H + +#include +#include + +#include "preferencestab.h" +#include "../keysequenceeditor.h" + +class PreferencesKeyboardTab : public PreferencesTab +{ + Q_OBJECT +public: + PreferencesKeyboardTab(QMenuBar* menubar); + + virtual void Accept() override; + +private slots: + /** + * @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 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(); + + /** + * @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); + +private: + /** + * @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); + + /** + * @brief UI widget for editing keyboard shortcuts + */ + QTreeWidget* keyboard_tree; + + /** + * @brief List of keyboard shortcut actions that can be triggered (links with key_shortcut_items and + * key_shortcut_fields) + */ + QVector key_shortcut_actions; + + /** + * @brief List of keyboard shortcut items in keyboard_tree corresponding to existing actions (links with + * key_shortcut_actions and key_shortcut_fields) + */ + QVector key_shortcut_items; + + /** + * @brief List of keyboard shortcut editing fields in keyboard_tree corresponding to existing actions (links with + * key_shortcut_actions and key_shortcut_fields) + */ + QVector key_shortcut_fields; +}; + +#endif // PREFERENCESKEYBOARDTAB_H diff --git a/app/dialog/preferences/tabs/preferencesplaybacktab.cpp b/app/dialog/preferences/tabs/preferencesplaybacktab.cpp new file mode 100644 index 000000000..5d21e773e --- /dev/null +++ b/app/dialog/preferences/tabs/preferencesplaybacktab.cpp @@ -0,0 +1,14 @@ +#include "preferencesplaybacktab.h" + +#include +#include +#include + +PreferencesPlaybackTab::PreferencesPlaybackTab() +{ +} + +void PreferencesPlaybackTab::Accept() +{ + +} diff --git a/app/dialog/preferences/tabs/preferencesplaybacktab.h b/app/dialog/preferences/tabs/preferencesplaybacktab.h new file mode 100644 index 000000000..00321ec0f --- /dev/null +++ b/app/dialog/preferences/tabs/preferencesplaybacktab.h @@ -0,0 +1,20 @@ +#ifndef PREFERENCESPLAYBACKTAB_H +#define PREFERENCESPLAYBACKTAB_H + +#include +#include + +#include "preferencestab.h" + +class PreferencesPlaybackTab : public PreferencesTab +{ + Q_OBJECT +public: + PreferencesPlaybackTab(); + + virtual void Accept() override; + +private: +}; + +#endif // PREFERENCESPLAYBACKTAB_H diff --git a/app/dialog/preferences/tabs/preferencestab.cpp b/app/dialog/preferences/tabs/preferencestab.cpp new file mode 100644 index 000000000..1fad11b7e --- /dev/null +++ b/app/dialog/preferences/tabs/preferencestab.cpp @@ -0,0 +1,6 @@ +#include "preferencestab.h" + +PreferencesTab::PreferencesTab() +{ + +} diff --git a/app/dialog/preferences/tabs/preferencestab.h b/app/dialog/preferences/tabs/preferencestab.h new file mode 100644 index 000000000..9dcfc6f2a --- /dev/null +++ b/app/dialog/preferences/tabs/preferencestab.h @@ -0,0 +1,16 @@ +#ifndef PREFERENCESTAB_H +#define PREFERENCESTAB_H + +#include + +#include "config/config.h" + +class PreferencesTab : public QWidget +{ +public: + PreferencesTab(); + + virtual void Accept() = 0; +}; + +#endif // PREFERENCESTAB_H diff --git a/app/main.cpp b/app/main.cpp index cdc7f0a87..6b2e7579f 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -57,6 +57,8 @@ int main(int argc, char *argv[]) { QString app_version = "0.2.0"; #ifdef GITHASH + // Anything after the hyphen is considered "unimportant" information. Text BEFORE the hyphen is used in version + // checking project files and config files app_version.append("-"); app_version.append(GITHASH); #endif diff --git a/app/project/item/folder/folder.cpp b/app/project/item/folder/folder.cpp index 2de856664..4e37ea98f 100644 --- a/app/project/item/folder/folder.cpp +++ b/app/project/item/folder/folder.cpp @@ -24,7 +24,6 @@ Folder::Folder() { - set_icon(olive::icon::Folder); } Item::Type Folder::type() const @@ -36,3 +35,8 @@ bool Folder::CanHaveChildren() const { return true; } + +QIcon Folder::icon() +{ + return olive::icon::Folder; +} diff --git a/app/project/item/folder/folder.h b/app/project/item/folder/folder.h index 7d9a68a71..cbbba9d36 100644 --- a/app/project/item/folder/folder.h +++ b/app/project/item/folder/folder.h @@ -38,6 +38,8 @@ public: virtual bool CanHaveChildren() const override; + virtual QIcon icon() override; + private: }; diff --git a/app/project/item/footage/footage.cpp b/app/project/item/footage/footage.cpp index cae7d7c5d..8bfee24f5 100644 --- a/app/project/item/footage/footage.cpp +++ b/app/project/item/footage/footage.cpp @@ -43,8 +43,6 @@ void Footage::set_status(const Footage::Status &status) { status_ = status; - UpdateIcon(); - UpdateTooltip(); } @@ -116,6 +114,38 @@ void Footage::set_decoder(const QString &id) decoder_ = id; } +QIcon Footage::icon() +{ + switch (status_) { + case kUnprobed: + case kUnindexed: + // FIXME Set a waiting icon + return QIcon(); + case kReady: + if (HasStreamsOfType(Stream::kVideo)) { + + // Prioritize the video icon + return olive::icon::Video; + + } else if (HasStreamsOfType(Stream::kAudio)) { + + // Otherwise assume it's audio only + return olive::icon::Audio; + + } else if (HasStreamsOfType(Stream::kImage)) { + + // Otherwise assume it's an image + return olive::icon::Image; + + } + /* fall through */ + case kInvalid: + return olive::icon::Error; + } + + return QIcon(); +} + void Footage::ClearStreams() { if (streams_.empty()) { @@ -138,41 +168,6 @@ bool Footage::HasStreamsOfType(const Stream::Type type) return false; } -void Footage::UpdateIcon() -{ - switch (status_) { - case kUnprobed: - case kUnindexed: - // FIXME Set a waiting icon - set_icon(QIcon()); - break; - case kReady: - if (HasStreamsOfType(Stream::kVideo)) { - - // Prioritize the video icon - set_icon(olive::icon::Video); - break; - - } else if (HasStreamsOfType(Stream::kAudio)) { - - // Otherwise assume it's audio only - set_icon(olive::icon::Audio); - break; - - } else if (HasStreamsOfType(Stream::kImage)) { - - // Otherwise assume it's an image - set_icon(olive::icon::Image); - break; - - } - /* fall through */ - case kInvalid: - set_icon(olive::icon::Error); - break; - } -} - void Footage::UpdateTooltip() { switch (status_) { diff --git a/app/project/item/footage/footage.h b/app/project/item/footage/footage.h index 740c4f728..130aaa2d3 100644 --- a/app/project/item/footage/footage.h +++ b/app/project/item/footage/footage.h @@ -205,6 +205,8 @@ public: */ void set_decoder(const QString& id); + virtual QIcon icon() override; + private: /** * @brief Internal function to delete all Stream children and empty the array diff --git a/app/project/item/item.cpp b/app/project/item/item.cpp index 0017001c0..d930b2b3b 100644 --- a/app/project/item/item.cpp +++ b/app/project/item/item.cpp @@ -101,16 +101,6 @@ void Item::set_tooltip(const QString &t) tooltip_ = t; } -const QIcon &Item::icon() -{ - return icon_; -} - -void Item::set_icon(const QIcon &icon) -{ - icon_ = icon; -} - Item *Item::parent() const { return parent_; diff --git a/app/project/item/item.h b/app/project/item/item.h index 9368d5295..2fa065792 100644 --- a/app/project/item/item.h +++ b/app/project/item/item.h @@ -92,8 +92,7 @@ public: const QString& tooltip() const; void set_tooltip(const QString& t); - const QIcon& icon(); - void set_icon(const QIcon& icon); + virtual QIcon icon() = 0; Item *parent() const; const Item* root() const; @@ -111,8 +110,6 @@ private: QString name_; - QIcon icon_; - QString tooltip_; }; diff --git a/app/project/item/sequence/sequence.cpp b/app/project/item/sequence/sequence.cpp index 7b604da11..ad14e04e0 100644 --- a/app/project/item/sequence/sequence.cpp +++ b/app/project/item/sequence/sequence.cpp @@ -25,7 +25,6 @@ Sequence::Sequence() { - set_icon(olive::icon::Sequence); } Item::Type Sequence::type() const @@ -33,6 +32,11 @@ Item::Type Sequence::type() const return kSequence; } +QIcon Sequence::icon() +{ + return olive::icon::Sequence; +} + const int &Sequence::video_width() { return video_width_; diff --git a/app/project/item/sequence/sequence.h b/app/project/item/sequence/sequence.h index a547af2d8..77a7f1681 100644 --- a/app/project/item/sequence/sequence.h +++ b/app/project/item/sequence/sequence.h @@ -38,6 +38,8 @@ public: */ virtual Type type() const override; + virtual QIcon icon() override; + /* VIDEO GETTER/SETTER FUNCTIONS */ const int& video_width(); diff --git a/app/ui/icons/icons.cpp b/app/ui/icons/icons.cpp index bdbed2a7f..080fec62d 100644 --- a/app/ui/icons/icons.cpp +++ b/app/ui/icons/icons.cpp @@ -123,7 +123,7 @@ QIcon olive::icon::Create(const QString& theme, const QString &name) QIcon icon; for (int i=0;i + palette.ini style.css png/add-button.16.png png/add-button.32.png diff --git a/app/ui/style/olive-dark/palette.ini b/app/ui/style/olive-dark/palette.ini new file mode 100644 index 000000000..91d617459 --- /dev/null +++ b/app/ui/style/olive-dark/palette.ini @@ -0,0 +1,18 @@ +[All] +AlternateBase=#353535 +Base=#191919 +BrightText=#FF0000 +Button=#353535 +ButtonText=#FFFFFF +Disabled-ButtonText=#808080 +Highlight=#2A82DA +HighlightedText=#FFFFFF +Link=#2A82DA +Text=#FFFFFF +ToolTipBase=#191919 +ToolTipText=#FFFFFF +Window=#353535 +WindowText=#FFFFFF + +[Disabled] +ButtonText=#808080 diff --git a/app/ui/style/olive-dark/style.css b/app/ui/style/olive-dark/style.css index b3f4d6722..76cb5bf54 100644 --- a/app/ui/style/olive-dark/style.css +++ b/app/ui/style/olive-dark/style.css @@ -18,56 +18,6 @@ ***/ -/*** - - Olive Dark - Qt CSS Theme - - A fairly basic CSS style for the Olive Video Editor/Qt Fusion. - - The primary colors are: - - Main: #353535 - Text: #ffffff - Disabled Text: #808080 - Highlight: #2a82da - Highlight Text: #ffffff - Dark: #191919 - -**/ - -/* Default widget colors */ -QWidget, QMenu::separator { - /* Main */ - background: #353535; - - /* Text */ - color: #ffffff; - - /* Highlight */ - selection-background-color: #2a82da; - - /* Highlight Text */ - selection-color: #ffffff; -} - -/* Default disabled colors */ -QWidget::disabled { - /* Disabled Text */ - color: #808080; -} - -/* Default link color */ -a { - /* Highlight */ - color: #2a82da; -} - -/* All of these widgets' backgrounds are dark */ -QTreeView, QListView, QLineEdit, QMenu, QProgressBar, QPushButton::checked, NodeView, QComboBox, QSpinBox { - /* Dark */ - background: #191919; -} - /* Node styling */ NodeViewItemWidget { qproperty-titlebarColor: #4040a0; diff --git a/app/ui/style/olive-light/olive-light.qrc b/app/ui/style/olive-light/olive-light.qrc index 40ee077f2..a1469343d 100644 --- a/app/ui/style/olive-light/olive-light.qrc +++ b/app/ui/style/olive-light/olive-light.qrc @@ -1,5 +1,6 @@ + palette.ini style.css png/add-button.16.png png/add-button.32.png diff --git a/app/ui/style/olive-light/palette.ini b/app/ui/style/olive-light/palette.ini new file mode 100644 index 000000000..5bdd02051 --- /dev/null +++ b/app/ui/style/olive-light/palette.ini @@ -0,0 +1,17 @@ +[All] +AlternateBase=#D0D0D0 +Base=#F0F0F0 +BrightText=#FF0000 +Button=#D0D0D0 +ButtonText=#000000 +Highlight=#2A82DA +HighlightedText=#FFFFFF +Link=#2A82DA +Text=#000000 +ToolTipBase=#FFFFFF +ToolTipText=#000000 +Window=#D0D0D0 +WindowText=#000000 + +[Disabled] +ButtonText=#D0D0D0 diff --git a/app/ui/style/olive-light/style.css b/app/ui/style/olive-light/style.css index cc660afb4..fed59b174 100644 --- a/app/ui/style/olive-light/style.css +++ b/app/ui/style/olive-light/style.css @@ -18,56 +18,6 @@ ***/ -/*** - - Olive Light - Qt CSS Theme - - A fairly basic CSS style for the Olive Video Editor/Qt Fusion. - - The primary colors are: - - Main: #d0d0d0 - Text: #000000 - Disabled Text: #808080 - Highlight: #2a82da - Highlight Text: #ffffff - Dark: #ffffff - -**/ - -/* Default widget colors */ -QWidget, QMenu::separator { - /* Main */ - background: #d0d0d0; - - /* Text */ - color: #000000; - - /* Highlight */ - selection-background-color: #2a82da; - - /* Highlight Text */ - selection-color: #ffffff; -} - -/* Default disabled colors */ -QWidget::disabled { - /* Disabled Text */ - color: #808080; -} - -/* Default link color */ -a { - /* Highlight */ - color: #2a82da; -} - -/* All of these widgets' backgrounds are dark */ -QTreeView, QListView, QLineEdit, QMenu, QProgressBar, QPushButton::checked, NodeView, QComboBox, QSpinBox { - /* Dark */ - background: #ffffff; -} - /* Node styling */ NodeViewItemWidget { qproperty-titlebarColor: #a0a0ff; diff --git a/app/ui/style/style.cpp b/app/ui/style/style.cpp index c24c513bf..6015297f3 100644 --- a/app/ui/style/style.cpp +++ b/app/ui/style/style.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -29,28 +30,151 @@ #include "ui/icons/icons.h" -void olive::style::AppSetDefault() +QList StyleManager::ListInternal() { - // FIXME: Fixed theme, allow the user to set this in-app - SetOliveStyle("olive-dark"); + QList style_list; + + style_list.append(StyleDescriptor(tr("Olive Dark"), ":/style/olive-dark")); + style_list.append(StyleDescriptor(tr("Olive Light"), ":/style/olive-light")); + + return style_list; } -void olive::style::SetOliveStyle(const QString &style_name) +QPalette StyleManager::ParsePalette(const QString& ini_path) { - qApp->setStyle(QStyleFactory::create("Fusion")); + QSettings ini(ini_path, QSettings::IniFormat); + QPalette palette; + + ParsePaletteGroup(&ini, &palette, QPalette::All); + ParsePaletteGroup(&ini, &palette, QPalette::Active); + ParsePaletteGroup(&ini, &palette, QPalette::Inactive); + ParsePaletteGroup(&ini, &palette, QPalette::Disabled); + + return palette; +} + +void StyleManager::ParsePaletteGroup(QSettings *ini, QPalette *palette, QPalette::ColorGroup group) +{ + QString group_name; + + switch (group) { + case QPalette::All: + group_name = "All"; + break; + case QPalette::Active: + group_name = "Active"; + break; + case QPalette::Inactive: + group_name = "Inactive"; + break; + case QPalette::Disabled: + group_name = "Disabled"; + break; + default: + return; + } + + ini->beginGroup(group_name); + + QStringList keys = ini->childKeys(); + foreach (QString k, keys) { + ParsePaletteColor(ini, palette, group, k); + } + + ini->endGroup(); +} + +void StyleManager::ParsePaletteColor(QSettings *ini, QPalette *palette, QPalette::ColorGroup group, const QString &role_name) +{ + QPalette::ColorRole role; + + if (!QString::compare(role_name, "Window", Qt::CaseInsensitive)) { + role = QPalette::Window; + } else if (!QString::compare(role_name, "WindowText", Qt::CaseInsensitive)) { + role = QPalette::WindowText; + } else if (!QString::compare(role_name, "Base", Qt::CaseInsensitive)) { + role = QPalette::Base; + } else if (!QString::compare(role_name, "AlternateBase", Qt::CaseInsensitive)) { + role = QPalette::AlternateBase; + } else if (!QString::compare(role_name, "ToolTipBase", Qt::CaseInsensitive)) { + role = QPalette::ToolTipBase; + } else if (!QString::compare(role_name, "ToolTipText", Qt::CaseInsensitive)) { + role = QPalette::ToolTipText; + } else if (!QString::compare(role_name, "PlaceholderText", Qt::CaseInsensitive)) { + role = QPalette::PlaceholderText; + } else if (!QString::compare(role_name, "Text", Qt::CaseInsensitive)) { + role = QPalette::Text; + } else if (!QString::compare(role_name, "Button", Qt::CaseInsensitive)) { + role = QPalette::Button; + } else if (!QString::compare(role_name, "ButtonText", Qt::CaseInsensitive)) { + role = QPalette::ButtonText; + } else if (!QString::compare(role_name, "BrightText", Qt::CaseInsensitive)) { + role = QPalette::BrightText; + } else if (!QString::compare(role_name, "Highlight", Qt::CaseInsensitive)) { + role = QPalette::Highlight; + } else if (!QString::compare(role_name, "HighlightedText", Qt::CaseInsensitive)) { + role = QPalette::HighlightedText; + } else if (!QString::compare(role_name, "Link", Qt::CaseInsensitive)) { + role = QPalette::Link; + } else if (!QString::compare(role_name, "LinkVisited", Qt::CaseInsensitive)) { + role = QPalette::LinkVisited; + } else { + return; + } + + palette->setColor(group, role, QColor(ini->value(role_name).toString())); +} + +StyleDescriptor StyleManager::DefaultStyle() +{ + return ListInternal().first(); +} + +void StyleManager::SetStyle(const StyleDescriptor &style) +{ + SetStyle(style.path()); +} + +void StyleManager::SetStyle(const QString &style_path) +{ + // Load all icons for this style (icons must be loaded first because the style change below triggers the icon change) + olive::icon::LoadAll(style_path); + + // Set palette for this + QString palette_file = QString("%1/palette.ini").arg(style_path); + if (QFileInfo::exists(palette_file)) { + qApp->setPalette(ParsePalette(palette_file)); + } else { + qApp->setPalette(qApp->style()->standardPalette()); + } // Set CSS style for this - QFile css_file(QString(":/style/%1/style.css").arg(style_name)); + QFile css_file(QString("%1/style.css").arg(style_path)); - if (css_file.open(QFile::ReadOnly | QFile::Text)) { + if (css_file.exists() && css_file.open(QFile::ReadOnly | QFile::Text)) { // Read in entire CSS from file and set as the application stylesheet QTextStream css_ts(&css_file); qApp->setStyleSheet(css_ts.readAll()); css_file.close(); + } else { + qApp->setStyleSheet(QString()); } +} - // Load all icons for this style - olive::icon::LoadAll(style_name); +StyleDescriptor::StyleDescriptor(const QString &name, const QString &path) : + name_(name), + path_(path) +{ +} + +const QString &StyleDescriptor::name() const +{ + return name_; +} + +const QString &StyleDescriptor::path() const +{ + return path_; } diff --git a/app/ui/style/style.h b/app/ui/style/style.h index a8114e46d..b671572aa 100644 --- a/app/ui/style/style.h +++ b/app/ui/style/style.h @@ -21,23 +21,39 @@ #ifndef STYLEMANAGER_H #define STYLEMANAGER_H +#include #include -namespace olive { -namespace style { +class StyleDescriptor { +public: + StyleDescriptor(const QString& name, const QString& path); -/** - * @brief Sets the application style to "Olive Default" - * - * This function should probably be replaced (or at least renamed) later as alternative styles are reimplemented. - * At the moment, this is a convenience function for setting to "Olive Default" which is a cross-platform default - * style used in Olive. - */ -void AppSetDefault(); + const QString& name() const; + const QString& path() const; -void SetOliveStyle(const QString& style_name); +private: + QString name_; + QString path_; +}; -} -} +class StyleManager : public QObject { +public: + StyleManager(); + + static StyleDescriptor DefaultStyle(); + + static void SetStyle(const StyleDescriptor& style); + + static void SetStyle(const QString& style_path); + + static QList ListInternal(); + +private: + static QPalette ParsePalette(const QString& ini_path); + + static void ParsePaletteGroup(QSettings* ini, QPalette* palette, QPalette::ColorGroup group); + + static void ParsePaletteColor(QSettings* ini, QPalette* palette, QPalette::ColorGroup group, const QString& role_name); +}; #endif // STYLEMANAGER_H diff --git a/app/widget/CMakeLists.txt b/app/widget/CMakeLists.txt index cb0bee103..4fc552fbb 100644 --- a/app/widget/CMakeLists.txt +++ b/app/widget/CMakeLists.txt @@ -14,6 +14,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +add_subdirectory(columnedgridlayout) add_subdirectory(flowlayout) add_subdirectory(footagecombobox) add_subdirectory(menu) diff --git a/app/widget/columnedgridlayout/CMakeLists.txt b/app/widget/columnedgridlayout/CMakeLists.txt new file mode 100644 index 000000000..c23d2b8d9 --- /dev/null +++ b/app/widget/columnedgridlayout/CMakeLists.txt @@ -0,0 +1,22 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2019 Olive Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + widget/columnedgridlayout/columnedgridlayout.h + widget/columnedgridlayout/columnedgridlayout.cpp + PARENT_SCOPE +) diff --git a/app/widget/columnedgridlayout/columnedgridlayout.cpp b/app/widget/columnedgridlayout/columnedgridlayout.cpp new file mode 100644 index 000000000..6404e6c96 --- /dev/null +++ b/app/widget/columnedgridlayout/columnedgridlayout.cpp @@ -0,0 +1,34 @@ +#include "columnedgridlayout.h" + +ColumnedGridLayout::ColumnedGridLayout(QWidget* parent, + int maximum_columns) : + QGridLayout (parent), + maximum_columns_(maximum_columns) +{ +} + +void ColumnedGridLayout::Add(QWidget *widget) +{ + if (maximum_columns_ > 0) { + + int row = count() / maximum_columns_; + int column = count() % maximum_columns_; + + addWidget(widget, row, column); + + } else { + + addWidget(widget); + + } +} + +int ColumnedGridLayout::MaximumColumns() const +{ + return maximum_columns_; +} + +void ColumnedGridLayout::SetMaximumColumns(int maximum_columns) +{ + maximum_columns_ = maximum_columns; +} diff --git a/app/widget/columnedgridlayout/columnedgridlayout.h b/app/widget/columnedgridlayout/columnedgridlayout.h new file mode 100644 index 000000000..d62eaa6d7 --- /dev/null +++ b/app/widget/columnedgridlayout/columnedgridlayout.h @@ -0,0 +1,27 @@ +#ifndef COLUMNEDGRIDLAYOUT_H +#define COLUMNEDGRIDLAYOUT_H + +#include + +/** + * @brief The ColumnedGridLayout class + * + * A simple derivative of QGridLayout that provides a automatic row/column layout based on a specified maximum + * column count. + */ +class ColumnedGridLayout : public QGridLayout +{ + Q_OBJECT +public: + ColumnedGridLayout(QWidget* parent = nullptr, + int maximum_columns = 0); + + void Add(QWidget* widget); + int MaximumColumns() const; + void SetMaximumColumns(int maximum_columns); + +private: + int maximum_columns_; +}; + +#endif // COLUMNEDGRIDLAYOUT_H diff --git a/app/widget/playbackcontrols/playbackcontrols.cpp b/app/widget/playbackcontrols/playbackcontrols.cpp index b074a9e3c..c8d20b99a 100644 --- a/app/widget/playbackcontrols/playbackcontrols.cpp +++ b/app/widget/playbackcontrols/playbackcontrols.cpp @@ -20,6 +20,8 @@ #include "playbackcontrols.h" +#include +#include #include #include "common/timecodefunctions.h" @@ -63,28 +65,24 @@ PlaybackControls::PlaybackControls(QWidget *parent) : lower_middle_layout->addStretch(); // Go To Start Button - QPushButton* go_to_start_btn = new QPushButton(); - go_to_start_btn->setIcon(olive::icon::GoToStart); - lower_middle_layout->addWidget(go_to_start_btn); - connect(go_to_start_btn, SIGNAL(clicked(bool)), this, SIGNAL(BeginClicked())); + go_to_start_btn_ = new QPushButton(); + lower_middle_layout->addWidget(go_to_start_btn_); + connect(go_to_start_btn_, SIGNAL(clicked(bool)), this, SIGNAL(BeginClicked())); // Prev Frame Button - QPushButton* prev_frame_btn = new QPushButton(); - prev_frame_btn->setIcon(olive::icon::PrevFrame); - lower_middle_layout->addWidget(prev_frame_btn); - connect(prev_frame_btn, SIGNAL(clicked(bool)), this, SIGNAL(PrevFrameClicked())); + prev_frame_btn_ = new QPushButton(); + lower_middle_layout->addWidget(prev_frame_btn_); + connect(prev_frame_btn_, SIGNAL(clicked(bool)), this, SIGNAL(PrevFrameClicked())); // Play/Pause Button playpause_stack_ = new QStackedWidget(); lower_middle_layout->addWidget(playpause_stack_); play_btn_ = new QPushButton(); - play_btn_->setIcon(olive::icon::Play); playpause_stack_->addWidget(play_btn_); connect(play_btn_, SIGNAL(clicked(bool)), this, SIGNAL(PlayClicked())); pause_btn_ = new QPushButton(); - pause_btn_->setIcon(olive::icon::Pause); playpause_stack_->addWidget(pause_btn_); connect(pause_btn_, SIGNAL(clicked(bool)), this, SIGNAL(PauseClicked())); @@ -93,16 +91,14 @@ PlaybackControls::PlaybackControls(QWidget *parent) : playpause_stack_->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding); // Next Frame Button - QPushButton* next_frame_btn = new QPushButton(); - next_frame_btn->setIcon(olive::icon::NextFrame); - lower_middle_layout->addWidget(next_frame_btn); - connect(next_frame_btn, SIGNAL(clicked(bool)), this, SIGNAL(NextFrameClicked())); + next_frame_btn_ = new QPushButton(); + lower_middle_layout->addWidget(next_frame_btn_); + connect(next_frame_btn_, SIGNAL(clicked(bool)), this, SIGNAL(NextFrameClicked())); // Go To End Button - QPushButton* go_to_end_btn = new QPushButton(); - go_to_end_btn->setIcon(olive::icon::GoToEnd); - lower_middle_layout->addWidget(go_to_end_btn); - connect(go_to_end_btn, SIGNAL(clicked(bool)), this, SIGNAL(EndClicked())); + go_to_end_btn_ = new QPushButton(); + lower_middle_layout->addWidget(go_to_end_btn_); + connect(go_to_end_btn_, SIGNAL(clicked(bool)), this, SIGNAL(EndClicked())); lower_middle_layout->addStretch(); @@ -119,6 +115,8 @@ PlaybackControls::PlaybackControls(QWidget *parent) : lower_right_layout->addStretch(); end_tc_lbl_ = new QLabel("00:00:00;00"); lower_right_layout->addWidget(end_tc_lbl_); + + UpdateIcons(); } void PlaybackControls::SetTimecodeEnabled(bool enabled) @@ -136,7 +134,9 @@ void PlaybackControls::SetTime(const int64_t &r) { Q_ASSERT(time_base_.denominator() != 0); - cur_tc_lbl_->setText(olive::timestamp_to_timecode(r, time_base_, kTimecodeDisplay)); + cur_tc_lbl_->setText(olive::timestamp_to_timecode(r, + time_base_, + olive::CurrentTimecodeDisplay())); } void PlaybackControls::ShowPauseButton() @@ -149,3 +149,22 @@ void PlaybackControls::ShowPlayButton() { playpause_stack_->setCurrentWidget(play_btn_); } + +void PlaybackControls::changeEvent(QEvent *e) +{ + QWidget::changeEvent(e); + + if (e->type() == QEvent::StyleChange) { + UpdateIcons(); + } +} + +void PlaybackControls::UpdateIcons() +{ + go_to_start_btn_->setIcon(olive::icon::GoToStart); + prev_frame_btn_->setIcon(olive::icon::PrevFrame); + play_btn_->setIcon(olive::icon::Play); + pause_btn_->setIcon(olive::icon::Pause); + next_frame_btn_->setIcon(olive::icon::NextFrame); + go_to_end_btn_->setIcon(olive::icon::GoToEnd); +} diff --git a/app/widget/playbackcontrols/playbackcontrols.h b/app/widget/playbackcontrols/playbackcontrols.h index 99b5096e4..610b5bbba 100644 --- a/app/widget/playbackcontrols/playbackcontrols.h +++ b/app/widget/playbackcontrols/playbackcontrols.h @@ -84,7 +84,12 @@ signals: */ void EndClicked(); +protected: + virtual void changeEvent(QEvent *) override; + private: + void UpdateIcons(); + QWidget* lower_left_container_; QWidget* lower_right_container_; @@ -93,8 +98,12 @@ private: rational time_base_; + QPushButton* go_to_start_btn_; + QPushButton* prev_frame_btn_; QPushButton* play_btn_; QPushButton* pause_btn_; + QPushButton* next_frame_btn_; + QPushButton* go_to_end_btn_; QStackedWidget* playpause_stack_; diff --git a/app/widget/projectexplorer/projectexplorernavigation.cpp b/app/widget/projectexplorer/projectexplorernavigation.cpp index 0b93c3c66..308725beb 100644 --- a/app/widget/projectexplorer/projectexplorernavigation.cpp +++ b/app/widget/projectexplorer/projectexplorernavigation.cpp @@ -36,7 +36,6 @@ ProjectExplorerNavigation::ProjectExplorerNavigation(QWidget *parent) : // Create "directory up" button dir_up_btn_ = new QPushButton(this); dir_up_btn_->setEnabled(false); - dir_up_btn_->setIcon(olive::icon::DirUp); dir_up_btn_->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); layout->addWidget(dir_up_btn_); connect(dir_up_btn_, SIGNAL(clicked(bool)), this, SIGNAL(DirectoryUpClicked())); @@ -49,14 +48,12 @@ ProjectExplorerNavigation::ProjectExplorerNavigation(QWidget *parent) : // Create size slider size_slider_ = new QSlider(this); size_slider_->setOrientation(Qt::Horizontal); - size_slider_->setMinimum(olive::kProjectIconSizeMinimum); - size_slider_->setMaximum(olive::kProjectIconSizeMaximum); - size_slider_->setValue(olive::kProjectIconSizeDefault); size_slider_->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); layout->addWidget(size_slider_); connect(size_slider_, SIGNAL(valueChanged(int)), this, SIGNAL(SizeChanged(int))); Retranslate(); + UpdateIcons(); } void ProjectExplorerNavigation::set_text(const QString &s) @@ -78,6 +75,8 @@ void ProjectExplorerNavigation::changeEvent(QEvent *e) { if (e->type() == QEvent::LanguageChange) { Retranslate(); + } else if (e->type() == QEvent::StyleChange) { + UpdateIcons(); } QWidget::changeEvent(e); } @@ -86,3 +85,11 @@ void ProjectExplorerNavigation::Retranslate() { dir_up_btn_->setToolTip(tr("Go to parent folder")); } + +void ProjectExplorerNavigation::UpdateIcons() +{ + dir_up_btn_->setIcon(olive::icon::DirUp); + size_slider_->setMinimum(olive::kProjectIconSizeMinimum); + size_slider_->setMaximum(olive::kProjectIconSizeMaximum); + size_slider_->setValue(olive::kProjectIconSizeDefault); +} diff --git a/app/widget/projectexplorer/projectexplorernavigation.h b/app/widget/projectexplorer/projectexplorernavigation.h index 83892ca38..f49712efd 100644 --- a/app/widget/projectexplorer/projectexplorernavigation.h +++ b/app/widget/projectexplorer/projectexplorernavigation.h @@ -99,6 +99,8 @@ protected: private: void Retranslate(); + void UpdateIcons(); + QPushButton* dir_up_btn_; QLabel* dir_lbl_; diff --git a/app/widget/projecttoolbar/projecttoolbar.cpp b/app/widget/projecttoolbar/projecttoolbar.cpp index 2d48d2c61..a313aa940 100644 --- a/app/widget/projecttoolbar/projecttoolbar.cpp +++ b/app/widget/projecttoolbar/projecttoolbar.cpp @@ -34,27 +34,22 @@ ProjectToolbar::ProjectToolbar(QWidget *parent) : layout->setMargin(0); new_button_ = new QPushButton(); - new_button_->setIcon(olive::icon::New); connect(new_button_, SIGNAL(clicked(bool)), this, SIGNAL(NewClicked())); layout->addWidget(new_button_); open_button_ = new QPushButton(); - open_button_->setIcon(olive::icon::Open); connect(open_button_, SIGNAL(clicked(bool)), this, SIGNAL(OpenClicked())); layout->addWidget(open_button_); save_button_ = new QPushButton(); - save_button_->setIcon(olive::icon::Save); connect(save_button_, SIGNAL(clicked(bool)), this, SIGNAL(SaveClicked())); layout->addWidget(save_button_); undo_button_ = new QPushButton(); - undo_button_->setIcon(olive::icon::Undo); connect(undo_button_, SIGNAL(clicked(bool)), this, SIGNAL(UndoClicked())); layout->addWidget(undo_button_); redo_button_ = new QPushButton(); - redo_button_->setIcon(olive::icon::Redo); connect(redo_button_, SIGNAL(clicked(bool)), this, SIGNAL(RedoClicked())); layout->addWidget(redo_button_); @@ -64,19 +59,16 @@ ProjectToolbar::ProjectToolbar(QWidget *parent) : layout->addWidget(search_field_); tree_button_ = new QPushButton(); - tree_button_->setIcon(olive::icon::TreeView); tree_button_->setCheckable(true); connect(tree_button_, SIGNAL(clicked(bool)), this, SLOT(ViewButtonClicked())); layout->addWidget(tree_button_); list_button_ = new QPushButton(); - list_button_->setIcon(olive::icon::ListView); list_button_->setCheckable(true); connect(list_button_, SIGNAL(clicked(bool)), this, SLOT(ViewButtonClicked())); layout->addWidget(list_button_); icon_button_ = new QPushButton(); - icon_button_->setIcon(olive::icon::IconView); icon_button_->setCheckable(true); connect(icon_button_, SIGNAL(clicked(bool)), this, SLOT(ViewButtonClicked())); layout->addWidget(icon_button_); @@ -89,6 +81,7 @@ ProjectToolbar::ProjectToolbar(QWidget *parent) : view_button_group->addButton(icon_button_); Retranslate(); + UpdateIcons(); } void ProjectToolbar::SetView(olive::ProjectViewType type) @@ -110,6 +103,8 @@ void ProjectToolbar::changeEvent(QEvent *e) { if (e->type() == QEvent::LanguageChange) { Retranslate(); + } else if (e->type() == QEvent::StyleChange) { + UpdateIcons(); } QWidget::changeEvent(e); } @@ -129,6 +124,18 @@ void ProjectToolbar::Retranslate() icon_button_->setToolTip(tr("Switch to Icon View")); } +void ProjectToolbar::UpdateIcons() +{ + new_button_->setIcon(olive::icon::New); + open_button_->setIcon(olive::icon::Open); + save_button_->setIcon(olive::icon::Save); + undo_button_->setIcon(olive::icon::Undo); + redo_button_->setIcon(olive::icon::Redo); + tree_button_->setIcon(olive::icon::TreeView); + list_button_->setIcon(olive::icon::ListView); + icon_button_->setIcon(olive::icon::IconView); +} + void ProjectToolbar::ViewButtonClicked() { // Determine which view button triggered this slot and emit a signal accordingly diff --git a/app/widget/projecttoolbar/projecttoolbar.h b/app/widget/projecttoolbar/projecttoolbar.h index 65c4c0e0d..1eef6f570 100644 --- a/app/widget/projecttoolbar/projecttoolbar.h +++ b/app/widget/projecttoolbar/projecttoolbar.h @@ -61,6 +61,7 @@ signals: private: void Retranslate(); + void UpdateIcons(); QPushButton* new_button_; QPushButton* open_button_; diff --git a/app/widget/timelineview/timelineview.cpp b/app/widget/timelineview/timelineview.cpp index bb1c1ec60..e66030e3b 100644 --- a/app/widget/timelineview/timelineview.cpp +++ b/app/widget/timelineview/timelineview.cpp @@ -51,6 +51,7 @@ TimelineView::TimelineView(QWidget *parent) : setAlignment(Qt::AlignLeft | Qt::AlignTop); setDragMode(RubberBandDrag); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + setBackgroundRole(QPalette::Window); connect(&scene_, SIGNAL(changed(const QList&)), this, SLOT(UpdateSceneRect())); diff --git a/app/widget/timelineview/tool/import.cpp b/app/widget/timelineview/tool/import.cpp index 5e6580657..470f65363 100644 --- a/app/widget/timelineview/tool/import.cpp +++ b/app/widget/timelineview/tool/import.cpp @@ -83,7 +83,7 @@ void TimelineView::ImportTool::DragEnter(QDragEnterEvent *event) if (stream->type() == Stream::kImage) { // Stream is essentially length-less - use config's default image length - footage_duration = kDefaultImageLength; + footage_duration = Config::Current()["DefaultStillLength"].value(); } else { // Use duration from file footage_duration = rational(stream->timebase().numerator() * stream->duration(), @@ -151,7 +151,7 @@ void TimelineView::ImportTool::DragMove(QDragMoveEvent *event) int64_t earliest_timestamp = olive::time_to_timestamp(earliest_ghost, parent()->timebase_); QString tooltip_text = olive::timestamp_to_timecode(earliest_timestamp, parent()->timebase_, - kTimecodeDisplay); + olive::CurrentTimecodeDisplay()); QToolTip::showText(QCursor::pos(), tooltip_text, parent()); diff --git a/app/widget/timelineview/tool/pointer.cpp b/app/widget/timelineview/tool/pointer.cpp index 414a5c024..eaa013fae 100644 --- a/app/widget/timelineview/tool/pointer.cpp +++ b/app/widget/timelineview/tool/pointer.cpp @@ -279,7 +279,7 @@ void TimelineView::PointerTool::ProcessDrag(const QPoint &mouse_pos) int64_t earliest_timestamp = olive::time_to_timestamp(time_movement, parent()->timebase_); QString tooltip_text = olive::timestamp_to_timecode(earliest_timestamp, parent()->timebase_, - kTimecodeDisplay, + olive::CurrentTimecodeDisplay(), true); QToolTip::showText(QCursor::pos(), tooltip_text, diff --git a/app/widget/timelineview/tool/slip.cpp b/app/widget/timelineview/tool/slip.cpp index 52ff93dfa..d70aa1916 100644 --- a/app/widget/timelineview/tool/slip.cpp +++ b/app/widget/timelineview/tool/slip.cpp @@ -58,7 +58,7 @@ void TimelineView::SlipTool::ProcessDrag(const QPoint &mouse_pos) int64_t earliest_timestamp = olive::time_to_timestamp(time_movement, parent()->timebase_); QString tooltip_text = olive::timestamp_to_timecode(earliest_timestamp, parent()->timebase_, - kTimecodeDisplay, + olive::CurrentTimecodeDisplay(), true); QToolTip::showText(QCursor::pos(), tooltip_text, diff --git a/app/widget/timeruler/timeruler.cpp b/app/widget/timeruler/timeruler.cpp index 9cde28392..d73cadabc 100644 --- a/app/widget/timeruler/timeruler.cpp +++ b/app/widget/timeruler/timeruler.cpp @@ -156,7 +156,7 @@ void TimeRuler::paintEvent(QPaintEvent *) if (text_visible_) { QFontMetrics fm = p.fontMetrics(); double width_of_second = scale_; - int average_text_width = QFontMetricsWidth(&fm, olive::timestamp_to_timecode(0, timebase_, kTimecodeDisplay)); + int average_text_width = QFontMetricsWidth(&fm, olive::timestamp_to_timecode(0, timebase_, olive::CurrentTimecodeDisplay())); half_average_text_width = average_text_width/2; while (width_of_second * text_skip < average_text_width) { text_skip++; @@ -202,7 +202,7 @@ void TimeRuler::paintEvent(QPaintEvent *) // Try to draw text here if (text_visible_ && sec%text_skip == 0) { - QString timecode_string = olive::timestamp_to_timecode(sec, timebase_, kTimecodeDisplay); + QString timecode_string = olive::timestamp_to_timecode(sec, timebase_, olive::CurrentTimecodeDisplay()); int text_x = i; diff --git a/app/widget/toolbar/toolbar.cpp b/app/widget/toolbar/toolbar.cpp index 6b46b7840..9aec0b59f 100644 --- a/app/widget/toolbar/toolbar.cpp +++ b/app/widget/toolbar/toolbar.cpp @@ -34,24 +34,25 @@ Toolbar::Toolbar(QWidget *parent) : layout_->setMargin(0); // Create standard tool buttons - btn_pointer_tool_ = CreateToolButton(olive::icon::ToolPointer, olive::tool::kPointer); - btn_edit_tool_ = CreateToolButton(olive::icon::ToolEdit, olive::tool::kEdit); - btn_ripple_tool_ = CreateToolButton(olive::icon::ToolRipple, olive::tool::kRipple); - btn_rolling_tool_ = CreateToolButton(olive::icon::ToolRolling, olive::tool::kRolling); - btn_razor_tool_ = CreateToolButton(olive::icon::ToolRazor, olive::tool::kRazor); - btn_slip_tool_ = CreateToolButton(olive::icon::ToolSlip, olive::tool::kSlip); - btn_slide_tool_ = CreateToolButton(olive::icon::ToolSlide, olive::tool::kSlide); - btn_hand_tool_ = CreateToolButton(olive::icon::ToolHand, olive::tool::kHand); - btn_zoom_tool_ = CreateToolButton(olive::icon::ZoomIn, olive::tool::kZoom); - btn_record_ = CreateToolButton(olive::icon::Record, olive::tool::kRecord); - btn_transition_tool_ = CreateToolButton(olive::icon::ToolTransition, olive::tool::kTransition); - btn_add_ = CreateToolButton(olive::icon::Add, olive::tool::kAdd); + btn_pointer_tool_ = CreateToolButton(olive::tool::kPointer); + btn_edit_tool_ = CreateToolButton(olive::tool::kEdit); + btn_ripple_tool_ = CreateToolButton(olive::tool::kRipple); + btn_rolling_tool_ = CreateToolButton(olive::tool::kRolling); + btn_razor_tool_ = CreateToolButton(olive::tool::kRazor); + btn_slip_tool_ = CreateToolButton(olive::tool::kSlip); + btn_slide_tool_ = CreateToolButton(olive::tool::kSlide); + btn_hand_tool_ = CreateToolButton(olive::tool::kHand); + btn_zoom_tool_ = CreateToolButton(olive::tool::kZoom); + btn_record_ = CreateToolButton(olive::tool::kRecord); + btn_transition_tool_ = CreateToolButton(olive::tool::kTransition); + btn_add_ = CreateToolButton(olive::tool::kAdd); // Create snapping button, which is not actually a tool, it's a toggle option - btn_snapping_toggle_ = CreateNonToolButton(olive::icon::Snapping); + btn_snapping_toggle_ = CreateNonToolButton(); connect(btn_snapping_toggle_, SIGNAL(clicked(bool)), this, SLOT(SnappingButtonClicked(bool))); Retranslate(); + UpdateIcons(); } void Toolbar::SetTool(const olive::tool::Tool& tool) @@ -74,6 +75,8 @@ void Toolbar::changeEvent(QEvent *e) { if (e->type() == QEvent::LanguageChange) { Retranslate(); + } else if (e->type() == QEvent::StyleChange) { + UpdateIcons(); } QWidget::changeEvent(e); } @@ -95,10 +98,27 @@ void Toolbar::Retranslate() btn_snapping_toggle_->setToolTip(tr("Toggle Snapping")); } -ToolbarButton* Toolbar::CreateToolButton(const QIcon &icon, const olive::tool::Tool& tool) +void Toolbar::UpdateIcons() +{ + btn_pointer_tool_->setIcon(olive::icon::ToolPointer); + btn_edit_tool_->setIcon(olive::icon::ToolEdit); + btn_ripple_tool_->setIcon(olive::icon::ToolRipple); + btn_rolling_tool_->setIcon(olive::icon::ToolRolling); + btn_razor_tool_->setIcon(olive::icon::ToolRazor); + btn_slip_tool_->setIcon(olive::icon::ToolSlip); + btn_slide_tool_->setIcon(olive::icon::ToolSlide); + btn_hand_tool_->setIcon(olive::icon::ToolHand); + btn_zoom_tool_->setIcon(olive::icon::ZoomIn); + btn_record_->setIcon(olive::icon::Record); + btn_transition_tool_->setIcon(olive::icon::ToolTransition); + btn_add_->setIcon(olive::icon::Add); + btn_snapping_toggle_->setIcon(olive::icon::Snapping); +} + +ToolbarButton* Toolbar::CreateToolButton(const olive::tool::Tool& tool) { // Create a ToolbarButton object - ToolbarButton* b = new ToolbarButton(this, icon, tool); + ToolbarButton* b = new ToolbarButton(this, tool); // Add it to the layout layout_->addWidget(b); @@ -112,10 +132,10 @@ ToolbarButton* Toolbar::CreateToolButton(const QIcon &icon, const olive::tool::T return b; } -ToolbarButton *Toolbar::CreateNonToolButton(const QIcon &icon) +ToolbarButton *Toolbar::CreateNonToolButton() { // Create a ToolbarButton object - ToolbarButton* b = new ToolbarButton(this, icon, olive::tool::kNone); + ToolbarButton* b = new ToolbarButton(this, olive::tool::kNone); // Add it to the layout layout_->addWidget(b); diff --git a/app/widget/toolbar/toolbar.h b/app/widget/toolbar/toolbar.h index 5ef9d2fdd..40e44f5e4 100644 --- a/app/widget/toolbar/toolbar.h +++ b/app/widget/toolbar/toolbar.h @@ -112,6 +112,11 @@ private: */ void Retranslate(); + /** + * @brief Update icons after a style change + */ + void UpdateIcons(); + /** * @brief Internal convenience function for creating tool buttons quickly * @@ -125,7 +130,7 @@ private: * * The created ToolbarButton. The button parent is automatically set to `this`. */ - ToolbarButton* CreateToolButton(const QIcon &icon, const olive::tool::Tool& tool); + ToolbarButton* CreateToolButton(const olive::tool::Tool& tool); /** * @brief Internal convenience function for creating buttons quickly @@ -138,7 +143,7 @@ private: * * The created ToolbarButton. The button parent is automatically set to `this`. */ - ToolbarButton* CreateNonToolButton(const QIcon &icon); + ToolbarButton* CreateNonToolButton(); /** * @brief Internal layout used for buttons diff --git a/app/widget/toolbar/toolbarbutton.cpp b/app/widget/toolbar/toolbarbutton.cpp index 0b4b140c0..547799f67 100644 --- a/app/widget/toolbar/toolbarbutton.cpp +++ b/app/widget/toolbar/toolbarbutton.cpp @@ -20,12 +20,11 @@ #include "toolbarbutton.h" -ToolbarButton::ToolbarButton(QWidget *parent, const QIcon &icon, const olive::tool::Tool &tool) : +ToolbarButton::ToolbarButton(QWidget *parent, const olive::tool::Tool &tool) : QPushButton(parent), tool_(tool) { setCheckable(true); - setIcon(icon); } const olive::tool::Tool &ToolbarButton::tool() diff --git a/app/widget/toolbar/toolbarbutton.h b/app/widget/toolbar/toolbarbutton.h index 4e59d06b9..1595c434b 100644 --- a/app/widget/toolbar/toolbarbutton.h +++ b/app/widget/toolbar/toolbarbutton.h @@ -38,15 +38,11 @@ public: * * QWidget parent. Almost always an instance of Toolbar. * - * @param icon - * - * Icon to set this QWidget to. - * * @param tool * * Tool object. Must be a member of enum olive::tool::Tool, including kNone if this button does not represent a tool. */ - ToolbarButton(QWidget* parent, const QIcon& icon, const olive::tool::Tool& tool); + ToolbarButton(QWidget* parent, const olive::tool::Tool& tool); /** * @brief Retrieve tool ID that this button represents diff --git a/app/window/mainwindow/mainmenu.cpp b/app/window/mainwindow/mainmenu.cpp index b8b36bf7f..e16bbb616 100644 --- a/app/window/mainwindow/mainmenu.cpp +++ b/app/window/mainwindow/mainmenu.cpp @@ -49,7 +49,7 @@ MainMenu::MainMenu(QMainWindow *parent) : file_menu_->addSeparator(); file_export_item_ = file_menu_->AddItem("export", nullptr, nullptr, "Ctrl+M"); file_menu_->addSeparator(); - file_exit_item_ = file_menu_->AddItem("exit", nullptr, nullptr); + file_exit_item_ = file_menu_->AddItem("exit", parent, SLOT(close()), "Ctrl+Q"); // // EDIT MENU @@ -289,7 +289,7 @@ MainMenu::MainMenu(QMainWindow *parent) : tools_menu_->addSeparator(); - tools_preferences_item_ = tools_menu_->AddItem("prefs", nullptr, nullptr, "Ctrl+,"); + tools_preferences_item_ = tools_menu_->AddItem("prefs", &olive::core, SLOT(DialogPreferencesShow()), "Ctrl+,"); // // HELP MENU