reimplemented goto prev/next cut, about dialog, and action search dialog

This commit is contained in:
itsmattkc
2019-09-25 02:33:33 +10:00
parent fe5f493368
commit c19718a4a5
28 changed files with 2573 additions and 24 deletions
+7
View File
@@ -28,6 +28,7 @@
#include <QMessageBox>
#include <QHBoxLayout>
#include "dialog/about/about.h"
#include "dialog/sequence/sequence.h"
#include "panel/panelmanager.h"
#include "panel/project/project.h"
@@ -160,6 +161,12 @@ void Core::SetSnapping(const bool &b)
emit SnappingChanged(snapping_);
}
void Core::DialogAboutShow()
{
AboutDialog a(main_window_);
a.exec();
}
void Core::DialogImportShow()
{
// Open dialog for user to select files
+5
View File
@@ -114,6 +114,11 @@ public slots:
*/
void SetSnapping(const bool& b);
/**
* @brief Show an About dialog
*/
void DialogAboutShow();
/**
* @brief Open the import footage dialog and import the files selected (runs ImportFiles())
*/
+2
View File
@@ -14,6 +14,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
add_subdirectory(about)
add_subdirectory(actionsearch)
add_subdirectory(sequence)
set(OLIVE_SOURCES
+22
View File
@@ -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 <http://www.gnu.org/licenses/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
dialog/about/about.h
dialog/about/about.cpp
PARENT_SCOPE
)
+65
View File
@@ -0,0 +1,65 @@
/***
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 <http://www.gnu.org/licenses/>.
***/
#include "about.h"
#include <QApplication>
#include <QLabel>
#include <QDialogButtonBox>
#include <QVBoxLayout>
AboutDialog::AboutDialog(QWidget *parent) :
QDialog(parent)
{
setWindowTitle(tr("About %1").arg(QApplication::applicationName()));
QVBoxLayout* layout = new QVBoxLayout(this);
//layout->setSpacing(20);
// Construct About text
QLabel* label =
new QLabel(QString("<html><head/><body>"
"<p><img src=\":/icons/olive-splash.png\"/></p>"
"<p><a href=\"https://www.olivevideoeditor.org/\">"
"<span style=\" text-decoration: underline; color:#007af4;\">"
"https://www.olivevideoeditor.org/"
"</span></a></p>"
"<p><b>%1</b></p>" // AppName (version identifier)
"<p>%2</p>" // First statement
"<p>%3</p>" // Second statement
"</body></html>").arg(QApplication::applicationName(),
tr("Olive is a non-linear video editor. This software is free and "
"protected by the GNU GPL."),
tr("Olive Team is obliged to inform users that Olive source code is "
"available for download from its website.")),this);
// Set text formatting
label->setAlignment(Qt::AlignCenter);
label->setTextInteractionFlags(Qt::TextSelectableByMouse);
label->setCursor(Qt::IBeamCursor);
label->setWordWrap(true);
layout->addWidget(label);
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok, this);
buttons->setCenterButtons(true);
layout->addWidget(buttons);
connect(buttons, SIGNAL(accepted()), this, SLOT(accept()));
}
+48
View File
@@ -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 <http://www.gnu.org/licenses/>.
***/
#ifndef ABOUTDIALOG_H
#define ABOUTDIALOG_H
#include <QDialog>
/**
* @brief The AboutDialog class
*
* The About dialog (accessible through Help > About). Contains license and version information. This can be run from
* anywhere
*/
class AboutDialog : public QDialog
{
Q_OBJECT
public:
/**
* @brief AboutDialog Constructor
*
* Creates About dialog.
*
* @param parent
*
* QWidget parent object. Usually this will be MainWindow.
*/
explicit AboutDialog(QWidget *parent = nullptr);
};
#endif // ABOUTDIALOG_H
+22
View File
@@ -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 <http://www.gnu.org/licenses/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
dialog/actionsearch/actionsearch.h
dialog/actionsearch/actionsearch.cpp
PARENT_SCOPE
)
+253
View File
@@ -0,0 +1,253 @@
/***
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 <http://www.gnu.org/licenses/>.
***/
#include "actionsearch.h"
#include <QVBoxLayout>
#include <QKeyEvent>
#include <QMenuBar>
#include <QLabel>
ActionSearch::ActionSearch(QWidget *parent) :
QDialog(parent),
menu_bar_(nullptr)
{
// ActionSearch requires a parent widget
Q_ASSERT(parent != nullptr);
// Set styling (object name is required for CSS specific to this object)
setObjectName("ASDiag");
setStyleSheet("#ASDiag{border: 2px solid #808080;}");
// Size proportionally to the parent (usually MainWindow).
resize(parent->width()/3, parent->height()/3);
// Show dialog as a "popup", which will make the dialog close if the user clicks out of it.
setWindowFlags(Qt::Popup);
QVBoxLayout* layout = new QVBoxLayout(this);
// Construct the main entry text field.
ActionSearchEntry* entry_field = new ActionSearchEntry(this);
// Set the main entry field font size to 1.2x its standard font size.
QFont entry_field_font = entry_field->font();
entry_field_font.setPointSize(qRound(entry_field_font.pointSize()*1.2));
entry_field->setFont(entry_field_font);
// Set placeholder text for the main entry field
entry_field->setPlaceholderText(tr("Search for action..."));
// Connect signals/slots
connect(entry_field, SIGNAL(textChanged(const QString&)), this, SLOT(search_update(const QString &)));
connect(entry_field, SIGNAL(returnPressed()), this, SLOT(perform_action()));
// moveSelectionUp() and moveSelectionDown() are emitted when the user pressed up or down on the text field.
// We override it here to select the upper or lower item in the list.
connect(entry_field, SIGNAL(moveSelectionUp()), this, SLOT(move_selection_up()));
connect(entry_field, SIGNAL(moveSelectionDown()), this, SLOT(move_selection_down()));
layout->addWidget(entry_field);
// Construct list of actions
list_widget = new ActionSearchList(this);
// Set list's font to 1.2x its standard font size
QFont list_widget_font = list_widget->font();
list_widget_font.setPointSize(qRound(list_widget_font.pointSize()*1.2));
list_widget->setFont(list_widget_font);
layout->addWidget(list_widget);
connect(list_widget, SIGNAL(dbl_click()), this, SLOT(perform_action()));
// Instantly focus on the entry field to allow for fully keyboard operation (if this popup was initiated by keyboard
// shortcut for example).
entry_field->setFocus();
}
void ActionSearch::SetMenuBar(QMenuBar *menu_bar)
{
menu_bar_ = menu_bar;
}
void ActionSearch::search_update(const QString &s, const QString &p, QMenu *parent)
{
// Do nothing if there's no menu bar to work with
if (menu_bar_ == nullptr) {
return;
}
// This function is recursive, using the `parent` parameter to loop through a menu's items. It functions in two
// modes - the parent being NULL, meaning it'll get MainWindow's menubar and loop over its menus, and the parent
// referring to a menu at which point it'll loop over its actions (and call itself recursively if it finds any
// submenus).
if (parent == nullptr) {
// If parent is NULL, we'll pull from the MainWindow's menubar and call this recursively on all of its submenus
// (and their submenus).
// We'll clear all the current items in the list since if we're here, we're just starting.
list_widget->clear();
QList<QAction*> menus = menu_bar_->actions();
// Loop through all menus from the menubar and run this function on each one.
for (int i=0;i<menus.size();i++) {
QMenu* menu = menus.at(i)->menu();
search_update(s, p, menu);
}
// Once we're here, all the recursion/item retrieval is complete. We auto-select the first item for better
// keyboard-exclusive functionality.
if (list_widget->count() > 0) {
list_widget->item(0)->setSelected(true);
}
} else {
// Parent was not NULL, so we loop over the actions in the menu we were given in `parent`.
// The list shows a '>' delimited hierarchy of the menus in which this action came from. We construct it here by
// adding the current menu's text to the existing hierarchy (passed in `p`).
QString menu_text;
if (!p.isEmpty()) menu_text += p + " > ";
menu_text += parent->title().replace("&", ""); // Strip out any &s used in menu action names
// Loop over the menu's actions
QList<QAction*> actions = parent->actions();
for (int i=0;i<actions.size();i++) {
QAction* a = actions.at(i);
// Ignore separator actions
if (!a->isSeparator()) {
if (a->menu() != nullptr) {
// If the action is a menu, run this function recursively on it
search_update(s, menu_text, a->menu());
} else {
// This is a valid non-separator non-menu action, so check it against the currently entered string.
// Strip out all &s from the action's name
QString comp = a->text().replace("&", "");
// See if the action's name contains any of the currently entered string
if (comp.contains(s, Qt::CaseInsensitive)) {
// If so, we add it to the list widget.
QListWidgetItem* item = new QListWidgetItem(QString("%1\n(%2)").arg(comp, menu_text), list_widget);
// Add a pointer to the original QAction in the item's data
item->setData(Qt::UserRole+1, reinterpret_cast<quintptr>(a));
list_widget->addItem(item);
}
}
}
}
}
}
void ActionSearch::perform_action() {
// Loop over all the items in the list and if we find one that's selected, we trigger it.
QList<QListWidgetItem*> selected_items = list_widget->selectedItems();
if (list_widget->count() > 0 && selected_items.size() > 0) {
QListWidgetItem* item = selected_items.at(0);
// Get QAction pointer from item's data
QAction* a = reinterpret_cast<QAction*>(item->data(Qt::UserRole+1).value<quintptr>());
a->trigger();
}
// Close this popup
accept();
}
void ActionSearch::move_selection_up() {
// Here we loop over all the items to find the currently selected one, and then select the one above it. We start
// iterating at 1 (instead of 0) to efficiently ignore the first item (since the selection can't go below the very
// bottom item).
int lim = list_widget->count();
for (int i=1;i<lim;i++) {
if (list_widget->item(i)->isSelected()) {
list_widget->item(i-1)->setSelected(true);
list_widget->scrollToItem(list_widget->item(i-1));
break;
}
}
}
void ActionSearch::move_selection_down() {
// Here we loop over all the items to find the currently selected one, and then select the one below it. We limit it
// one entry before count() to efficiently ignore the item at the end (since the selection can't go below the very
// bottom item).
int lim = list_widget->count()-1;
for (int i=0;i<lim;i++) {
if (list_widget->item(i)->isSelected()) {
list_widget->item(i+1)->setSelected(true);
list_widget->scrollToItem(list_widget->item(i+1));
break;
}
}
}
ActionSearchEntry::ActionSearchEntry(QWidget *parent) : QLineEdit(parent) {}
void ActionSearchEntry::keyPressEvent(QKeyEvent * event) {
// Listen for up/down, otherwise pass the key event to the base class.
switch (event->key()) {
case Qt::Key_Up:
emit moveSelectionUp();
break;
case Qt::Key_Down:
emit moveSelectionDown();
break;
default:
QLineEdit::keyPressEvent(event);
}
}
ActionSearchList::ActionSearchList(QWidget *parent) : QListWidget(parent) {}
void ActionSearchList::mouseDoubleClickEvent(QMouseEvent *) {
// Indiscriminately emit a signal on any double click
emit dbl_click();
}
+181
View File
@@ -0,0 +1,181 @@
/***
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 <http://www.gnu.org/licenses/>.
***/
#ifndef ACTIONSEARCH_H
#define ACTIONSEARCH_H
#include <QDialog>
#include <QLineEdit>
#include <QListWidget>
#include <QMenu>
#include <QMenuBar>
class ActionSearchList;
/**
* @brief The ActionSearch class
*
* A popup window (accessible through Help > Action Search) that allows users to search for a menu command by typing
* rather than browsing through the menu bar. This can be created from anywhere provided olive::MainWindow is valid.
*/
class ActionSearch : public QDialog
{
Q_OBJECT
public:
/**
* @brief ActionSearch Constructor
*
* Create ActionSearch popup.
*
* @param parent
*
* QWidget parent. Usually MainWindow.
*/
ActionSearch(QWidget* parent);
/**
* @brief Set the menu bar to use in this action search
*/
void SetMenuBar(QMenuBar* menu_bar);
private slots:
/**
* @brief Update the list of actions according to a search query
*
* This function adds/removes actions in the action list according to a given search query entered by the user.
*
* To loop over the menubar and all of its menus and submenus, this function will call itself recursively. As such
* some of its parameters do not need to be set externally, as these will be set by the function itself as it calls
* itself.
*
* @param s
*
* The search text. This is the only parameter that should be set externally.
*
* @param p
*
* The current parent hierarchy. In most cases, this should be left as nullptr when called externally.
* search_update() will fill this automatically as it needs while calling itself recursively.
*
* @param parent
*
* The current menu to loop over. In most cases, this should be left as nullptr when called externally.
* search_update() will fill this automatically as it needs while calling itself recursively.
*/
void search_update(const QString& s, const QString &p = nullptr, QMenu *parent = nullptr);
/**
* @brief Perform the currently selected action
*
* Usually triggered by pressing Enter on the ActionSearchEntry field, this will trigger whatever action is currently
* highlighted and then close this popup. If no entries are highlighted (i.e. the list is empty), no action is
* triggered and the popup closes anyway.
*/
void perform_action();
/**
* @brief Move selection up
*
* A slot for pressing up on the ActionSearchEntry field. Moves the selection in the list up once. If the
* selection is already at the top of the list, this is a no-op.
*/
void move_selection_up();
/**
* @brief Move selection down
*
* A slot for pressing down on the ActionSearchEntry field. Moves the selection in the list down once. If the
* selection is already at the bottom of the list, this is a no-op.
*/
void move_selection_down();
private:
/**
* @brief Main widget that shows the list of commands
*/
ActionSearchList* list_widget;
/**
* @brief Attached menu bar object
*/
QMenuBar* menu_bar_;
};
/**
* @brief The ActionSearchList class
*
* Simple wrapper around QListWidget that emits a signal when an item is double clicked that ActionSearch connects
* to a slot that triggers the currently selected action.
*/
class ActionSearchList : public QListWidget {
Q_OBJECT
public:
/**
* @brief ActionSearchList Constructor
* @param parent
*
* Usually ActionSearch.
*/
ActionSearchList(QWidget* parent);
protected:
/**
* @brief Override of QListWidget's double click event that emits a signal.
*/
void mouseDoubleClickEvent(QMouseEvent *);
signals:
/**
* @brief Signal emitted when a QListWidget item is double clicked.
*/
void dbl_click();
};
/**
* @brief The ActionSearchEntry class
*
* Simple wrapper around QLineEdit that emits signals when the up or down arrow keys are pressed so that ActionSearch
* can connect them to moving the current selection up or down.
*/
class ActionSearchEntry : public QLineEdit {
Q_OBJECT
public:
/**
* @brief ActionSearchEntry
* @param parent
*
* Usually ActionSearch.
*/
ActionSearchEntry(QWidget* parent);
protected:
/**
* @brief Override of QLineEdit's key press event that listens for up/down key presses.
* @param event
*/
void keyPressEvent(QKeyEvent * event);
signals:
/**
* @brief Emitted when the user presses the up arrow key.
*/
void moveSelectionUp();
/**
* @brief Emitted when the user presses the down arrow key.
*/
void moveSelectionDown();
};
#endif // ACTIONSEARCH_H
File diff suppressed because it is too large Load Diff
+432
View File
@@ -0,0 +1,432 @@
/***
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 <http://www.gnu.org/licenses/>.
***/
#ifndef PREFERENCESDIALOG_H
#define PREFERENCESDIALOG_H
#include <QDialog>
#include <QKeySequenceEdit>
#include <QMenuBar>
#include <QLineEdit>
#include <QComboBox>
#include <QRadioButton>
#include <QTreeWidget>
#include <QTreeWidgetItem>
#include <QMenu>
#include <QCheckBox>
#include <QDoubleSpinBox>
#include <QSpinBox>
#include <OpenColorIO/OpenColorIO.h>
namespace OCIO = OCIO_NAMESPACE::v1;
#include "timeline/sequence.h"
class KeySequenceEditor;
/**
* @brief The PreferencesDialog class
*
* A dialog for the global application settings. Mostly an interface for Config. Can be loaded from any part of the
* application.
*/
class PreferencesDialog : public QDialog
{
Q_OBJECT
public:
/**
* @brief PreferencesDialog Constructor
*
* @param parent
*
* QWidget parent. Usually MainWindow.
*/
explicit PreferencesDialog(QWidget *parent = nullptr);
private slots:
/**
* @brief Override of accept to save preferences to Config.
*/
virtual void accept() override;
/**
* @brief Reset all selected shortcuts in keyboard_tree to their defaults
*/
void reset_default_shortcut();
/**
* @brief Reset all shortcuts indiscriminately to their defaults
*
* This is safe to call directly as it'll ask the user if they wish to do so before it resets.
*/
void reset_all_shortcuts();
/**
* @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:
/**
* @brief Create and arrange all UI widgets
*/
void setup_ui();
/**
* @brief Populate keyboard shortcut panel with keyboard shortcuts from the menu bar
*
* @param menu
*
* A reference to the main application's menu bar. Usually MainWindow::menuBar().
*/
void setup_kbd_shortcuts(QMenuBar* menu);
/**
* @brief Internal function called by setup_kbd_shortcuts() to traverse down the menu bar's hierarchy and populate the
* shortcut panel.
*
* This function will call itself recursively as it finds submenus belong to the menu provided. It will also create
* QTreeWidgetItems as children of the parent item provided, either using them as parents themselves for submenus
* or attaching a KeySequenceEditor to them for shortcut editing.
*
* @param menu
*
* The current menu to traverse down.
*
* @param parent
*
* The parent item to add QTreeWidgetItems to.
*/
void setup_kbd_shortcut_worker(QMenu* menu, QTreeWidgetItem* parent);
enum PreviewDeleteTypes {
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;
/**
* @brief Stored default Sequence object
*
* 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<QAction*> 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<QTreeWidgetItem*> 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<KeySequenceEditor*> 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);
/**
* @brief Add an automated QCheckBox+boolean value pair
*
* Many preferences are simple true/false (or on/off) options. Rather than adding a QCheckBox for each one and
* manually setting its checked value to the configuration setting (and vice versa when saving), this convenience
* function will add it to an automated set of checkboxes, automatically setting the checked state to the current
* setting, and then saving the new checked state back to the setting when the user accepts the changes (clicks OK).
*
* @param ui
*
* A valid QCheckBox item. This function does not take ownership of the QWidget or place it in a layout anywhere.
*
* @param value
*
* A pointer to the Boolean value this QCheckBox should be shared with. The QCheckBox widget's checked state will be
* set to the value of this pointer.
*
* @param restart_required
*
* Defaults to FALSE, set this to TRUE if changing this setting should prompt the user for a restart of Olive before
* the setting change takes effect.
*/
void AddBoolPair(QCheckBox* ui, bool* value, bool restart_required = false);
/**
* @brief Internal array managed by AddBoolPair(). Do not access this directly.
*/
QVector<QCheckBox*> bool_ui;
/**
* @brief Internal array managed by AddBoolPair(). Do not access this directly.
*/
QVector<bool*> bool_value;
/**
* @brief Internal array managed by AddBoolPair(). Do not access this directly.
*/
QVector<bool> 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
+5
View File
@@ -36,6 +36,11 @@ void PanelManager::DeleteAllPanels()
focus_history_.clear();
}
const QList<PanelWidget *> &PanelManager::panels()
{
return focus_history_;
}
PanelWidget *PanelManager::CurrentlyFocused() const
{
if (focus_history_.isEmpty()) {
+12
View File
@@ -47,8 +47,20 @@ class PanelManager : public QObject
public:
PanelManager(QObject* parent);
/**
* @brief Destroy all panels
*
* Should only be used on application exit to cleanly free all panels.
*/
void DeleteAllPanels();
/**
* @brief Get a list of all existing panels
*
* Panels are ordered from most recently focused to least recently focused.
*/
const QList<PanelWidget*>& panels();
/**
* @brief Return the currently focused widget, or nullptr if nothing is focused
*/
+10
View File
@@ -119,6 +119,16 @@ void TimelinePanel::EditToOut()
view_->EditToOut();
}
void TimelinePanel::GoToPrevCut()
{
view_->GoToPrevCut();
}
void TimelinePanel::GoToNextCut()
{
view_->GoToNextCut();
}
void TimelinePanel::changeEvent(QEvent *e)
{
if (e->type() == QEvent::LanguageChange) {
+4
View File
@@ -55,6 +55,10 @@ public:
virtual void EditToOut() override;
virtual void GoToPrevCut() override;
virtual void GoToNextCut() override;
public slots:
void SetTimebase(const rational& timebase);
+15
View File
@@ -69,6 +69,21 @@ void ViewerPanel::GoToEnd()
viewer_->GoToEnd();
}
void ViewerPanel::ShuttleLeft()
{
viewer_->ShuttleLeft();
}
void ViewerPanel::ShuttleStop()
{
viewer_->ShuttleStop();
}
void ViewerPanel::ShuttleRight()
{
viewer_->ShuttleRight();
}
void ViewerPanel::SetTimebase(const rational &timebase)
{
viewer_->SetTimebase(timebase);
+6
View File
@@ -48,6 +48,12 @@ public:
virtual void GoToEnd() override;
virtual void ShuttleLeft() override;
virtual void ShuttleStop() override;
virtual void ShuttleRight() override;
void SetTimebase(const rational& timebase);
void ConnectViewerNode(ViewerOutput* node);
+20
View File
@@ -1,3 +1,23 @@
/***
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 <http://www.gnu.org/licenses/>.
***/
#include "undostack.h"
OliveUndoStack olive::undo_stack;
+20
View File
@@ -1,3 +1,23 @@
/***
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 <http://www.gnu.org/licenses/>.
***/
#ifndef UNDOSTACK_H
#define UNDOSTACK_H
+10
View File
@@ -96,6 +96,16 @@ public:
virtual void EditToOut(){}
virtual void ShuttleLeft(){}
virtual void ShuttleStop(){}
virtual void ShuttleRight(){}
virtual void GoToPrevCut(){}
virtual void GoToNextCut(){}
protected:
/**
* @brief Set panel's title
+70 -2
View File
@@ -238,6 +238,69 @@ void TimelineView::EditToOut()
RippleEditTo(olive::timeline::kTrimOut, true);
}
void TimelineView::GoToPrevCut()
{
if (timeline_node_ == nullptr) {
return;
}
if (playhead_ == 0) {
return;
}
int64_t closest_cut = 0;
foreach (TrackOutput* track, timeline_node_->Tracks()) {
int64_t this_track_closest_cut = 0;
foreach (Block* block, track->Blocks()) {
int64_t block_out_ts = olive::time_to_timestamp(block->out(), timebase_);
if (block_out_ts < playhead_) {
this_track_closest_cut = block_out_ts;
} else {
break;
}
}
closest_cut = qMax(closest_cut, this_track_closest_cut);
}
UserSetTime(closest_cut);
}
void TimelineView::GoToNextCut()
{
if (timeline_node_ == nullptr) {
return;
}
int64_t closest_cut = INT64_MAX;
foreach (TrackOutput* track, timeline_node_->Tracks()) {
int64_t this_track_closest_cut = olive::time_to_timestamp(track->in(), timebase_);
if (this_track_closest_cut <= playhead_) {
this_track_closest_cut = INT64_MAX;
}
foreach (Block* block, track->Blocks()) {
int64_t block_in_ts = olive::time_to_timestamp(block->in(), timebase_);
if (block_in_ts > playhead_) {
this_track_closest_cut = block_in_ts;
break;
}
}
closest_cut = qMin(closest_cut, this_track_closest_cut);
}
if (closest_cut < INT64_MAX) {
UserSetTime(closest_cut);
}
}
void TimelineView::SetTime(const int64_t time)
{
playhead_ = time;
@@ -456,11 +519,16 @@ void TimelineView::RippleEditTo(olive::timeline::MovementMode mode, bool insert_
if (mode == olive::timeline::kTrimIn && !insert_gaps) {
int64_t new_time = olive::time_to_timestamp(closest_point_to_playhead, timebase_);
SetTime(new_time);
emit TimeChanged(new_time);
UserSetTime(new_time);
}
}
void TimelineView::UserSetTime(const int64_t &time)
{
SetTime(time);
emit TimeChanged(time);
}
void TimelineView::BlockChanged()
{
TimelineViewRect* rect = block_items_[static_cast<Block*>(sender())];
+6
View File
@@ -64,6 +64,10 @@ public:
void EditToOut();
void GoToPrevCut();
void GoToNextCut();
public slots:
void SetTimebase(const rational& timebase);
@@ -358,6 +362,8 @@ private:
void RippleEditTo(olive::timeline::MovementMode mode, bool insert_gaps);
void UserSetTime(const int64_t& time);
QGraphicsScene scene_;
double scale_;
+66 -13
View File
@@ -31,7 +31,8 @@
ViewerWidget::ViewerWidget(QWidget *parent) :
QWidget(parent),
viewer_node_(nullptr)
viewer_node_(nullptr),
playback_speed_(0)
{
// Set up main layout
QVBoxLayout* layout = new QVBoxLayout(this);
@@ -181,6 +182,24 @@ void ViewerWidget::UpdateTextureFromNode(const rational& time)
}
}
void ViewerWidget::PlayInternal(int speed)
{
Q_ASSERT(speed != 0);
if (time_base_.isNull()) {
qWarning() << "ViewerWidget can't play with an invalid timebase";
return;
}
start_msec_ = QDateTime::currentMSecsSinceEpoch();
start_timestamp_ = ruler_->GetTime();
playback_speed_ = speed;
playback_timer_.start();
controls_->ShowPauseButton();
}
void ViewerWidget::RulerTimeChange(int64_t i)
{
Pause();
@@ -190,17 +209,7 @@ void ViewerWidget::RulerTimeChange(int64_t i)
void ViewerWidget::Play()
{
if (time_base_.isNull()) {
qWarning() << "ViewerWidget can't play with an invalid timebase";
return;
}
start_msec_ = QDateTime::currentMSecsSinceEpoch();
start_timestamp_ = ruler_->GetTime();
playback_timer_.start();
controls_->ShowPauseButton();
PlayInternal(1);
}
void ViewerWidget::Pause()
@@ -208,6 +217,8 @@ void ViewerWidget::Pause()
playback_timer_.stop();
controls_->ShowPlayButton();
playback_speed_ = 0;
}
void ViewerWidget::GoToStart()
@@ -238,13 +249,55 @@ void ViewerWidget::GoToEnd()
qWarning() << "No end frame support yet";
}
void ViewerWidget::ShuttleLeft()
{
int current_speed = playback_speed_;
if (current_speed != 0) {
Pause();
}
current_speed--;
if (current_speed != 0) {
PlayInternal(current_speed);
}
}
void ViewerWidget::ShuttleStop()
{
Pause();
}
void ViewerWidget::ShuttleRight()
{
int current_speed = playback_speed_;
if (current_speed != 0) {
Pause();
}
current_speed++;
if (current_speed != 0) {
PlayInternal(current_speed);
}
}
void ViewerWidget::PlaybackTimerUpdate()
{
int64_t real_time = QDateTime::currentMSecsSinceEpoch() - start_msec_;
int64_t frames_since_start = qRound(static_cast<double>(real_time) / (time_base_dbl_ * 1000));
SetTime(start_timestamp_ + frames_since_start);
int64_t current_time = start_timestamp_ + frames_since_start * playback_speed_;
if (current_time < 0) {
current_time = 0;
Pause();
}
SetTime(current_time);
}
void ViewerWidget::ViewerNodeChangedBetween(const rational &start, const rational &end)
+10
View File
@@ -86,6 +86,12 @@ public slots:
void GoToEnd();
void ShuttleLeft();
void ShuttleStop();
void ShuttleRight();
signals:
void TimeChanged(const rational&);
@@ -97,6 +103,8 @@ private:
void UpdateTextureFromNode(const rational &time);
void PlayInternal(int speed);
ViewerGLWidget* gl_widget_;
PlaybackControls* controls_;
@@ -116,6 +124,8 @@ private:
ViewerOutput* viewer_node_;
int playback_speed_;
private slots:
void RulerTimeChange(int64_t);
+41 -8
View File
@@ -23,6 +23,7 @@
#include <QEvent>
#include "core.h"
#include "dialog/actionsearch/actionsearch.h"
#include "panel/panelmanager.h"
#include "tool/tool.h"
#include "ui/style/style.h"
@@ -169,8 +170,8 @@ MainMenu::MainMenu(QMainWindow *parent) :
playback_menu_->addSeparator();
playback_prevcut_item_ = playback_menu_->AddItem("prevcut", nullptr, nullptr, "Up");
playback_nextcut_item_ = playback_menu_->AddItem("nextcut", nullptr, nullptr, "Down");
playback_prevcut_item_ = playback_menu_->AddItem("prevcut", this, SLOT(GoToPrevCutTriggered()), "Up");
playback_nextcut_item_ = playback_menu_->AddItem("nextcut", this, SLOT(GoToNextCutTriggered()), "Down");
playback_menu_->addSeparator();
@@ -179,9 +180,9 @@ MainMenu::MainMenu(QMainWindow *parent) :
playback_menu_->addSeparator();
playback_shuttleleft_item_ = playback_menu_->AddItem("decspeed", nullptr, nullptr, "J");
playback_shuttlestop_item_ = playback_menu_->AddItem("pause", nullptr, nullptr, "K");
playback_shuttleright_item_ = playback_menu_->AddItem("incspeed", nullptr, nullptr, "L");
playback_shuttleleft_item_ = playback_menu_->AddItem("decspeed", this, SLOT(ShuttleLeftTriggered()), "J");
playback_shuttlestop_item_ = playback_menu_->AddItem("pause", this, SLOT(ShuttleStopTriggered()), "K");
playback_shuttleright_item_ = playback_menu_->AddItem("incspeed", this, SLOT(ShuttleRightTriggered()), "L");
playback_menu_->addSeparator();
@@ -193,7 +194,7 @@ MainMenu::MainMenu(QMainWindow *parent) :
//
window_menu_ = new Menu(this, this, SLOT(WindowMenuAboutToShow()));
window_menu_separator_ = window_menu_->addSeparator();
window_maximize_panel_item_ = window_menu_->AddItem("maximizepanel", nullptr, nullptr, "`");
window_maximize_panel_item_ = window_menu_->AddItem("maximizepanel", parent, SLOT(ToggleMaximizedPanel()), "`");
window_lock_layout_item_ = window_menu_->AddItem("lockpanels", olive::panel_manager, SLOT(SetPanelsLocked(bool)));
window_lock_layout_item_->setCheckable(true);
window_menu_->addSeparator();
@@ -294,11 +295,11 @@ MainMenu::MainMenu(QMainWindow *parent) :
// HELP MENU
//
help_menu_ = new Menu(this);
help_action_search_item_ = help_menu_->AddItem("actionsearch", nullptr, nullptr, "/");
help_action_search_item_ = help_menu_->AddItem("actionsearch", this, SLOT(ActionSearchTriggered()), "/");
help_menu_->addSeparator();
help_debug_log_item_ = help_menu_->AddItem("debuglog", nullptr, nullptr);
help_menu_->addSeparator();
help_about_item_ = help_menu_->AddItem("about", nullptr, nullptr);
help_about_item_ = help_menu_->AddItem("about", &olive::core, SLOT(DialogAboutShow()));
Retranslate();
}
@@ -427,6 +428,38 @@ void MainMenu::EditToOutTriggered()
olive::panel_manager->CurrentlyFocused()->EditToOut();
}
void MainMenu::ActionSearchTriggered()
{
ActionSearch as(parentWidget());
as.SetMenuBar(this);
as.exec();
}
void MainMenu::ShuttleLeftTriggered()
{
olive::panel_manager->CurrentlyFocused()->ShuttleLeft();
}
void MainMenu::ShuttleStopTriggered()
{
olive::panel_manager->CurrentlyFocused()->ShuttleStop();
}
void MainMenu::ShuttleRightTriggered()
{
olive::panel_manager->CurrentlyFocused()->ShuttleRight();
}
void MainMenu::GoToPrevCutTriggered()
{
olive::panel_manager->CurrentlyFocused()->GoToPrevCut();
}
void MainMenu::GoToNextCutTriggered()
{
olive::panel_manager->CurrentlyFocused()->GoToNextCut();
}
void MainMenu::Retranslate()
{
// MenuShared is not a QWidget and therefore does not receive a LanguageEvent, we use MainMenu's to update it
+11
View File
@@ -24,6 +24,7 @@
#include <QMainWindow>
#include <QMenuBar>
#include "dialog/actionsearch/actionsearch.h"
#include "widget/menu/menu.h"
/**
@@ -106,6 +107,15 @@ private slots:
void EditToInTriggered();
void EditToOutTriggered();
void ActionSearchTriggered();
void ShuttleLeftTriggered();
void ShuttleStopTriggered();
void ShuttleRightTriggered();
void GoToPrevCutTriggered();
void GoToNextCutTriggered();
private:
/**
* @brief Set strings based on the current application language.
@@ -201,6 +211,7 @@ private:
QAction* help_action_search_item_;
QAction* help_debug_log_item_;
QAction* help_about_item_;
};
#endif // MAINMENU_H
+31
View File
@@ -64,6 +64,37 @@ void olive::MainWindow::SetFullscreen(bool fullscreen)
}
}
void olive::MainWindow::ToggleMaximizedPanel()
{
qDebug() << "Hello!";
if (premaximized_state_.isEmpty()) {
// Assume nothing is maximized at the moment
// Find the currently focused panel
PanelWidget* currently_focused = olive::panel_manager->CurrentlyFocused();
// If this panel is not actually on the main window, this is a no-op
if (currently_focused->isFloating()) {
return;
}
// Save the current state so it can be restored later
premaximized_state_ = saveState();
// For every other panel that is on the main window, hide it
foreach (PanelWidget* panel, olive::panel_manager->panels()) {
if (!panel->isFloating() && panel != currently_focused) {
panel->setVisible(false);
}
}
} else {
// Assume we are currently maximized, restore the state
restoreState(premaximized_state_);
premaximized_state_.clear();
}
}
void olive::MainWindow::ProjectOpen(Project* p)
{
// FIXME Use settings data to create panels and restore state if they exist
+2 -1
View File
@@ -38,12 +38,13 @@ public:
public slots:
void ProjectOpen(Project *p);
void SetFullscreen(bool fullscreen);
void ToggleMaximizedPanel();
protected:
virtual void closeEvent(QCloseEvent* e) override;
private:
Qt::WindowStates old_window_state_;
QByteArray premaximized_state_;
};