fix line endings

This commit is contained in:
itsmattkc
2019-06-15 07:39:55 -07:00
parent 13d6f9f5b2
commit 0acee942f4
300 changed files with 49260 additions and 49254 deletions
+66 -66
View File
@@ -1,66 +1,66 @@
/***
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 "aboutdialog.h"
#include <QVBoxLayout>
#include <QLabel>
#include <QDialogButtonBox>
#include "global/global.h"
AboutDialog::AboutDialog(QWidget *parent) :
QDialog(parent)
{
setWindowTitle("About Olive");
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(olive::AppName,
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()));
}
/***
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 "aboutdialog.h"
#include <QVBoxLayout>
#include <QLabel>
#include <QDialogButtonBox>
#include "global/global.h"
AboutDialog::AboutDialog(QWidget *parent) :
QDialog(parent)
{
setWindowTitle("About Olive");
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(olive::AppName,
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 -48
View File
@@ -1,48 +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
/***
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
+244 -244
View File
@@ -1,244 +1,244 @@
/***
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>
#include "ui/mainwindow.h"
ActionSearch::ActionSearch(QWidget *parent) :
QDialog(parent)
{
// 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::search_update(const QString &s, const QString &p, QMenu *parent) {
// 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 = olive::MainWindow->menuBar()->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();
}
/***
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>
#include "ui/mainwindow.h"
ActionSearch::ActionSearch(QWidget *parent) :
QDialog(parent)
{
// 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::search_update(const QString &s, const QString &p, QMenu *parent) {
// 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 = olive::MainWindow->menuBar()->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();
}
+170 -170
View File
@@ -1,170 +1,170 @@
/***
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>
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);
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 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
/***
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>
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);
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 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
+107 -107
View File
@@ -1,107 +1,107 @@
/***
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 "advancedvideodialog.h"
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QLabel>
#include <QComboBox>
#include <QDebug>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavutil/pixdesc.h>
}
AdvancedVideoDialog::AdvancedVideoDialog(QWidget *parent,
AVCodecID encoding_codec,
VideoCodecParams &iparams) :
QDialog(parent),
params_(iparams)
{
setWindowTitle(tr("Advanced Video Settings"));
// use variable for row to assist adding new fields to the grid layout
int row = 0;
// get encoder information for this codec from FFmpeg
AVCodec* codec_info = avcodec_find_encoder(static_cast<AVCodecID>(encoding_codec));
// set up grid layout for dialog
QGridLayout* layout = new QGridLayout(this);
// create row for codec pixel formats
layout->addWidget(new QLabel(tr("Pixel Format:")), row, 0);
pix_fmt_combo_ = new QComboBox();
// loop through available pixel formats for this codec
int pix_fmt_index = 0;
while (codec_info->pix_fmts[pix_fmt_index] != -1) { // AVCodec->pix_fmts is terminated by "-1"
// get the name of the pixel format and add it to the combobox (with the pixel format constant)
pix_fmt_combo_->addItem(av_get_pix_fmt_name(codec_info->pix_fmts[pix_fmt_index]),
codec_info->pix_fmts[pix_fmt_index]);
// if the user has already selected a pixel format, set the combobox to it as well
if (codec_info->pix_fmts[pix_fmt_index] == params_.pix_fmt) {
pix_fmt_combo_->setCurrentIndex(pix_fmt_combo_->count()-1);
}
pix_fmt_index++;
}
layout->addWidget(pix_fmt_combo_, row, 1);
row++;
// create row for multithreading thread count
layout->addWidget(new QLabel(tr("Threads:")), row, 0);
thread_spinbox_ = new QSpinBox();
// with the thread count, "0" is considered automatics
thread_spinbox_->setMinimum(0);
thread_spinbox_->setSpecialValueText("Auto");
// load current thread value
thread_spinbox_->setValue(params_.threads);
layout->addWidget(thread_spinbox_);
row++;
// buttons
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
buttons->setCenterButtons(true);
connect(buttons, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttons, SIGNAL(rejected()), this, SLOT(reject()));
layout->addWidget(buttons, row, 0, 1, 2);
}
void AdvancedVideoDialog::accept() {
// store settings back into struct
params_.pix_fmt = pix_fmt_combo_->currentData().toInt();
params_.threads = thread_spinbox_->value();
QDialog::accept();
}
/***
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 "advancedvideodialog.h"
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QLabel>
#include <QComboBox>
#include <QDebug>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavutil/pixdesc.h>
}
AdvancedVideoDialog::AdvancedVideoDialog(QWidget *parent,
AVCodecID encoding_codec,
VideoCodecParams &iparams) :
QDialog(parent),
params_(iparams)
{
setWindowTitle(tr("Advanced Video Settings"));
// use variable for row to assist adding new fields to the grid layout
int row = 0;
// get encoder information for this codec from FFmpeg
AVCodec* codec_info = avcodec_find_encoder(static_cast<AVCodecID>(encoding_codec));
// set up grid layout for dialog
QGridLayout* layout = new QGridLayout(this);
// create row for codec pixel formats
layout->addWidget(new QLabel(tr("Pixel Format:")), row, 0);
pix_fmt_combo_ = new QComboBox();
// loop through available pixel formats for this codec
int pix_fmt_index = 0;
while (codec_info->pix_fmts[pix_fmt_index] != -1) { // AVCodec->pix_fmts is terminated by "-1"
// get the name of the pixel format and add it to the combobox (with the pixel format constant)
pix_fmt_combo_->addItem(av_get_pix_fmt_name(codec_info->pix_fmts[pix_fmt_index]),
codec_info->pix_fmts[pix_fmt_index]);
// if the user has already selected a pixel format, set the combobox to it as well
if (codec_info->pix_fmts[pix_fmt_index] == params_.pix_fmt) {
pix_fmt_combo_->setCurrentIndex(pix_fmt_combo_->count()-1);
}
pix_fmt_index++;
}
layout->addWidget(pix_fmt_combo_, row, 1);
row++;
// create row for multithreading thread count
layout->addWidget(new QLabel(tr("Threads:")), row, 0);
thread_spinbox_ = new QSpinBox();
// with the thread count, "0" is considered automatics
thread_spinbox_->setMinimum(0);
thread_spinbox_->setSpecialValueText("Auto");
// load current thread value
thread_spinbox_->setValue(params_.threads);
layout->addWidget(thread_spinbox_);
row++;
// buttons
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
buttons->setCenterButtons(true);
connect(buttons, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttons, SIGNAL(rejected()), this, SLOT(reject()));
layout->addWidget(buttons, row, 0, 1, 2);
}
void AdvancedVideoDialog::accept() {
// store settings back into struct
params_.pix_fmt = pix_fmt_combo_->currentData().toInt();
params_.threads = thread_spinbox_->value();
QDialog::accept();
}
+80 -80
View File
@@ -1,80 +1,80 @@
/***
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 ADVANCEDVIDEODIALOG_H
#define ADVANCEDVIDEODIALOG_H
#include <QDialog>
#include <QComboBox>
#include <QSpinBox>
#include "rendering/exportthread.h"
/**
* @brief The AdvancedVideoDialog class
*
* A dialog for interfacing with VideoCodecParams, a struct for more advanced video settings sometimes specific to
* one codec. Primarily a companion to ExportDialog which will provide the VideoCodecParams reference,
*/
class AdvancedVideoDialog : public QDialog {
Q_OBJECT
public:
/**
* @brief AdvancedVideoDialog Constructor
*
* @param parent
*
* QWidget parent. Usually ExportDialog.
*
* @param encoding_codec
*
* The AVCodecID of the selected export codec.
*
* @param iparams
*
* A VideoCodecParams struct containing the extra codec data.
*/
AdvancedVideoDialog(QWidget* parent,
AVCodecID encoding_codec,
VideoCodecParams& iparams);
public slots:
/**
* @brief Overridden accept for saving the UI data into the provided VideoCodecParams struct.
*/
virtual void accept() override;
private:
/**
* @brief Internal reference to VideoCodecParams struct provided by ExportDialog.
*/
VideoCodecParams& params_;
/**
* @brief ComboBox to show available pixel formats for this codec
*/
QComboBox* pix_fmt_combo_;
/**
* @brief SpinBox for multithreading settings
*/
QSpinBox* thread_spinbox_;
};
#endif // ADVANCEDVIDEODIALOG_H
/***
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 ADVANCEDVIDEODIALOG_H
#define ADVANCEDVIDEODIALOG_H
#include <QDialog>
#include <QComboBox>
#include <QSpinBox>
#include "rendering/exportthread.h"
/**
* @brief The AdvancedVideoDialog class
*
* A dialog for interfacing with VideoCodecParams, a struct for more advanced video settings sometimes specific to
* one codec. Primarily a companion to ExportDialog which will provide the VideoCodecParams reference,
*/
class AdvancedVideoDialog : public QDialog {
Q_OBJECT
public:
/**
* @brief AdvancedVideoDialog Constructor
*
* @param parent
*
* QWidget parent. Usually ExportDialog.
*
* @param encoding_codec
*
* The AVCodecID of the selected export codec.
*
* @param iparams
*
* A VideoCodecParams struct containing the extra codec data.
*/
AdvancedVideoDialog(QWidget* parent,
AVCodecID encoding_codec,
VideoCodecParams& iparams);
public slots:
/**
* @brief Overridden accept for saving the UI data into the provided VideoCodecParams struct.
*/
virtual void accept() override;
private:
/**
* @brief Internal reference to VideoCodecParams struct provided by ExportDialog.
*/
VideoCodecParams& params_;
/**
* @brief ComboBox to show available pixel formats for this codec
*/
QComboBox* pix_fmt_combo_;
/**
* @brief SpinBox for multithreading settings
*/
QSpinBox* thread_spinbox_;
};
#endif // ADVANCEDVIDEODIALOG_H
+145 -145
View File
@@ -1,145 +1,145 @@
/***
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 "clippropertiesdialog.h"
#include <QGridLayout>
#include <QLabel>
#include <QDialogButtonBox>
#include "panels/panels.h"
#include "undo/undo.h"
ClipPropertiesDialog::ClipPropertiesDialog(QWidget *parent, QVector<Clip *> clips) :
QDialog(parent)
{
setWindowTitle((clips.size() == 1) ?
tr("\"%1\" Properties").arg(clips.at(0)->name()) :
tr("Multiple Clip Properties"));
clips_ = clips;
QGridLayout* layout = new QGridLayout(this);
int row = 0;
// Clip Name field
layout->addWidget(new QLabel(tr("Name:")), row, 0);
clip_name_field_ = new QLineEdit();
layout->addWidget(clip_name_field_, row, 1);
row++;
// Clip Duration field
layout->addWidget(new QLabel(tr("Duration:")), row, 0);
duration_field_ = new LabelSlider();
duration_field_->SetDisplayType(LabelSlider::FrameNumber);
duration_field_->SetMinimum(1);
layout->addWidget(duration_field_, row, 1);
row++;
// Dialog buttons (OK and Cancel)
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
buttons->setCenterButtons(true);
layout->addWidget(buttons, row, 0, 1, 2);
connect(buttons, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttons, SIGNAL(rejected()), this, SLOT(reject()));
// analyze list of clips for default values
bool all_clips_have_same_name = true;
bool all_clips_have_same_duration = true;
for (int i=1;i<clips.size();i++) {
if (clips.at(i-1)->name() != clips.at(i)->name()) {
all_clips_have_same_name = false;
}
if (clips.at(i-1)->length() != clips.at(i)->length()) {
all_clips_have_same_duration = false;
}
}
Clip* first_clip = clips_.first();
if (all_clips_have_same_name) {
// if there's only one clip selected, set all defaults to that clip's properties
clip_name_field_->setText(first_clip->name());
} else {
// if there are multiple clips, use different properties
clip_name_field_->setPlaceholderText(tr("(multiple)"));
}
// it's assumed all the clips come from the same sequence
duration_field_->SetFrameRate(first_clip->track()->sequence()->frame_rate());
if (all_clips_have_same_duration) {
duration_field_->SetDefault(first_clip->length());
duration_field_->SetValue(first_clip->length());
duration_field_->SetMaximum(first_clip->media_length());
} else {
duration_field_->SetDefault(qSNaN());
duration_field_->SetValue(qSNaN());
}
}
void ClipPropertiesDialog::accept()
{
const QString& clip_name = clip_name_field_->text();
double clip_duration = duration_field_->value();
ComboAction* ca = new ComboAction();
for (int i=0;i<clips_.size();i++) {
Clip* clip = clips_.at(i);
// If the user entered a Clip name and the name is different from the Clip's name, create a rename command
if (!clip_name.isEmpty() && clip_name != clip->name()) {
ca->append(new RenameClipCommand(clip, clip_name));
}
// If the user entered a clip duration (and the duration has changed), create a "clip move" command
if (!qIsNaN(clip_duration)) {
long clip_duration_rounded = qRound(clip_duration);
if (clip->length() != clip_duration_rounded) {
clip->Move(ca,
clip->timeline_in(),
clip->timeline_in() + clip_duration_rounded,
clip->clip_in(),
clip->track());
}
}
}
if (ca->hasActions()) {
olive::undo_stack.push(ca);
update_ui(false);
} else {
delete ca;
}
QDialog::accept();
}
/***
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 "clippropertiesdialog.h"
#include <QGridLayout>
#include <QLabel>
#include <QDialogButtonBox>
#include "panels/panels.h"
#include "undo/undo.h"
ClipPropertiesDialog::ClipPropertiesDialog(QWidget *parent, QVector<Clip *> clips) :
QDialog(parent)
{
setWindowTitle((clips.size() == 1) ?
tr("\"%1\" Properties").arg(clips.at(0)->name()) :
tr("Multiple Clip Properties"));
clips_ = clips;
QGridLayout* layout = new QGridLayout(this);
int row = 0;
// Clip Name field
layout->addWidget(new QLabel(tr("Name:")), row, 0);
clip_name_field_ = new QLineEdit();
layout->addWidget(clip_name_field_, row, 1);
row++;
// Clip Duration field
layout->addWidget(new QLabel(tr("Duration:")), row, 0);
duration_field_ = new LabelSlider();
duration_field_->SetDisplayType(LabelSlider::FrameNumber);
duration_field_->SetMinimum(1);
layout->addWidget(duration_field_, row, 1);
row++;
// Dialog buttons (OK and Cancel)
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
buttons->setCenterButtons(true);
layout->addWidget(buttons, row, 0, 1, 2);
connect(buttons, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttons, SIGNAL(rejected()), this, SLOT(reject()));
// analyze list of clips for default values
bool all_clips_have_same_name = true;
bool all_clips_have_same_duration = true;
for (int i=1;i<clips.size();i++) {
if (clips.at(i-1)->name() != clips.at(i)->name()) {
all_clips_have_same_name = false;
}
if (clips.at(i-1)->length() != clips.at(i)->length()) {
all_clips_have_same_duration = false;
}
}
Clip* first_clip = clips_.first();
if (all_clips_have_same_name) {
// if there's only one clip selected, set all defaults to that clip's properties
clip_name_field_->setText(first_clip->name());
} else {
// if there are multiple clips, use different properties
clip_name_field_->setPlaceholderText(tr("(multiple)"));
}
// it's assumed all the clips come from the same sequence
duration_field_->SetFrameRate(first_clip->track()->sequence()->frame_rate());
if (all_clips_have_same_duration) {
duration_field_->SetDefault(first_clip->length());
duration_field_->SetValue(first_clip->length());
duration_field_->SetMaximum(first_clip->media_length());
} else {
duration_field_->SetDefault(qSNaN());
duration_field_->SetValue(qSNaN());
}
}
void ClipPropertiesDialog::accept()
{
const QString& clip_name = clip_name_field_->text();
double clip_duration = duration_field_->value();
ComboAction* ca = new ComboAction();
for (int i=0;i<clips_.size();i++) {
Clip* clip = clips_.at(i);
// If the user entered a Clip name and the name is different from the Clip's name, create a rename command
if (!clip_name.isEmpty() && clip_name != clip->name()) {
ca->append(new RenameClipCommand(clip, clip_name));
}
// If the user entered a clip duration (and the duration has changed), create a "clip move" command
if (!qIsNaN(clip_duration)) {
long clip_duration_rounded = qRound(clip_duration);
if (clip->length() != clip_duration_rounded) {
clip->Move(ca,
clip->timeline_in(),
clip->timeline_in() + clip_duration_rounded,
clip->clip_in(),
clip->track());
}
}
}
if (ca->hasActions()) {
olive::undo_stack.push(ca);
update_ui(false);
} else {
delete ca;
}
QDialog::accept();
}
+72 -72
View File
@@ -1,72 +1,72 @@
/***
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 CLIPPROPERTIESDIALOG_H
#define CLIPPROPERTIESDIALOG_H
#include <QDialog>
#include <QLineEdit>
#include "timeline/clip.h"
#include "ui/labelslider.h"
/**
* @brief The ClipPropertiesDialog class
*
* A dialog for setting Clip properties, accessible by right clicking a Clip and clicking "Properties". This can be
* run from anywhere provided it's given a valid array of Clip objects.
*/
class ClipPropertiesDialog : public QDialog {
Q_OBJECT
public:
/**
* @brief ClipPropertiesDialog Constructor
* @param parent
*
* Parent widget.
*
* @param clips
*
* Array of Clip objects to set the properties of.
*/
ClipPropertiesDialog(QWidget* parent, QVector<Clip*> clips);
protected:
/**
* @brief Accept override. Saves the current properties to the array of Clips.
*/
virtual void accept() override;
private:
/**
* @brief Internal clip array (set in the constructor)
*/
QVector<Clip*> clips_;
/**
* @brief Widget for setting the Clip names
*/
QLineEdit* clip_name_field_;
/**
* @brief Widget for setting the Clip durations
*/
LabelSlider* duration_field_;
};
#endif // CLIPPROPERTIESDIALOG_H
/***
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 CLIPPROPERTIESDIALOG_H
#define CLIPPROPERTIESDIALOG_H
#include <QDialog>
#include <QLineEdit>
#include "timeline/clip.h"
#include "ui/labelslider.h"
/**
* @brief The ClipPropertiesDialog class
*
* A dialog for setting Clip properties, accessible by right clicking a Clip and clicking "Properties". This can be
* run from anywhere provided it's given a valid array of Clip objects.
*/
class ClipPropertiesDialog : public QDialog {
Q_OBJECT
public:
/**
* @brief ClipPropertiesDialog Constructor
* @param parent
*
* Parent widget.
*
* @param clips
*
* Array of Clip objects to set the properties of.
*/
ClipPropertiesDialog(QWidget* parent, QVector<Clip*> clips);
protected:
/**
* @brief Accept override. Saves the current properties to the array of Clips.
*/
virtual void accept() override;
private:
/**
* @brief Internal clip array (set in the constructor)
*/
QVector<Clip*> clips_;
/**
* @brief Widget for setting the Clip names
*/
QLineEdit* clip_name_field_;
/**
* @brief Widget for setting the Clip durations
*/
LabelSlider* duration_field_;
};
#endif // CLIPPROPERTIESDIALOG_H
+63 -63
View File
@@ -1,63 +1,63 @@
/***
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 "debugdialog.h"
#include <QTextEdit>
#include <QVBoxLayout>
#include <QScrollBar>
#include <QEvent>
#include "global/debug.h"
DebugDialog* olive::DebugDialog = nullptr;
DebugDialog::DebugDialog(QWidget *parent) : QDialog(parent) {
QVBoxLayout* layout = new QVBoxLayout(this);
textEdit = new QTextEdit(this);
textEdit->setWordWrapMode(QTextOption::NoWrap);
layout->addWidget(textEdit);
Retranslate();
}
void DebugDialog::Retranslate()
{
setWindowTitle(tr("Debug Log"));
}
void DebugDialog::update_log() {
textEdit->setHtml(get_debug_str());
textEdit->verticalScrollBar()->setValue(textEdit->verticalScrollBar()->maximum());
}
void DebugDialog::changeEvent(QEvent *e)
{
if (e->type() == QEvent::LanguageChange) {
Retranslate();
} else {
QDialog::changeEvent(e);
}
}
void DebugDialog::showEvent(QShowEvent *) {
update_log();
}
/***
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 "debugdialog.h"
#include <QTextEdit>
#include <QVBoxLayout>
#include <QScrollBar>
#include <QEvent>
#include "global/debug.h"
DebugDialog* olive::DebugDialog = nullptr;
DebugDialog::DebugDialog(QWidget *parent) : QDialog(parent) {
QVBoxLayout* layout = new QVBoxLayout(this);
textEdit = new QTextEdit(this);
textEdit->setWordWrapMode(QTextOption::NoWrap);
layout->addWidget(textEdit);
Retranslate();
}
void DebugDialog::Retranslate()
{
setWindowTitle(tr("Debug Log"));
}
void DebugDialog::update_log() {
textEdit->setHtml(get_debug_str());
textEdit->verticalScrollBar()->setValue(textEdit->verticalScrollBar()->maximum());
}
void DebugDialog::changeEvent(QEvent *e)
{
if (e->type() == QEvent::LanguageChange) {
Retranslate();
} else {
QDialog::changeEvent(e);
}
}
void DebugDialog::showEvent(QShowEvent *) {
update_log();
}
+79 -79
View File
@@ -1,79 +1,79 @@
/***
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 DEBUGDIALOG_H
#define DEBUGDIALOG_H
#include <QDialog>
#include <QTextEdit>
/**
* @brief The DebugDialog class
*
* A dialog to display the current debug output. This dialog is omnipresent and shown and hidden when the user wants
* to see it. For efficiency, it will not update if it's hidden.
*/
class DebugDialog : public QDialog {
Q_OBJECT
public:
/**
* @brief DebugDialog Constructor
* @param parent
*
* Parent widget. Usually MainWindow.
*/
DebugDialog(QWidget* parent = nullptr);
/**
* @brief Retranslate window title
*
* Sets title based on the current translation.
*/
void Retranslate();
public slots:
/**
* @brief Update the visual log with the debug text from get_debug_str()
*/
void update_log();
protected:
/**
* @brief Overrides change event to trigger Retranslate() on a LanguageChange event.
*/
virtual void changeEvent(QEvent* e) override;
/**
* @brief Overrides show event to trigger an update of the visual log (the visual log does not update while the
* debug dialog is hidden).
*/
virtual void showEvent(QShowEvent* event) override;
private:
/**
* @brief Display widget for the debug dialog.
*/
QTextEdit* textEdit;
};
namespace olive {
/**
* @brief Omnipresent instance of DebugDialog to be shown or hidden as the user wants
*/
extern DebugDialog* DebugDialog;
}
#endif // DEBUGDIALOG_H
/***
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 DEBUGDIALOG_H
#define DEBUGDIALOG_H
#include <QDialog>
#include <QTextEdit>
/**
* @brief The DebugDialog class
*
* A dialog to display the current debug output. This dialog is omnipresent and shown and hidden when the user wants
* to see it. For efficiency, it will not update if it's hidden.
*/
class DebugDialog : public QDialog {
Q_OBJECT
public:
/**
* @brief DebugDialog Constructor
* @param parent
*
* Parent widget. Usually MainWindow.
*/
DebugDialog(QWidget* parent = nullptr);
/**
* @brief Retranslate window title
*
* Sets title based on the current translation.
*/
void Retranslate();
public slots:
/**
* @brief Update the visual log with the debug text from get_debug_str()
*/
void update_log();
protected:
/**
* @brief Overrides change event to trigger Retranslate() on a LanguageChange event.
*/
virtual void changeEvent(QEvent* e) override;
/**
* @brief Overrides show event to trigger an update of the visual log (the visual log does not update while the
* debug dialog is hidden).
*/
virtual void showEvent(QShowEvent* event) override;
private:
/**
* @brief Display widget for the debug dialog.
*/
QTextEdit* textEdit;
};
namespace olive {
/**
* @brief Omnipresent instance of DebugDialog to be shown or hidden as the user wants
*/
extern DebugDialog* DebugDialog;
}
#endif // DEBUGDIALOG_H
+62 -62
View File
@@ -1,62 +1,62 @@
/***
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 "demonotice.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QDialogButtonBox>
DemoNotice::DemoNotice(QWidget *parent) :
QDialog(parent)
{
setWindowTitle(tr("Welcome to Olive!"));
QVBoxLayout* vlayout = new QVBoxLayout(this);
QHBoxLayout* layout = new QHBoxLayout();
layout->setMargin(10);
layout->setSpacing(20);
QLabel* icon = new QLabel("<html><head/><body>"
"<p><img src=\":/icons/olive-splash.png\"/></p>"
"</body></html>", this);
layout->addWidget(icon);
QLabel* text = new QLabel("<html><head/><body><p>"
"<span style=\" font-size:14pt;\">"
+ tr("Welcome to Olive!")
+ "</span></p><p>"
+ tr("Olive is a free open-source video editor released under the GNU GPL. If you have paid for this software, you have been scammed.")
+ "</p><p>"
+ tr("This software is currently in ALPHA which means it is unstable and very likely to crash, have bugs, and have missing features. We offer no warranty so use at your own risk. Please report any bugs or feature requests at %1").arg("<a href=\"https://olivevideoeditor.org/\"><span style=\" text-decoration: underline; color:#007af4;\">www.olivevideoeditor.org</span></a>")
+ "</p><p>"
+ tr("Thank you for trying Olive and we hope you enjoy it!")
+ "</p></body></html>", this);
text->setWordWrap(true);
layout->addWidget(text);
vlayout->addLayout(layout);
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok, this);
buttons->setCenterButtons(true);
connect(buttons, SIGNAL(accepted()), this, SLOT(accept()));
vlayout->addWidget(buttons);
}
/***
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 "demonotice.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QDialogButtonBox>
DemoNotice::DemoNotice(QWidget *parent) :
QDialog(parent)
{
setWindowTitle(tr("Welcome to Olive!"));
QVBoxLayout* vlayout = new QVBoxLayout(this);
QHBoxLayout* layout = new QHBoxLayout();
layout->setMargin(10);
layout->setSpacing(20);
QLabel* icon = new QLabel("<html><head/><body>"
"<p><img src=\":/icons/olive-splash.png\"/></p>"
"</body></html>", this);
layout->addWidget(icon);
QLabel* text = new QLabel("<html><head/><body><p>"
"<span style=\" font-size:14pt;\">"
+ tr("Welcome to Olive!")
+ "</span></p><p>"
+ tr("Olive is a free open-source video editor released under the GNU GPL. If you have paid for this software, you have been scammed.")
+ "</p><p>"
+ tr("This software is currently in ALPHA which means it is unstable and very likely to crash, have bugs, and have missing features. We offer no warranty so use at your own risk. Please report any bugs or feature requests at %1").arg("<a href=\"https://olivevideoeditor.org/\"><span style=\" text-decoration: underline; color:#007af4;\">www.olivevideoeditor.org</span></a>")
+ "</p><p>"
+ tr("Thank you for trying Olive and we hope you enjoy it!")
+ "</p></body></html>", this);
text->setWordWrap(true);
layout->addWidget(text);
vlayout->addLayout(layout);
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok, this);
buttons->setCenterButtons(true);
connect(buttons, SIGNAL(accepted()), this, SLOT(accept()));
vlayout->addWidget(buttons);
}
+47 -47
View File
@@ -1,47 +1,47 @@
/***
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 DEMONOTICE_H
#define DEMONOTICE_H
#include <QDialog>
/**
* @brief The DemoNotice class
*
* Simple dialog shown on startup to introduce Olive as alpha software (in release builds). Can be run from anywhere,
* but there should be no reason to create it outside of the application launch.
*
* To be phased out as Olive gains maturity.
*/
class DemoNotice : public QDialog
{
Q_OBJECT
public:
/**
* @brief DemoNotice Constructor
* @param parent
*
* QWidget parent. Usually MainWindow.
*/
explicit DemoNotice(QWidget *parent = nullptr);
};
#endif // DEMONOTICE_H
/***
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 DEMONOTICE_H
#define DEMONOTICE_H
#include <QDialog>
/**
* @brief The DemoNotice class
*
* Simple dialog shown on startup to introduce Olive as alpha software (in release builds). Can be run from anywhere,
* but there should be no reason to create it outside of the application launch.
*
* To be phased out as Olive gains maturity.
*/
class DemoNotice : public QDialog
{
Q_OBJECT
public:
/**
* @brief DemoNotice Constructor
* @param parent
*
* QWidget parent. Usually MainWindow.
*/
explicit DemoNotice(QWidget *parent = nullptr);
};
#endif // DEMONOTICE_H
+807 -807
View File
File diff suppressed because it is too large Load Diff
+277 -277
View File
@@ -1,277 +1,277 @@
/***
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 EXPORTDIALOG_H
#define EXPORTDIALOG_H
#include <QDialog>
#include <QComboBox>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include <QLabel>
#include <QProgressBar>
#include <QGroupBox>
#include "timeline/sequence.h"
#include "rendering/exportthread.h"
/**
* @brief The ExportDialog class
*
* The dialog to initiate an export. Requires a valid Sequence to be set in olive::ActiveSequence or the result is
* defined (most likely a crash), so you should always do a `nullptr` check on olive::ActiveSequence before constructing
* this dialog.
*/
class ExportDialog : public QDialog
{
Q_OBJECT
public:
/**
* @brief ExportDialog Constructor
*
* @param parent
*
* QWidget parent. Usually MainWindow.
*/
explicit ExportDialog(QWidget *parent, Sequence *sequence);
private slots:
/**
* @brief Slot for when the user changes the format
*
* Used to populate the available codecs list for this format.
*
* @param index
*
* Current format index (corresponding to enum ExportFormats)
*/
void format_changed(int index);
/**
* @brief Slot for when the user clicks the Export button
*
* Asks the user for the file to save to.
*/
void StartExport();
/**
* @brief Slot for the export thread to update the progress bar's value
*
* @param value
*
* An value between 0 - 100. A percentage of the Sequence that has been exported so far.
*
* @param remaining_ms
*
* The estimated time in milliseconds that it will take to complete the rest of the Sequence.
*/
void update_progress_bar(int value, qint64 remaining_ms);
/**
* @brief Slot for the export thread completing (both succeeding and failing)
*
* Runs whenever the thread has finished. Determines whether the thread succeeded or not (and shows an error message
* if not), cleans up the ExportThread object, sets the UI state back to normal.
*
* Connect to ExportThread::finished().
*/
void export_thread_finished();
/**
* @brief Slot for when the video codec changes
*
* Some video codecs require different settings. In the case of that, this function sorts through those.
*
* @param index
*
* Current vcodecCombobox index - its item data contains the AVCodecID.
*/
void vcodec_changed(int index);
/**
* @brief Slot for when the compression type changes
*
* Different UI objects should be displayed for different compression types.
*
* @param index
*
* Unused.
*/
void comp_type_changed(int index);
/**
* @brief Slot to open the Advanced Video Dialog
*
* Opens a dialog for setting more advanced video settings and passes a reference to vcodec_params to it.
*/
void open_advanced_video_dialog();
private:
/**
* @brief Function to create UI objects.
*/
void setup_ui();
/**
* @brief Enables/disables certain UI objects based on the exporting state.
*
* Some UI controls don't need to be set while exporting. This function enables/disables them appropriately.
*
* @param r
*
* TRUE if we're exporting, FALSE if we finished.
*/
void prep_ui_for_render(bool r);
/**
* @brief Retrieves the human-readable name of an AVCodecID and adds it to a QComboBox
*
* Also sets that item's data to the AVCodecID so it can be retrieved directly from the QComboBox.
*
* @param box
*
* The QComboBox to add the item to.
*
* @param codec
*
* The codec to add to the QComboBox.
*/
void add_codec_to_combobox(QComboBox* box, enum AVCodecID codec);
/**
* @brief Internal array of human-readable names corresponding to enum ExportFormats
*/
QVector<QString> format_strings;
/**
* @brief Pointer to an ExportThread
*
* Set when exporting starts, and deleted by export_thread_finished() when the thread is complete.
*/
ExportThread* export_thread_;
/**
* @brief Struct for advanced video codec parameters.
*
* More advanced video encoding parameters to be sent to the ExportThread. These variables are not directly editable
* in this dialog, instead calling open_advanced_video_dialog() will open an AdvancedVideoDialog for setting these
* values directly. vcodec_changed() should also set these to the defaults for that codec where appropriate.
*/
VideoCodecParams vcodec_params;
/**
* @brief ComboBox for selecting the time range of the Sequence to export
*/
QComboBox* rangeCombobox;
/**
* @brief SpinBox for the exported video's width
*/
QSpinBox* widthSpinbox;
/**
* @brief SpinBox for the exported video's bitrate
*/
QDoubleSpinBox* videobitrateSpinbox;
/**
* @brief Label for the exported video's bitrate - changes depending on the compression type
*/
QLabel* videoBitrateLabel;
/**
* @brief SpinBox for the exported video's frame rate
*/
QDoubleSpinBox* framerateSpinbox;
/**
* @brief ComboBox for the exported video codec
*/
QComboBox* vcodecCombobox;
/**
* @brief ComboBox for the exported audio's codec
*/
QComboBox* acodecCombobox;
/**
* @brief SpinBox for the exported audio's sample rate
*/
QSpinBox* samplingRateSpinbox;
/**
* @brief SpinBox for the exported audio's bitrate
*/
QSpinBox* audiobitrateSpinbox;
/**
* @brief Progress bar for visually showing the export progress
*/
QProgressBar* progressBar;
/**
* @brief ComboBox for the exported video's format
*/
QComboBox* formatCombobox;
/**
* @brief SpinBox for the exported video's height
*/
QSpinBox* heightSpinbox;
/**
* @brief Export button to trigger the start of an export
*/
QPushButton* export_button;
/**
* @brief Dialog cancel button to close this dialog
*/
QPushButton* cancel_button;
/**
* @brief Cancel button to abort the export before completion
*/
QPushButton* renderCancel;
/**
* @brief GroupBox containing all video-related UI objects
*/
QGroupBox* videoGroupbox;
/**
* @brief GroupBox containing all audio-related UI objects
*/
QGroupBox* audioGroupbox;
/**
* @brief ComboBox for the exported video compression type
*/
QComboBox* compressionTypeCombobox;
/**
* @brief Time value set when exporting begins to determine the total duration of the export
*/
qint64 total_export_time_start;
Sequence* sequence_;
};
#endif // EXPORTDIALOG_H
/***
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 EXPORTDIALOG_H
#define EXPORTDIALOG_H
#include <QDialog>
#include <QComboBox>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include <QLabel>
#include <QProgressBar>
#include <QGroupBox>
#include "timeline/sequence.h"
#include "rendering/exportthread.h"
/**
* @brief The ExportDialog class
*
* The dialog to initiate an export. Requires a valid Sequence to be set in olive::ActiveSequence or the result is
* defined (most likely a crash), so you should always do a `nullptr` check on olive::ActiveSequence before constructing
* this dialog.
*/
class ExportDialog : public QDialog
{
Q_OBJECT
public:
/**
* @brief ExportDialog Constructor
*
* @param parent
*
* QWidget parent. Usually MainWindow.
*/
explicit ExportDialog(QWidget *parent, Sequence *sequence);
private slots:
/**
* @brief Slot for when the user changes the format
*
* Used to populate the available codecs list for this format.
*
* @param index
*
* Current format index (corresponding to enum ExportFormats)
*/
void format_changed(int index);
/**
* @brief Slot for when the user clicks the Export button
*
* Asks the user for the file to save to.
*/
void StartExport();
/**
* @brief Slot for the export thread to update the progress bar's value
*
* @param value
*
* An value between 0 - 100. A percentage of the Sequence that has been exported so far.
*
* @param remaining_ms
*
* The estimated time in milliseconds that it will take to complete the rest of the Sequence.
*/
void update_progress_bar(int value, qint64 remaining_ms);
/**
* @brief Slot for the export thread completing (both succeeding and failing)
*
* Runs whenever the thread has finished. Determines whether the thread succeeded or not (and shows an error message
* if not), cleans up the ExportThread object, sets the UI state back to normal.
*
* Connect to ExportThread::finished().
*/
void export_thread_finished();
/**
* @brief Slot for when the video codec changes
*
* Some video codecs require different settings. In the case of that, this function sorts through those.
*
* @param index
*
* Current vcodecCombobox index - its item data contains the AVCodecID.
*/
void vcodec_changed(int index);
/**
* @brief Slot for when the compression type changes
*
* Different UI objects should be displayed for different compression types.
*
* @param index
*
* Unused.
*/
void comp_type_changed(int index);
/**
* @brief Slot to open the Advanced Video Dialog
*
* Opens a dialog for setting more advanced video settings and passes a reference to vcodec_params to it.
*/
void open_advanced_video_dialog();
private:
/**
* @brief Function to create UI objects.
*/
void setup_ui();
/**
* @brief Enables/disables certain UI objects based on the exporting state.
*
* Some UI controls don't need to be set while exporting. This function enables/disables them appropriately.
*
* @param r
*
* TRUE if we're exporting, FALSE if we finished.
*/
void prep_ui_for_render(bool r);
/**
* @brief Retrieves the human-readable name of an AVCodecID and adds it to a QComboBox
*
* Also sets that item's data to the AVCodecID so it can be retrieved directly from the QComboBox.
*
* @param box
*
* The QComboBox to add the item to.
*
* @param codec
*
* The codec to add to the QComboBox.
*/
void add_codec_to_combobox(QComboBox* box, enum AVCodecID codec);
/**
* @brief Internal array of human-readable names corresponding to enum ExportFormats
*/
QVector<QString> format_strings;
/**
* @brief Pointer to an ExportThread
*
* Set when exporting starts, and deleted by export_thread_finished() when the thread is complete.
*/
ExportThread* export_thread_;
/**
* @brief Struct for advanced video codec parameters.
*
* More advanced video encoding parameters to be sent to the ExportThread. These variables are not directly editable
* in this dialog, instead calling open_advanced_video_dialog() will open an AdvancedVideoDialog for setting these
* values directly. vcodec_changed() should also set these to the defaults for that codec where appropriate.
*/
VideoCodecParams vcodec_params;
/**
* @brief ComboBox for selecting the time range of the Sequence to export
*/
QComboBox* rangeCombobox;
/**
* @brief SpinBox for the exported video's width
*/
QSpinBox* widthSpinbox;
/**
* @brief SpinBox for the exported video's bitrate
*/
QDoubleSpinBox* videobitrateSpinbox;
/**
* @brief Label for the exported video's bitrate - changes depending on the compression type
*/
QLabel* videoBitrateLabel;
/**
* @brief SpinBox for the exported video's frame rate
*/
QDoubleSpinBox* framerateSpinbox;
/**
* @brief ComboBox for the exported video codec
*/
QComboBox* vcodecCombobox;
/**
* @brief ComboBox for the exported audio's codec
*/
QComboBox* acodecCombobox;
/**
* @brief SpinBox for the exported audio's sample rate
*/
QSpinBox* samplingRateSpinbox;
/**
* @brief SpinBox for the exported audio's bitrate
*/
QSpinBox* audiobitrateSpinbox;
/**
* @brief Progress bar for visually showing the export progress
*/
QProgressBar* progressBar;
/**
* @brief ComboBox for the exported video's format
*/
QComboBox* formatCombobox;
/**
* @brief SpinBox for the exported video's height
*/
QSpinBox* heightSpinbox;
/**
* @brief Export button to trigger the start of an export
*/
QPushButton* export_button;
/**
* @brief Dialog cancel button to close this dialog
*/
QPushButton* cancel_button;
/**
* @brief Cancel button to abort the export before completion
*/
QPushButton* renderCancel;
/**
* @brief GroupBox containing all video-related UI objects
*/
QGroupBox* videoGroupbox;
/**
* @brief GroupBox containing all audio-related UI objects
*/
QGroupBox* audioGroupbox;
/**
* @brief ComboBox for the exported video compression type
*/
QComboBox* compressionTypeCombobox;
/**
* @brief Time value set when exporting begins to determine the total duration of the export
*/
qint64 total_export_time_start;
Sequence* sequence_;
};
#endif // EXPORTDIALOG_H
+63 -63
View File
@@ -1,63 +1,63 @@
/***
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 "loaddialog.h"
#include <QVBoxLayout>
#include <QLabel>
#include <QPushButton>
#include "global/global.h"
#include "panels/panels.h"
#include "ui/sourcetable.h"
#include "ui/mainwindow.h"
LoadDialog::LoadDialog(QWidget *parent) :
QDialog(parent)
{
setWindowTitle(tr("Loading..."));
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
QVBoxLayout* layout = new QVBoxLayout(this);
layout->addWidget(new QLabel(tr("Loading '%1'...").arg(olive::ActiveProjectFilename.mid(olive::ActiveProjectFilename.lastIndexOf('/')+1)), this));
bar = new QProgressBar(this);
bar->setValue(0);
layout->addWidget(bar);
QPushButton* cancel_button = new QPushButton(tr("Cancel"), this);
connect(cancel_button, SIGNAL(clicked(bool)), this, SIGNAL(cancel()));
// Wrap cancel button in a horizontal layout so it can be centered
QHBoxLayout* hboxLayout = new QHBoxLayout();
hboxLayout->addStretch();
hboxLayout->addWidget(cancel_button);
hboxLayout->addStretch();
layout->addLayout(hboxLayout);
}
void LoadDialog::setValue(int i)
{
bar->setValue(i);
}
/***
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 "loaddialog.h"
#include <QVBoxLayout>
#include <QLabel>
#include <QPushButton>
#include "global/global.h"
#include "panels/panels.h"
#include "ui/sourcetable.h"
#include "ui/mainwindow.h"
LoadDialog::LoadDialog(QWidget *parent) :
QDialog(parent)
{
setWindowTitle(tr("Loading..."));
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
QVBoxLayout* layout = new QVBoxLayout(this);
layout->addWidget(new QLabel(tr("Loading '%1'...").arg(olive::ActiveProjectFilename.mid(olive::ActiveProjectFilename.lastIndexOf('/')+1)), this));
bar = new QProgressBar(this);
bar->setValue(0);
layout->addWidget(bar);
QPushButton* cancel_button = new QPushButton(tr("Cancel"), this);
connect(cancel_button, SIGNAL(clicked(bool)), this, SIGNAL(cancel()));
// Wrap cancel button in a horizontal layout so it can be centered
QHBoxLayout* hboxLayout = new QHBoxLayout();
hboxLayout->addStretch();
hboxLayout->addWidget(cancel_button);
hboxLayout->addStretch();
layout->addLayout(hboxLayout);
}
void LoadDialog::setValue(int i)
{
bar->setValue(i);
}
+76 -76
View File
@@ -1,76 +1,76 @@
/***
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 LOADDIALOG_H
#define LOADDIALOG_H
#include <QDialog>
#include <QProgressBar>
#include <QHBoxLayout>
#include "project/projectelements.h"
#include "project/loadthread.h"
/**
* @brief The LoadDialog class
*
* Shows a modal dialog for loading a project. Designed to be connected to a LoadThread object. This dialog should
* generally not be created directly, use OliveGlobal::LoadProject (or its variants) to correctly set up a LoadDialog
* and LoadThread and connect them to each other.
*/
class LoadDialog : public QDialog
{
Q_OBJECT
public:
/**
* @brief LoadDialog Constructor
*
* @param parent
*
* QWidget parent. Usually MainWindow.
*/
LoadDialog(QWidget* parent);
public slots:
/**
* @brief Set the progress bar value
*
* Ideally, connect this to LoadThread::report_progress().
*
* @param i
*
* Should be a value between 0-100.
*/
void setValue(int i);
signals:
/**
* @brief Signal emitted when the cancel button is clicked.
*
* Ideally, connect this to LoadThread::cancel();
*/
void cancel();
private:
/**
* @brief Progress bar widget
*/
QProgressBar* bar;
};
#endif // LOADDIALOG_H
/***
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 LOADDIALOG_H
#define LOADDIALOG_H
#include <QDialog>
#include <QProgressBar>
#include <QHBoxLayout>
#include "project/projectelements.h"
#include "project/loadthread.h"
/**
* @brief The LoadDialog class
*
* Shows a modal dialog for loading a project. Designed to be connected to a LoadThread object. This dialog should
* generally not be created directly, use OliveGlobal::LoadProject (or its variants) to correctly set up a LoadDialog
* and LoadThread and connect them to each other.
*/
class LoadDialog : public QDialog
{
Q_OBJECT
public:
/**
* @brief LoadDialog Constructor
*
* @param parent
*
* QWidget parent. Usually MainWindow.
*/
LoadDialog(QWidget* parent);
public slots:
/**
* @brief Set the progress bar value
*
* Ideally, connect this to LoadThread::report_progress().
*
* @param i
*
* Should be a value between 0-100.
*/
void setValue(int i);
signals:
/**
* @brief Signal emitted when the cancel button is clicked.
*
* Ideally, connect this to LoadThread::cancel();
*/
void cancel();
private:
/**
* @brief Progress bar widget
*/
QProgressBar* bar;
};
#endif // LOADDIALOG_H
+238 -238
View File
@@ -1,238 +1,238 @@
/***
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 "mediapropertiesdialog.h"
#include <QGridLayout>
#include <QLabel>
#include <QComboBox>
#include <QLineEdit>
#include <QDialogButtonBox>
#include <QTreeWidgetItem>
#include <QGroupBox>
#include <QListWidget>
#include <QCheckBox>
#include <QSpinBox>
#include <OpenColorIO/OpenColorIO.h>
namespace OCIO = OCIO_NAMESPACE::v1;
#include "project/footage.h"
#include "project/media.h"
#include "panels/project.h"
#include "undo/undo.h"
#include "undo/undostack.h"
MediaPropertiesDialog::MediaPropertiesDialog(QWidget *parent, Media *i) :
QDialog(parent),
item(i)
{
setWindowTitle(tr("\"%1\" Properties").arg(i->get_name()));
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QGridLayout* grid = new QGridLayout(this);
int row = 0;
Footage* f = item->to_footage();
grid->addWidget(new QLabel(tr("Tracks:"), this), row, 0, 1, 2);
row++;
track_list = new QListWidget(this);
for (int i=0;i<f->video_tracks.size();i++) {
const FootageStream& fs = f->video_tracks.at(i);
QListWidgetItem* item = new QListWidgetItem(
tr("Video %1: %2x%3 %4FPS").arg(
QString::number(fs.file_index),
QString::number(fs.video_width),
QString::number(fs.video_height),
QString::number(fs.video_frame_rate)
),
track_list
);
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(fs.enabled ? Qt::Checked : Qt::Unchecked);
item->setData(Qt::UserRole+1, fs.file_index);
track_list->addItem(item);
}
for (int i=0;i<f->audio_tracks.size();i++) {
const FootageStream& fs = f->audio_tracks.at(i);
QListWidgetItem* item = new QListWidgetItem(
tr("Audio %1: %2Hz %3").arg(
QString::number(fs.file_index),
QString::number(fs.audio_frequency),
tr("%n channel(s)", "", fs.audio_channels)
),
track_list
);
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(fs.enabled ? Qt::Checked : Qt::Unchecked);
item->setData(Qt::UserRole+1, fs.file_index);
track_list->addItem(item);
}
grid->addWidget(track_list, row, 0, 1, 2);
row++;
if (f->video_tracks.size() > 0) {
// frame conforming
if (!f->video_tracks.at(0).infinite_length) {
grid->addWidget(new QLabel(tr("Conform to Frame Rate:"), this), row, 0);
conform_fr = new QDoubleSpinBox(this);
conform_fr->setMinimum(0.01);
conform_fr->setValue(f->video_tracks.at(0).video_frame_rate * f->speed);
grid->addWidget(conform_fr, row, 1);
}
row++;
// premultiplied alpha mode
premultiply_alpha_setting = new QCheckBox(tr("Alpha is Premultiplied"), this);
premultiply_alpha_setting->setChecked(f->alpha_is_associated);
grid->addWidget(premultiply_alpha_setting, row, 0);
row++;
// deinterlacing mode
interlacing_box = new QComboBox(this);
interlacing_box->addItem(
tr("Auto (%1)").arg(
Footage::get_interlacing_name(f->video_tracks.at(0).video_auto_interlacing)
)
);
interlacing_box->addItem(Footage::get_interlacing_name(VIDEO_PROGRESSIVE));
interlacing_box->addItem(Footage::get_interlacing_name(VIDEO_TOP_FIELD_FIRST));
interlacing_box->addItem(Footage::get_interlacing_name(VIDEO_BOTTOM_FIELD_FIRST));
interlacing_box->setCurrentIndex(
(f->video_tracks.at(0).video_auto_interlacing == f->video_tracks.at(0).video_interlacing)
? 0
: f->video_tracks.at(0).video_interlacing + 1);
grid->addWidget(new QLabel(tr("Interlacing:"), this), row, 0);
grid->addWidget(interlacing_box, row, 1);
row++;
input_color_space = new QComboBox(this);
OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
QString footage_colorspace = f->Colorspace();
for (int i=0;i<config->getNumColorSpaces();i++) {
QString colorspace = config->getColorSpaceNameByIndex(i);
input_color_space->addItem(colorspace);
if (colorspace == footage_colorspace) {
input_color_space->setCurrentIndex(i);
}
}
grid->addWidget(new QLabel(tr("Color Space:")), row, 0);
grid->addWidget(input_color_space, row, 1);
row++;
}
name_box = new QLineEdit(item->get_name(), this);
grid->addWidget(new QLabel(tr("Name:"), this), row, 0);
grid->addWidget(name_box, row, 1);
row++;
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
buttons->setCenterButtons(true);
grid->addWidget(buttons, row, 0, 1, 2);
connect(buttons, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttons, SIGNAL(rejected()), this, SLOT(reject()));
}
void MediaPropertiesDialog::accept() {
Footage* f = item->to_footage();
ComboAction* ca = new ComboAction();
// set track enable
for (int i=0;i<track_list->count();i++) {
QListWidgetItem* item = track_list->item(i);
const QVariant& data = item->data(Qt::UserRole+1);
if (!data.isNull()) {
int index = data.toInt();
bool found = false;
for (int j=0;j<f->video_tracks.size();j++) {
if (f->video_tracks.at(j).file_index == index) {
f->video_tracks[j].enabled = (item->checkState() == Qt::Checked);
found = true;
break;
}
}
if (!found) {
for (int j=0;j<f->audio_tracks.size();j++) {
if (f->audio_tracks.at(j).file_index == index) {
f->audio_tracks[j].enabled = (item->checkState() == Qt::Checked);
break;
}
}
}
}
}
bool refresh_clips = false;
// set interlacing
if (f->video_tracks.size() > 0) {
if (interlacing_box->currentIndex() > 0) {
ca->append(new SetInt(&f->video_tracks[0].video_interlacing, interlacing_box->currentIndex() - 1));
} else {
ca->append(new SetInt(&f->video_tracks[0].video_interlacing, f->video_tracks.at(0).video_auto_interlacing));
}
// set frame rate conform
if (!f->video_tracks.at(0).infinite_length) {
if (!qFuzzyCompare(conform_fr->value(), f->video_tracks.at(0).video_frame_rate)) {
ca->append(new SetDouble(&f->speed, f->speed, conform_fr->value()/f->video_tracks.at(0).video_frame_rate));
refresh_clips = true;
}
}
// set premultiplied alpha
f->alpha_is_associated = premultiply_alpha_setting->isChecked();
}
f->SetColorspace(input_color_space->currentText());
// set name
MediaRename* mr = new MediaRename(item, name_box->text());
ca->append(mr);
ca->appendPost(new CloseAllClipsCommand());
ca->appendPost(new UpdateFootageTooltip(item));
if (refresh_clips) {
ca->appendPost(new RefreshClips(item));
}
ca->appendPost(new UpdateViewer());
olive::undo_stack.push(ca);
QDialog::accept();
}
/***
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 "mediapropertiesdialog.h"
#include <QGridLayout>
#include <QLabel>
#include <QComboBox>
#include <QLineEdit>
#include <QDialogButtonBox>
#include <QTreeWidgetItem>
#include <QGroupBox>
#include <QListWidget>
#include <QCheckBox>
#include <QSpinBox>
#include <OpenColorIO/OpenColorIO.h>
namespace OCIO = OCIO_NAMESPACE::v1;
#include "project/footage.h"
#include "project/media.h"
#include "panels/project.h"
#include "undo/undo.h"
#include "undo/undostack.h"
MediaPropertiesDialog::MediaPropertiesDialog(QWidget *parent, Media *i) :
QDialog(parent),
item(i)
{
setWindowTitle(tr("\"%1\" Properties").arg(i->get_name()));
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QGridLayout* grid = new QGridLayout(this);
int row = 0;
Footage* f = item->to_footage();
grid->addWidget(new QLabel(tr("Tracks:"), this), row, 0, 1, 2);
row++;
track_list = new QListWidget(this);
for (int i=0;i<f->video_tracks.size();i++) {
const FootageStream& fs = f->video_tracks.at(i);
QListWidgetItem* item = new QListWidgetItem(
tr("Video %1: %2x%3 %4FPS").arg(
QString::number(fs.file_index),
QString::number(fs.video_width),
QString::number(fs.video_height),
QString::number(fs.video_frame_rate)
),
track_list
);
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(fs.enabled ? Qt::Checked : Qt::Unchecked);
item->setData(Qt::UserRole+1, fs.file_index);
track_list->addItem(item);
}
for (int i=0;i<f->audio_tracks.size();i++) {
const FootageStream& fs = f->audio_tracks.at(i);
QListWidgetItem* item = new QListWidgetItem(
tr("Audio %1: %2Hz %3").arg(
QString::number(fs.file_index),
QString::number(fs.audio_frequency),
tr("%n channel(s)", "", fs.audio_channels)
),
track_list
);
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(fs.enabled ? Qt::Checked : Qt::Unchecked);
item->setData(Qt::UserRole+1, fs.file_index);
track_list->addItem(item);
}
grid->addWidget(track_list, row, 0, 1, 2);
row++;
if (f->video_tracks.size() > 0) {
// frame conforming
if (!f->video_tracks.at(0).infinite_length) {
grid->addWidget(new QLabel(tr("Conform to Frame Rate:"), this), row, 0);
conform_fr = new QDoubleSpinBox(this);
conform_fr->setMinimum(0.01);
conform_fr->setValue(f->video_tracks.at(0).video_frame_rate * f->speed);
grid->addWidget(conform_fr, row, 1);
}
row++;
// premultiplied alpha mode
premultiply_alpha_setting = new QCheckBox(tr("Alpha is Premultiplied"), this);
premultiply_alpha_setting->setChecked(f->alpha_is_associated);
grid->addWidget(premultiply_alpha_setting, row, 0);
row++;
// deinterlacing mode
interlacing_box = new QComboBox(this);
interlacing_box->addItem(
tr("Auto (%1)").arg(
Footage::get_interlacing_name(f->video_tracks.at(0).video_auto_interlacing)
)
);
interlacing_box->addItem(Footage::get_interlacing_name(VIDEO_PROGRESSIVE));
interlacing_box->addItem(Footage::get_interlacing_name(VIDEO_TOP_FIELD_FIRST));
interlacing_box->addItem(Footage::get_interlacing_name(VIDEO_BOTTOM_FIELD_FIRST));
interlacing_box->setCurrentIndex(
(f->video_tracks.at(0).video_auto_interlacing == f->video_tracks.at(0).video_interlacing)
? 0
: f->video_tracks.at(0).video_interlacing + 1);
grid->addWidget(new QLabel(tr("Interlacing:"), this), row, 0);
grid->addWidget(interlacing_box, row, 1);
row++;
input_color_space = new QComboBox(this);
OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
QString footage_colorspace = f->Colorspace();
for (int i=0;i<config->getNumColorSpaces();i++) {
QString colorspace = config->getColorSpaceNameByIndex(i);
input_color_space->addItem(colorspace);
if (colorspace == footage_colorspace) {
input_color_space->setCurrentIndex(i);
}
}
grid->addWidget(new QLabel(tr("Color Space:")), row, 0);
grid->addWidget(input_color_space, row, 1);
row++;
}
name_box = new QLineEdit(item->get_name(), this);
grid->addWidget(new QLabel(tr("Name:"), this), row, 0);
grid->addWidget(name_box, row, 1);
row++;
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
buttons->setCenterButtons(true);
grid->addWidget(buttons, row, 0, 1, 2);
connect(buttons, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttons, SIGNAL(rejected()), this, SLOT(reject()));
}
void MediaPropertiesDialog::accept() {
Footage* f = item->to_footage();
ComboAction* ca = new ComboAction();
// set track enable
for (int i=0;i<track_list->count();i++) {
QListWidgetItem* item = track_list->item(i);
const QVariant& data = item->data(Qt::UserRole+1);
if (!data.isNull()) {
int index = data.toInt();
bool found = false;
for (int j=0;j<f->video_tracks.size();j++) {
if (f->video_tracks.at(j).file_index == index) {
f->video_tracks[j].enabled = (item->checkState() == Qt::Checked);
found = true;
break;
}
}
if (!found) {
for (int j=0;j<f->audio_tracks.size();j++) {
if (f->audio_tracks.at(j).file_index == index) {
f->audio_tracks[j].enabled = (item->checkState() == Qt::Checked);
break;
}
}
}
}
}
bool refresh_clips = false;
// set interlacing
if (f->video_tracks.size() > 0) {
if (interlacing_box->currentIndex() > 0) {
ca->append(new SetInt(&f->video_tracks[0].video_interlacing, interlacing_box->currentIndex() - 1));
} else {
ca->append(new SetInt(&f->video_tracks[0].video_interlacing, f->video_tracks.at(0).video_auto_interlacing));
}
// set frame rate conform
if (!f->video_tracks.at(0).infinite_length) {
if (!qFuzzyCompare(conform_fr->value(), f->video_tracks.at(0).video_frame_rate)) {
ca->append(new SetDouble(&f->speed, f->speed, conform_fr->value()/f->video_tracks.at(0).video_frame_rate));
refresh_clips = true;
}
}
// set premultiplied alpha
f->alpha_is_associated = premultiply_alpha_setting->isChecked();
}
f->SetColorspace(input_color_space->currentText());
// set name
MediaRename* mr = new MediaRename(item, name_box->text());
ca->append(mr);
ca->appendPost(new CloseAllClipsCommand());
ca->appendPost(new UpdateFootageTooltip(item));
if (refresh_clips) {
ca->appendPost(new RefreshClips(item));
}
ca->appendPost(new UpdateViewer());
olive::undo_stack.push(ca);
QDialog::accept();
}
+97 -97
View File
@@ -1,97 +1,97 @@
/***
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 MEDIAPROPERTIESDIALOG_H
#define MEDIAPROPERTIESDIALOG_H
#include <QDialog>
#include <QComboBox>
#include <QLineEdit>
#include <QListWidget>
#include <QDoubleSpinBox>
#include <QCheckBox>
#include "project/footage.h"
#include "project/media.h"
/**
* @brief The MediaPropertiesDialog class
*
* A dialog for setting properties on Media. This can be loaded from any part of the application provided it's given
* a valid Media object.
*/
class MediaPropertiesDialog : public QDialog {
Q_OBJECT
public:
/**
* @brief MediaPropertiesDialog Constructor
*
* @param parent
*
* QWidget parent. Usually MainWindow or Project panel.
*
* @param i
*
* Media object to set properties for.
*/
MediaPropertiesDialog(QWidget *parent, Media* i);
private:
/**
* @brief ComboBox for interlacing setting
*/
QComboBox* interlacing_box;
/**
* @brief Media name text field
*/
QLineEdit* name_box;
/**
* @brief Internal pointer to Media object (set in constructor)
*/
Media* item;
/**
* @brief A list widget for listing the tracks in Media
*/
QListWidget* track_list;
/**
* @brief Frame rate to conform to
*/
QDoubleSpinBox* conform_fr;
/**
* @brief Setting for associated/premultiplied alpha
*/
QCheckBox* premultiply_alpha_setting;
/**
* @brief Setting for this media's color space
*/
QComboBox* input_color_space;
private slots:
/**
* @brief Overridden accept function for saving the properties back to the Media class
*/
void accept();
};
#endif // MEDIAPROPERTIESDIALOG_H
/***
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 MEDIAPROPERTIESDIALOG_H
#define MEDIAPROPERTIESDIALOG_H
#include <QDialog>
#include <QComboBox>
#include <QLineEdit>
#include <QListWidget>
#include <QDoubleSpinBox>
#include <QCheckBox>
#include "project/footage.h"
#include "project/media.h"
/**
* @brief The MediaPropertiesDialog class
*
* A dialog for setting properties on Media. This can be loaded from any part of the application provided it's given
* a valid Media object.
*/
class MediaPropertiesDialog : public QDialog {
Q_OBJECT
public:
/**
* @brief MediaPropertiesDialog Constructor
*
* @param parent
*
* QWidget parent. Usually MainWindow or Project panel.
*
* @param i
*
* Media object to set properties for.
*/
MediaPropertiesDialog(QWidget *parent, Media* i);
private:
/**
* @brief ComboBox for interlacing setting
*/
QComboBox* interlacing_box;
/**
* @brief Media name text field
*/
QLineEdit* name_box;
/**
* @brief Internal pointer to Media object (set in constructor)
*/
Media* item;
/**
* @brief A list widget for listing the tracks in Media
*/
QListWidget* track_list;
/**
* @brief Frame rate to conform to
*/
QDoubleSpinBox* conform_fr;
/**
* @brief Setting for associated/premultiplied alpha
*/
QCheckBox* premultiply_alpha_setting;
/**
* @brief Setting for this media's color space
*/
QComboBox* input_color_space;
private slots:
/**
* @brief Overridden accept function for saving the properties back to the Media class
*/
void accept();
};
#endif // MEDIAPROPERTIESDIALOG_H
+323 -323
View File
@@ -1,323 +1,323 @@
/***
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 "newsequencedialog.h"
#include <QVariant>
#include <QVBoxLayout>
#include <QComboBox>
#include <QGroupBox>
#include <QGridLayout>
#include <QSpinBox>
#include <QLabel>
#include <QLineEdit>
#include <QDialogButtonBox>
#include "panels/panels.h"
#include "panels/project.h"
#include "timeline/sequence.h"
#include "undo/undostack.h"
#include "undo/undo.h"
#include "timeline/clip.h"
#include "panels/timeline.h"
#include "project/media.h"
#include "rendering/audio.h"
#include "global/config.h"
// FIXME: TEST CODE
#include "nodes/nodes/nodemedia.h"
// END TEST CODE
extern "C" {
#include <libavcodec/avcodec.h>
}
NewSequenceDialog::NewSequenceDialog(QWidget *parent, Media *existing, Sequence* iexisting_sequence) :
QDialog(parent),
existing_item(existing),
existing_sequence(iexisting_sequence)
{
Q_ASSERT(!(existing != nullptr && iexisting_sequence != nullptr));
setup_ui();
if (existing != nullptr) {
existing_sequence = existing->to_sequence().get();
}
if (existing_sequence != nullptr) {
setWindowTitle(tr("Editing \"%1\"").arg(existing_sequence->name()));
width_numeric->setValue(existing_sequence->width());
height_numeric->setValue(existing_sequence->height());
int comp_rate = qRound(existing_sequence->frame_rate()*100);
for (int i=0;i<frame_rate_combobox->count();i++) {
if (qRound(frame_rate_combobox->itemData(i).toDouble()*100) == comp_rate) {
frame_rate_combobox->setCurrentIndex(i);
break;
}
}
sequence_name_edit->setText(existing_sequence->name());
for (int i=0;i<audio_frequency_combobox->count();i++) {
if (audio_frequency_combobox->itemData(i) == existing_sequence->audio_frequency()) {
audio_frequency_combobox->setCurrentIndex(i);
break;
}
}
} else {
existing_sequence = nullptr;
setWindowTitle(tr("New Sequence"));
}
}
void NewSequenceDialog::set_sequence_name(const QString& s) {
sequence_name_edit->setText(s);
}
void NewSequenceDialog::SetNameEditable(bool enabled)
{
sequence_name_edit->setVisible(enabled);
sequence_name_label->setVisible(enabled);
}
void NewSequenceDialog::accept() {
if (existing_sequence == nullptr) {
// The dialog wasn't given an existing Sequence object, so we'll make a new one
SequencePtr s = std::make_shared<Sequence>();
s->set_name(sequence_name_edit->text());
s->set_width(width_numeric->value());
s->set_height(height_numeric->value());
s->set_frame_rate(frame_rate_combobox->currentData().toDouble());
s->set_audio_frequency(audio_frequency_combobox->currentData().toInt());
s->set_audio_layout(AV_CH_LAYOUT_STEREO);
ComboAction* ca = new ComboAction();
olive::project_model.CreateSequence(ca, s, true, nullptr);
olive::undo_stack.push(ca);
} else if (existing_item != nullptr) {
// The dialog was given an existing Sequence object, so we'll apply the changes to it
ComboAction* ca = new ComboAction();
double multiplier = frame_rate_combobox->currentData().toDouble() / existing_sequence->frame_rate();
EditSequenceCommand* esc = new EditSequenceCommand(existing_item, existing_item->to_sequence());
esc->name = sequence_name_edit->text();
esc->width = width_numeric->value();
esc->height = height_numeric->value();
esc->frame_rate = frame_rate_combobox->currentData().toDouble();
esc->audio_frequency = audio_frequency_combobox->currentData().toInt();
esc->audio_layout = AV_CH_LAYOUT_STEREO;
ca->append(esc);
QVector<Clip*> existing_sequence_clips = existing_sequence->GetAllClips();
for (int i=0;i<existing_sequence_clips.size();i++) {
existing_sequence_clips.at(i)->refactor_frame_rate(ca, multiplier, true);
}
olive::undo_stack.push(ca);
} else if (existing_sequence != nullptr) {
// This dialog was given an existing Sequence without a Media wrapper - therefore just directly apply the settings
existing_sequence->set_name(sequence_name_edit->text());
existing_sequence->set_width(width_numeric->value());
existing_sequence->set_height(height_numeric->value());
existing_sequence->set_frame_rate(frame_rate_combobox->currentData().toDouble());
existing_sequence->set_audio_frequency(audio_frequency_combobox->currentData().toInt());
existing_sequence->set_audio_layout(AV_CH_LAYOUT_STEREO);
}
QDialog::accept();
}
void NewSequenceDialog::preset_changed(int index) {
switch (index) {
case 0: // FILM 4K
width_numeric->setValue(4096);
height_numeric->setValue(2160);
break;
case 1: // TV 4K
width_numeric->setValue(3840);
height_numeric->setValue(2160);
break;
case 2: // 1080p
width_numeric->setValue(1920);
height_numeric->setValue(1080);
break;
case 3: // 720p
width_numeric->setValue(1280);
height_numeric->setValue(720);
break;
case 4: // 480p
width_numeric->setValue(640);
height_numeric->setValue(480);
break;
case 5: // 360p
width_numeric->setValue(640);
height_numeric->setValue(360);
break;
case 6: // 240p
width_numeric->setValue(320);
height_numeric->setValue(240);
break;
case 7: // 144p
width_numeric->setValue(192);
height_numeric->setValue(144);
break;
case 8: // NTSC (480i)
width_numeric->setValue(720);
height_numeric->setValue(480);
break;
case 9: // PAL (576i)
width_numeric->setValue(720);
height_numeric->setValue(576);
break;
}
}
void NewSequenceDialog::setup_ui() {
QVBoxLayout* verticalLayout = new QVBoxLayout(this);
QWidget* widget = new QWidget(this);
QHBoxLayout* preset_layout = new QHBoxLayout(widget);
preset_layout->setContentsMargins(0, 0, 0, 0);
preset_layout->addWidget(new QLabel(tr("Preset:"), this));
preset_combobox = new QComboBox(widget);
preset_combobox->addItem(tr("Film 4K"));
preset_combobox->addItem(tr("TV 4K (Ultra HD/2160p)"));
preset_combobox->addItem(tr("1080p"));
preset_combobox->addItem(tr("720p"));
preset_combobox->addItem(tr("480p"));
preset_combobox->addItem(tr("360p"));
preset_combobox->addItem(tr("240p"));
preset_combobox->addItem(tr("144p"));
preset_combobox->addItem(tr("NTSC (480i)"));
preset_combobox->addItem(tr("PAL (576i)"));
preset_combobox->addItem(tr("Custom"));
preset_combobox->setCurrentIndex(2);
preset_layout->addWidget(preset_combobox);
verticalLayout->addWidget(widget);
QGroupBox* videoGroupBox = new QGroupBox(this);
videoGroupBox->setTitle(tr("Video"));
QGridLayout* videoLayout = new QGridLayout(videoGroupBox);
videoLayout->addWidget(new QLabel(tr("Width:"), this), 0, 0, 1, 1);
width_numeric = new QSpinBox(videoGroupBox);
width_numeric->setMaximum(9999);
width_numeric->setValue(olive::config.default_sequence_width);
videoLayout->addWidget(width_numeric, 0, 2, 1, 2);
videoLayout->addWidget(new QLabel(tr("Height:"), this), 1, 0, 1, 2);
height_numeric = new QSpinBox(videoGroupBox);
height_numeric->setMaximum(9999);
height_numeric->setValue(olive::config.default_sequence_height);
videoLayout->addWidget(height_numeric, 1, 2, 1, 2);
videoLayout->addWidget(new QLabel(tr("Frame Rate:"), this), 2, 0, 1, 1);
frame_rate_combobox = new QComboBox(videoGroupBox);
frame_rate_combobox->addItem("10 FPS", 10.0);
frame_rate_combobox->addItem("12.5 FPS", 12.5);
frame_rate_combobox->addItem("15 FPS", 15.0);
frame_rate_combobox->addItem("23.976 FPS", 23.976);
frame_rate_combobox->addItem("24 FPS", 24.0);
frame_rate_combobox->addItem("25 FPS", 25.0);
frame_rate_combobox->addItem("29.97 FPS", 29.97);
frame_rate_combobox->addItem("30 FPS", 30.0);
frame_rate_combobox->addItem("50 FPS", 50.0);
frame_rate_combobox->addItem("59.94 FPS", 59.94);
frame_rate_combobox->addItem("60 FPS", 60.0);
for (int i=0;i<frame_rate_combobox->count();i++) {
if (qFuzzyCompare(frame_rate_combobox->itemData(i).toDouble(), olive::config.default_sequence_framerate)) {
frame_rate_combobox->setCurrentIndex(i);
}
}
videoLayout->addWidget(frame_rate_combobox, 2, 2, 1, 2);
videoLayout->addWidget(new QLabel(tr("Pixel Aspect Ratio:"), this), 4, 0, 1, 1);
par_combobox = new QComboBox(videoGroupBox);
par_combobox->addItem(tr("Square Pixels (1.0)"));
videoLayout->addWidget(par_combobox, 4, 2, 1, 2);
videoLayout->addWidget(new QLabel(tr("Interlacing:"), this), 6, 0, 1, 1);
interlacing_combobox = new QComboBox(videoGroupBox);
interlacing_combobox->addItem(tr("None (Progressive)"));
videoLayout->addWidget(interlacing_combobox, 6, 2, 1, 2);
verticalLayout->addWidget(videoGroupBox);
QGroupBox* audioGroupBox = new QGroupBox(this);
audioGroupBox->setTitle(tr("Audio"));
QGridLayout* audioLayout = new QGridLayout(audioGroupBox);
audioLayout->addWidget(new QLabel(tr("Sample Rate: "), this), 0, 0, 1, 1);
audio_frequency_combobox = new QComboBox(audioGroupBox);
combobox_audio_sample_rates(audio_frequency_combobox);
for (int i=0;i<audio_frequency_combobox->count();i++) {
if (audio_frequency_combobox->itemData(i) == olive::config.default_sequence_audio_frequency) {
audio_frequency_combobox->setCurrentIndex(i);
}
}
audioLayout->addWidget(audio_frequency_combobox, 0, 1, 1, 1);
verticalLayout->addWidget(audioGroupBox);
QWidget* nameWidget = new QWidget(this);
QHBoxLayout* nameLayout = new QHBoxLayout(nameWidget);
nameLayout->setContentsMargins(0, 0, 0, 0);
sequence_name_label = new QLabel(tr("Name:"));
nameLayout->addWidget(sequence_name_label);
sequence_name_edit = new QLineEdit(nameWidget);
nameLayout->addWidget(sequence_name_edit);
verticalLayout->addWidget(nameWidget);
QDialogButtonBox* buttonBox = new QDialogButtonBox(this);
buttonBox->setOrientation(Qt::Horizontal);
buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
buttonBox->setCenterButtons(true);
verticalLayout->addWidget(buttonBox);
connect(preset_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(preset_changed(int)));
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
}
/***
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 "newsequencedialog.h"
#include <QVariant>
#include <QVBoxLayout>
#include <QComboBox>
#include <QGroupBox>
#include <QGridLayout>
#include <QSpinBox>
#include <QLabel>
#include <QLineEdit>
#include <QDialogButtonBox>
#include "panels/panels.h"
#include "panels/project.h"
#include "timeline/sequence.h"
#include "undo/undostack.h"
#include "undo/undo.h"
#include "timeline/clip.h"
#include "panels/timeline.h"
#include "project/media.h"
#include "rendering/audio.h"
#include "global/config.h"
// FIXME: TEST CODE
#include "nodes/nodes/nodemedia.h"
// END TEST CODE
extern "C" {
#include <libavcodec/avcodec.h>
}
NewSequenceDialog::NewSequenceDialog(QWidget *parent, Media *existing, Sequence* iexisting_sequence) :
QDialog(parent),
existing_item(existing),
existing_sequence(iexisting_sequence)
{
Q_ASSERT(!(existing != nullptr && iexisting_sequence != nullptr));
setup_ui();
if (existing != nullptr) {
existing_sequence = existing->to_sequence().get();
}
if (existing_sequence != nullptr) {
setWindowTitle(tr("Editing \"%1\"").arg(existing_sequence->name()));
width_numeric->setValue(existing_sequence->width());
height_numeric->setValue(existing_sequence->height());
int comp_rate = qRound(existing_sequence->frame_rate()*100);
for (int i=0;i<frame_rate_combobox->count();i++) {
if (qRound(frame_rate_combobox->itemData(i).toDouble()*100) == comp_rate) {
frame_rate_combobox->setCurrentIndex(i);
break;
}
}
sequence_name_edit->setText(existing_sequence->name());
for (int i=0;i<audio_frequency_combobox->count();i++) {
if (audio_frequency_combobox->itemData(i) == existing_sequence->audio_frequency()) {
audio_frequency_combobox->setCurrentIndex(i);
break;
}
}
} else {
existing_sequence = nullptr;
setWindowTitle(tr("New Sequence"));
}
}
void NewSequenceDialog::set_sequence_name(const QString& s) {
sequence_name_edit->setText(s);
}
void NewSequenceDialog::SetNameEditable(bool enabled)
{
sequence_name_edit->setVisible(enabled);
sequence_name_label->setVisible(enabled);
}
void NewSequenceDialog::accept() {
if (existing_sequence == nullptr) {
// The dialog wasn't given an existing Sequence object, so we'll make a new one
SequencePtr s = std::make_shared<Sequence>();
s->set_name(sequence_name_edit->text());
s->set_width(width_numeric->value());
s->set_height(height_numeric->value());
s->set_frame_rate(frame_rate_combobox->currentData().toDouble());
s->set_audio_frequency(audio_frequency_combobox->currentData().toInt());
s->set_audio_layout(AV_CH_LAYOUT_STEREO);
ComboAction* ca = new ComboAction();
olive::project_model.CreateSequence(ca, s, true, nullptr);
olive::undo_stack.push(ca);
} else if (existing_item != nullptr) {
// The dialog was given an existing Sequence object, so we'll apply the changes to it
ComboAction* ca = new ComboAction();
double multiplier = frame_rate_combobox->currentData().toDouble() / existing_sequence->frame_rate();
EditSequenceCommand* esc = new EditSequenceCommand(existing_item, existing_item->to_sequence());
esc->name = sequence_name_edit->text();
esc->width = width_numeric->value();
esc->height = height_numeric->value();
esc->frame_rate = frame_rate_combobox->currentData().toDouble();
esc->audio_frequency = audio_frequency_combobox->currentData().toInt();
esc->audio_layout = AV_CH_LAYOUT_STEREO;
ca->append(esc);
QVector<Clip*> existing_sequence_clips = existing_sequence->GetAllClips();
for (int i=0;i<existing_sequence_clips.size();i++) {
existing_sequence_clips.at(i)->refactor_frame_rate(ca, multiplier, true);
}
olive::undo_stack.push(ca);
} else if (existing_sequence != nullptr) {
// This dialog was given an existing Sequence without a Media wrapper - therefore just directly apply the settings
existing_sequence->set_name(sequence_name_edit->text());
existing_sequence->set_width(width_numeric->value());
existing_sequence->set_height(height_numeric->value());
existing_sequence->set_frame_rate(frame_rate_combobox->currentData().toDouble());
existing_sequence->set_audio_frequency(audio_frequency_combobox->currentData().toInt());
existing_sequence->set_audio_layout(AV_CH_LAYOUT_STEREO);
}
QDialog::accept();
}
void NewSequenceDialog::preset_changed(int index) {
switch (index) {
case 0: // FILM 4K
width_numeric->setValue(4096);
height_numeric->setValue(2160);
break;
case 1: // TV 4K
width_numeric->setValue(3840);
height_numeric->setValue(2160);
break;
case 2: // 1080p
width_numeric->setValue(1920);
height_numeric->setValue(1080);
break;
case 3: // 720p
width_numeric->setValue(1280);
height_numeric->setValue(720);
break;
case 4: // 480p
width_numeric->setValue(640);
height_numeric->setValue(480);
break;
case 5: // 360p
width_numeric->setValue(640);
height_numeric->setValue(360);
break;
case 6: // 240p
width_numeric->setValue(320);
height_numeric->setValue(240);
break;
case 7: // 144p
width_numeric->setValue(192);
height_numeric->setValue(144);
break;
case 8: // NTSC (480i)
width_numeric->setValue(720);
height_numeric->setValue(480);
break;
case 9: // PAL (576i)
width_numeric->setValue(720);
height_numeric->setValue(576);
break;
}
}
void NewSequenceDialog::setup_ui() {
QVBoxLayout* verticalLayout = new QVBoxLayout(this);
QWidget* widget = new QWidget(this);
QHBoxLayout* preset_layout = new QHBoxLayout(widget);
preset_layout->setContentsMargins(0, 0, 0, 0);
preset_layout->addWidget(new QLabel(tr("Preset:"), this));
preset_combobox = new QComboBox(widget);
preset_combobox->addItem(tr("Film 4K"));
preset_combobox->addItem(tr("TV 4K (Ultra HD/2160p)"));
preset_combobox->addItem(tr("1080p"));
preset_combobox->addItem(tr("720p"));
preset_combobox->addItem(tr("480p"));
preset_combobox->addItem(tr("360p"));
preset_combobox->addItem(tr("240p"));
preset_combobox->addItem(tr("144p"));
preset_combobox->addItem(tr("NTSC (480i)"));
preset_combobox->addItem(tr("PAL (576i)"));
preset_combobox->addItem(tr("Custom"));
preset_combobox->setCurrentIndex(2);
preset_layout->addWidget(preset_combobox);
verticalLayout->addWidget(widget);
QGroupBox* videoGroupBox = new QGroupBox(this);
videoGroupBox->setTitle(tr("Video"));
QGridLayout* videoLayout = new QGridLayout(videoGroupBox);
videoLayout->addWidget(new QLabel(tr("Width:"), this), 0, 0, 1, 1);
width_numeric = new QSpinBox(videoGroupBox);
width_numeric->setMaximum(9999);
width_numeric->setValue(olive::config.default_sequence_width);
videoLayout->addWidget(width_numeric, 0, 2, 1, 2);
videoLayout->addWidget(new QLabel(tr("Height:"), this), 1, 0, 1, 2);
height_numeric = new QSpinBox(videoGroupBox);
height_numeric->setMaximum(9999);
height_numeric->setValue(olive::config.default_sequence_height);
videoLayout->addWidget(height_numeric, 1, 2, 1, 2);
videoLayout->addWidget(new QLabel(tr("Frame Rate:"), this), 2, 0, 1, 1);
frame_rate_combobox = new QComboBox(videoGroupBox);
frame_rate_combobox->addItem("10 FPS", 10.0);
frame_rate_combobox->addItem("12.5 FPS", 12.5);
frame_rate_combobox->addItem("15 FPS", 15.0);
frame_rate_combobox->addItem("23.976 FPS", 23.976);
frame_rate_combobox->addItem("24 FPS", 24.0);
frame_rate_combobox->addItem("25 FPS", 25.0);
frame_rate_combobox->addItem("29.97 FPS", 29.97);
frame_rate_combobox->addItem("30 FPS", 30.0);
frame_rate_combobox->addItem("50 FPS", 50.0);
frame_rate_combobox->addItem("59.94 FPS", 59.94);
frame_rate_combobox->addItem("60 FPS", 60.0);
for (int i=0;i<frame_rate_combobox->count();i++) {
if (qFuzzyCompare(frame_rate_combobox->itemData(i).toDouble(), olive::config.default_sequence_framerate)) {
frame_rate_combobox->setCurrentIndex(i);
}
}
videoLayout->addWidget(frame_rate_combobox, 2, 2, 1, 2);
videoLayout->addWidget(new QLabel(tr("Pixel Aspect Ratio:"), this), 4, 0, 1, 1);
par_combobox = new QComboBox(videoGroupBox);
par_combobox->addItem(tr("Square Pixels (1.0)"));
videoLayout->addWidget(par_combobox, 4, 2, 1, 2);
videoLayout->addWidget(new QLabel(tr("Interlacing:"), this), 6, 0, 1, 1);
interlacing_combobox = new QComboBox(videoGroupBox);
interlacing_combobox->addItem(tr("None (Progressive)"));
videoLayout->addWidget(interlacing_combobox, 6, 2, 1, 2);
verticalLayout->addWidget(videoGroupBox);
QGroupBox* audioGroupBox = new QGroupBox(this);
audioGroupBox->setTitle(tr("Audio"));
QGridLayout* audioLayout = new QGridLayout(audioGroupBox);
audioLayout->addWidget(new QLabel(tr("Sample Rate: "), this), 0, 0, 1, 1);
audio_frequency_combobox = new QComboBox(audioGroupBox);
combobox_audio_sample_rates(audio_frequency_combobox);
for (int i=0;i<audio_frequency_combobox->count();i++) {
if (audio_frequency_combobox->itemData(i) == olive::config.default_sequence_audio_frequency) {
audio_frequency_combobox->setCurrentIndex(i);
}
}
audioLayout->addWidget(audio_frequency_combobox, 0, 1, 1, 1);
verticalLayout->addWidget(audioGroupBox);
QWidget* nameWidget = new QWidget(this);
QHBoxLayout* nameLayout = new QHBoxLayout(nameWidget);
nameLayout->setContentsMargins(0, 0, 0, 0);
sequence_name_label = new QLabel(tr("Name:"));
nameLayout->addWidget(sequence_name_label);
sequence_name_edit = new QLineEdit(nameWidget);
nameLayout->addWidget(sequence_name_edit);
verticalLayout->addWidget(nameWidget);
QDialogButtonBox* buttonBox = new QDialogButtonBox(this);
buttonBox->setOrientation(Qt::Horizontal);
buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
buttonBox->setCenterButtons(true);
verticalLayout->addWidget(buttonBox);
connect(preset_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(preset_changed(int)));
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
}
+168 -168
View File
@@ -1,168 +1,168 @@
/***
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 NEWSEQUENCEDIALOG_H
#define NEWSEQUENCEDIALOG_H
#include <QDialog>
#include <QComboBox>
#include <QSpinBox>
#include <QLineEdit>
#include "panels/project.h"
#include "project/media.h"
#include "timeline/sequence.h"
/**
* @brief The NewSequenceDialog class
*
* A dialog that creates a new (or edits an existing) Sequence object. Can be run from any part of the application.
*/
class NewSequenceDialog : public QDialog
{
Q_OBJECT
public:
/**
* @brief NewSequenceDialog constructor
*
* @param parent
*
* QWidget parent. Usually MainWindow.
*
* @param existing
*
* Set this to a Sequence object (wrapped in a Media object) to edit an existing Sequence,
* or leave as nullptr to create a new one.
*
* @param existing_sequence
*
* If your Sequence object is not wrapped in a Media object, use this to reference a raw Sequence pointer. You must
* not use both existing_sequence AND existing - one must be nullptr.
*/
explicit NewSequenceDialog(QWidget *parent = nullptr, Media* existing = nullptr, Sequence* iexisting_sequence = nullptr);
/**
* @brief Set the name for the new Sequence
*
* If creating a new Sequence, use this function before calling exec() to set what the new Sequence's
* name will be.
*
* The primary use of this is to set a unique default name (i.e. one that doesn't exist
* in the Sequence already) which is done by Project panel. This is usually "Sequence" followed by a number.
*
* @param s
*
* The name to set the new Sequence.
*/
void set_sequence_name(const QString& s);
/**
* @brief Set whether the Sequence's name can be edited
*
* This defaults to TRUE.
*
* @param enabled
*
* TRUE to allow the user to edit the Sequence's name. FALSE if not.
*/
void SetNameEditable(bool enabled);
private slots:
/**
* @brief Override accept function to create/edit a Sequence
*/
virtual void accept() override;
/**
* @brief Slot when the user changes the preset
*
* Sets all values according to the preset chosen.
*
* @param index
*
* Currently selected index of preset_combobox;
*/
void preset_changed(int index);
private:
/**
* @brief Internal reference to an existing Media wrapper (if one was provided to the constructor)
*/
Media* existing_item;
/**
* @brief Internal reference to an existing Sequence (if one was provided to the constructor)
*/
Sequence* existing_sequence;
/**
* @brief Internal function to create the dialog's UI
*/
void setup_ui();
/**
* @brief ComboBox to set the preset
*/
QComboBox* preset_combobox;
/**
* @brief SpinBox to set the Sequence height
*/
QSpinBox* height_numeric;
/**
* @brief SpinBox to set the Sequence width
*/
QSpinBox* width_numeric;
/**
* @brief ComboBox to set the pixel aspect ratio
*/
QComboBox* par_combobox;
/**
* @brief ComboBox to set the interlacing mode
*/
QComboBox* interlacing_combobox;
/**
* @brief ComboBox to set the frame rate
*/
QComboBox* frame_rate_combobox;
/**
* @brief ComboBox to set the audio frequence
*/
QComboBox* audio_frequency_combobox;
/**
* @brief Label marker for setting the Sequence's name
*
* Primarily a persistent class reference so it can be hidden with SetNameEditable() alongside sequence_name_edit.
*/
QLabel* sequence_name_label;
/**
* @brief Line edit to set the Sequence's name
*/
QLineEdit* sequence_name_edit;
};
#endif // NEWSEQUENCEDIALOG_H
/***
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 NEWSEQUENCEDIALOG_H
#define NEWSEQUENCEDIALOG_H
#include <QDialog>
#include <QComboBox>
#include <QSpinBox>
#include <QLineEdit>
#include "panels/project.h"
#include "project/media.h"
#include "timeline/sequence.h"
/**
* @brief The NewSequenceDialog class
*
* A dialog that creates a new (or edits an existing) Sequence object. Can be run from any part of the application.
*/
class NewSequenceDialog : public QDialog
{
Q_OBJECT
public:
/**
* @brief NewSequenceDialog constructor
*
* @param parent
*
* QWidget parent. Usually MainWindow.
*
* @param existing
*
* Set this to a Sequence object (wrapped in a Media object) to edit an existing Sequence,
* or leave as nullptr to create a new one.
*
* @param existing_sequence
*
* If your Sequence object is not wrapped in a Media object, use this to reference a raw Sequence pointer. You must
* not use both existing_sequence AND existing - one must be nullptr.
*/
explicit NewSequenceDialog(QWidget *parent = nullptr, Media* existing = nullptr, Sequence* iexisting_sequence = nullptr);
/**
* @brief Set the name for the new Sequence
*
* If creating a new Sequence, use this function before calling exec() to set what the new Sequence's
* name will be.
*
* The primary use of this is to set a unique default name (i.e. one that doesn't exist
* in the Sequence already) which is done by Project panel. This is usually "Sequence" followed by a number.
*
* @param s
*
* The name to set the new Sequence.
*/
void set_sequence_name(const QString& s);
/**
* @brief Set whether the Sequence's name can be edited
*
* This defaults to TRUE.
*
* @param enabled
*
* TRUE to allow the user to edit the Sequence's name. FALSE if not.
*/
void SetNameEditable(bool enabled);
private slots:
/**
* @brief Override accept function to create/edit a Sequence
*/
virtual void accept() override;
/**
* @brief Slot when the user changes the preset
*
* Sets all values according to the preset chosen.
*
* @param index
*
* Currently selected index of preset_combobox;
*/
void preset_changed(int index);
private:
/**
* @brief Internal reference to an existing Media wrapper (if one was provided to the constructor)
*/
Media* existing_item;
/**
* @brief Internal reference to an existing Sequence (if one was provided to the constructor)
*/
Sequence* existing_sequence;
/**
* @brief Internal function to create the dialog's UI
*/
void setup_ui();
/**
* @brief ComboBox to set the preset
*/
QComboBox* preset_combobox;
/**
* @brief SpinBox to set the Sequence height
*/
QSpinBox* height_numeric;
/**
* @brief SpinBox to set the Sequence width
*/
QSpinBox* width_numeric;
/**
* @brief ComboBox to set the pixel aspect ratio
*/
QComboBox* par_combobox;
/**
* @brief ComboBox to set the interlacing mode
*/
QComboBox* interlacing_combobox;
/**
* @brief ComboBox to set the frame rate
*/
QComboBox* frame_rate_combobox;
/**
* @brief ComboBox to set the audio frequence
*/
QComboBox* audio_frequency_combobox;
/**
* @brief Label marker for setting the Sequence's name
*
* Primarily a persistent class reference so it can be hidden with SetNameEditable() alongside sequence_name_edit.
*/
QLabel* sequence_name_label;
/**
* @brief Line edit to set the Sequence's name
*/
QLineEdit* sequence_name_edit;
};
#endif // NEWSEQUENCEDIALOG_H
+184 -184
View File
@@ -1,184 +1,184 @@
/***
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 "proxydialog.h"
#include <QGridLayout>
#include <QLabel>
#include <QDialogButtonBox>
#include <QComboBox>
#include <QFileDialog>
#include <QMessageBox>
#include <QDebug>
#include "project/proxygenerator.h"
#include "project/footage.h"
#include "ui/mainwindow.h"
#include "global/global.h"
ProxyDialog::ProxyDialog(QWidget *parent, const QVector<Media*> &media) :
QDialog(parent),
selected_media(media)
{
// set dialog title
setWindowTitle(tr("Create Proxy"));
// set proxy folder name to "Proxy", depending on the user's language
proxy_folder_name = tr("Proxy");
// set up dialog's layout
QGridLayout* layout = new QGridLayout(this);
// set the video dimensions of the proxy
layout->addWidget(new QLabel(tr("Dimensions:"), this), 0, 0);
size_combobox = new QComboBox(this);
size_combobox->addItem(tr("Same Size as Source"), 1.0);
size_combobox->addItem(tr("Half Resolution (1/2)"), 0.5);
size_combobox->addItem(tr("Quarter Resolution (1/4)"), 0.25);
size_combobox->addItem(tr("Eighth Resolution (1/8)"), 0.125);
size_combobox->addItem(tr("Sixteenth Resolution (1/16)"), 0.0625);
layout->addWidget(size_combobox, 0, 1);
// set the desired format of the proxy to create
layout->addWidget(new QLabel(tr("Format:"), this), 1, 0);
format_combobox = new QComboBox(this);
format_combobox->addItem(tr("ProRes HQ"));
// format_combobox->addItem(tr("ProRes SQ"));
// format_combobox->addItem(tr("ProRes LT"));
// format_combobox->addItem(tr("DNxHD"));
// format_combobox->addItem(tr("H.264"));
layout->addWidget(format_combobox, 1, 1);
// set the location to place the proxies
layout->addWidget(new QLabel(tr("Location:"), this), 2, 0);
location_combobox = new QComboBox(this);
location_combobox->addItem(tr("Same as Source (in \"%1\" folder)").arg(proxy_folder_name));
location_combobox->addItem("");
connect(location_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(location_changed(int)));
layout->addWidget(location_combobox, 2, 1);
// location_changed will set the default "location" items
location_changed(0);
// set up dialog buttons
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
buttons->setCenterButtons(true);
layout->addWidget(buttons, 3, 0, 1, 2);
connect(buttons, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttons, SIGNAL(rejected()), this, SLOT(reject()));
}
void ProxyDialog::accept() {
QVector<ProxyInfo> info_list;
// set to TRUE if any existing proxies exist and the user chooses to overwrite all of them
bool overwrite_all_existing = false;
for (int i=0;i<selected_media.size();i++) {
// loop through selected footage and send info to the proxy queue
ProxyInfo info;
// fill info struct based on user input
info.media = selected_media.at(i);
info.codec_type = 0;
info.size_multiplier = size_combobox->currentData().toDouble();
Footage* footage = selected_media.at(i)->to_footage();
QString base_footage_fn = QFileInfo(footage->url).baseName();
// TEMPORARILY hardcoded proxy format
base_footage_fn.append(".mov");
// determine path from input
if (custom_location.isEmpty()) {
// use same as source (proxy subfolder)
// generate full path from footage path and proxy_folder_name's translated "Proxy"
info.path = QDir(QFileInfo(footage->url).dir().filePath(proxy_folder_name)).filePath(base_footage_fn);
} else {
// use existing location
info.path = QDir(custom_location).filePath(base_footage_fn);
}
// if the proposed proxy file already exists & user didn't select YesToAll box
if (QFileInfo::exists(info.path) && !overwrite_all_existing){
int rtn = QMessageBox::warning( this,
tr("Proxy file exists"),
tr("The file \"%1\" already exists. Do you wish to replace it?").arg(info.path),
QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::No);
switch (rtn){
case QMessageBox::Yes:
// continue as normal, proxy generator will automatically overwrite this file
break;
case QMessageBox::YesToAll:
// continue as normal, also set variable so that above messagebox is not shown again
overwrite_all_existing = true;
break;
case QMessageBox::No:
// return to dialog without closing or starting any proxy generation
return;
}
}
// send to proxy generator thread
info_list.append(info);
}
// all proxy info checks out, queue it with the proxy generator
for (int i=0;i<info_list.size();i++) {
Footage* footage = info_list.at(i).media->to_footage();
footage->proxy = true;
footage->proxy_path.clear();
olive::proxy_generator.queue(info_list.at(i));
}
olive::Global->set_modified(true);
QDialog::accept();
}
void ProxyDialog::location_changed(int i) {
// clear any custom location - either the user picked a new one or chose not a custom location
custom_location.clear();
if (i == 1) {
// if the user picked a custom location, ask which directory
QString s = QFileDialog::getExistingDirectory(this);
if (s.isEmpty()) {
// if the user didn't input anything, set the combobox back to default
location_combobox->setCurrentIndex(0);
} else {
// if the user chose a custom location, set the combobox text to it and custom_location for future usage
location_combobox->setItemText(1, s);
custom_location = s;
}
} else {
// if the user doesn't picks something other than custom location, set this string back to default for clearer UX
location_combobox->setItemText(1, tr("Custom Location"));
}
}
/***
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 "proxydialog.h"
#include <QGridLayout>
#include <QLabel>
#include <QDialogButtonBox>
#include <QComboBox>
#include <QFileDialog>
#include <QMessageBox>
#include <QDebug>
#include "project/proxygenerator.h"
#include "project/footage.h"
#include "ui/mainwindow.h"
#include "global/global.h"
ProxyDialog::ProxyDialog(QWidget *parent, const QVector<Media*> &media) :
QDialog(parent),
selected_media(media)
{
// set dialog title
setWindowTitle(tr("Create Proxy"));
// set proxy folder name to "Proxy", depending on the user's language
proxy_folder_name = tr("Proxy");
// set up dialog's layout
QGridLayout* layout = new QGridLayout(this);
// set the video dimensions of the proxy
layout->addWidget(new QLabel(tr("Dimensions:"), this), 0, 0);
size_combobox = new QComboBox(this);
size_combobox->addItem(tr("Same Size as Source"), 1.0);
size_combobox->addItem(tr("Half Resolution (1/2)"), 0.5);
size_combobox->addItem(tr("Quarter Resolution (1/4)"), 0.25);
size_combobox->addItem(tr("Eighth Resolution (1/8)"), 0.125);
size_combobox->addItem(tr("Sixteenth Resolution (1/16)"), 0.0625);
layout->addWidget(size_combobox, 0, 1);
// set the desired format of the proxy to create
layout->addWidget(new QLabel(tr("Format:"), this), 1, 0);
format_combobox = new QComboBox(this);
format_combobox->addItem(tr("ProRes HQ"));
// format_combobox->addItem(tr("ProRes SQ"));
// format_combobox->addItem(tr("ProRes LT"));
// format_combobox->addItem(tr("DNxHD"));
// format_combobox->addItem(tr("H.264"));
layout->addWidget(format_combobox, 1, 1);
// set the location to place the proxies
layout->addWidget(new QLabel(tr("Location:"), this), 2, 0);
location_combobox = new QComboBox(this);
location_combobox->addItem(tr("Same as Source (in \"%1\" folder)").arg(proxy_folder_name));
location_combobox->addItem("");
connect(location_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(location_changed(int)));
layout->addWidget(location_combobox, 2, 1);
// location_changed will set the default "location" items
location_changed(0);
// set up dialog buttons
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
buttons->setCenterButtons(true);
layout->addWidget(buttons, 3, 0, 1, 2);
connect(buttons, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttons, SIGNAL(rejected()), this, SLOT(reject()));
}
void ProxyDialog::accept() {
QVector<ProxyInfo> info_list;
// set to TRUE if any existing proxies exist and the user chooses to overwrite all of them
bool overwrite_all_existing = false;
for (int i=0;i<selected_media.size();i++) {
// loop through selected footage and send info to the proxy queue
ProxyInfo info;
// fill info struct based on user input
info.media = selected_media.at(i);
info.codec_type = 0;
info.size_multiplier = size_combobox->currentData().toDouble();
Footage* footage = selected_media.at(i)->to_footage();
QString base_footage_fn = QFileInfo(footage->url).baseName();
// TEMPORARILY hardcoded proxy format
base_footage_fn.append(".mov");
// determine path from input
if (custom_location.isEmpty()) {
// use same as source (proxy subfolder)
// generate full path from footage path and proxy_folder_name's translated "Proxy"
info.path = QDir(QFileInfo(footage->url).dir().filePath(proxy_folder_name)).filePath(base_footage_fn);
} else {
// use existing location
info.path = QDir(custom_location).filePath(base_footage_fn);
}
// if the proposed proxy file already exists & user didn't select YesToAll box
if (QFileInfo::exists(info.path) && !overwrite_all_existing){
int rtn = QMessageBox::warning( this,
tr("Proxy file exists"),
tr("The file \"%1\" already exists. Do you wish to replace it?").arg(info.path),
QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::No);
switch (rtn){
case QMessageBox::Yes:
// continue as normal, proxy generator will automatically overwrite this file
break;
case QMessageBox::YesToAll:
// continue as normal, also set variable so that above messagebox is not shown again
overwrite_all_existing = true;
break;
case QMessageBox::No:
// return to dialog without closing or starting any proxy generation
return;
}
}
// send to proxy generator thread
info_list.append(info);
}
// all proxy info checks out, queue it with the proxy generator
for (int i=0;i<info_list.size();i++) {
Footage* footage = info_list.at(i).media->to_footage();
footage->proxy = true;
footage->proxy_path.clear();
olive::proxy_generator.queue(info_list.at(i));
}
olive::Global->set_modified(true);
QDialog::accept();
}
void ProxyDialog::location_changed(int i) {
// clear any custom location - either the user picked a new one or chose not a custom location
custom_location.clear();
if (i == 1) {
// if the user picked a custom location, ask which directory
QString s = QFileDialog::getExistingDirectory(this);
if (s.isEmpty()) {
// if the user didn't input anything, set the combobox back to default
location_combobox->setCurrentIndex(0);
} else {
// if the user chose a custom location, set the combobox text to it and custom_location for future usage
location_combobox->setItemText(1, s);
custom_location = s;
}
} else {
// if the user doesn't picks something other than custom location, set this string back to default for clearer UX
location_combobox->setItemText(1, tr("Custom Location"));
}
}
+107 -107
View File
@@ -1,107 +1,107 @@
/***
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 PROXYDIALOG_H
#define PROXYDIALOG_H
#include <QDialog>
#include <QVector>
#include <QComboBox>
#include "project/media.h"
/**
* @brief The ProxyDialog class
*
* Dialog to set up proxy generation of footage. This dialog can be called from anywhere provided it's given a valid
* array of Media and will start all proxy generation.
*/
class ProxyDialog : public QDialog {
Q_OBJECT
public:
/**
* @brief ProxyDialog Constructor
* @param parent
*
* Parent widget to become modal to.
*
* @param footage
*
* List of Footage items to process.
*/
ProxyDialog(QWidget* parent, const QVector<Media *> &media);
public slots:
/**
* @brief Accept changes
*
* Called when the user clicks OK on the dialog. Verifies all proxies, asking the user whether they want to overwrite
* existing proxies if necessary, and if everything is valid, queues the footage with ProxyGenerator.
*/
virtual void accept() override;
private:
/**
* @brief User's desired dimensions
*
* Always a fraction of the original video size (e.g. 1/2, 1/4, 1/8, etc.)
*/
QComboBox* size_combobox;
/**
* @brief User's desired proxy format
*
* e.g. ProRes, DNxHD, etc.
*/
QComboBox* format_combobox;
/**
* @brief Allows users to set the directory to store proxies in
*/
QComboBox* location_combobox;
/**
* @brief Stores the custom location to store proxies if the user sets a custom location
*/
QString custom_location;
/**
* @brief Stores the default subdirectory to be made next to the source (dependent on the user's language)
*
* "Proxy" in en-US.
*/
QString proxy_folder_name;
/**
* @brief Stored list of footage to make proxies for
*/
QVector<Media*> selected_media;
private slots:
/**
* @brief Slot when the user changes the location
*
* Triggered when the user changes the index in the location combobox.
*
* @param i
*
* location_combobox's new selected index
*/
void location_changed(int i);
};
#endif // PROXYDIALOG_H
/***
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 PROXYDIALOG_H
#define PROXYDIALOG_H
#include <QDialog>
#include <QVector>
#include <QComboBox>
#include "project/media.h"
/**
* @brief The ProxyDialog class
*
* Dialog to set up proxy generation of footage. This dialog can be called from anywhere provided it's given a valid
* array of Media and will start all proxy generation.
*/
class ProxyDialog : public QDialog {
Q_OBJECT
public:
/**
* @brief ProxyDialog Constructor
* @param parent
*
* Parent widget to become modal to.
*
* @param footage
*
* List of Footage items to process.
*/
ProxyDialog(QWidget* parent, const QVector<Media *> &media);
public slots:
/**
* @brief Accept changes
*
* Called when the user clicks OK on the dialog. Verifies all proxies, asking the user whether they want to overwrite
* existing proxies if necessary, and if everything is valid, queues the footage with ProxyGenerator.
*/
virtual void accept() override;
private:
/**
* @brief User's desired dimensions
*
* Always a fraction of the original video size (e.g. 1/2, 1/4, 1/8, etc.)
*/
QComboBox* size_combobox;
/**
* @brief User's desired proxy format
*
* e.g. ProRes, DNxHD, etc.
*/
QComboBox* format_combobox;
/**
* @brief Allows users to set the directory to store proxies in
*/
QComboBox* location_combobox;
/**
* @brief Stores the custom location to store proxies if the user sets a custom location
*/
QString custom_location;
/**
* @brief Stores the default subdirectory to be made next to the source (dependent on the user's language)
*
* "Proxy" in en-US.
*/
QString proxy_folder_name;
/**
* @brief Stored list of footage to make proxies for
*/
QVector<Media*> selected_media;
private slots:
/**
* @brief Slot when the user changes the location
*
* Triggered when the user changes the index in the location combobox.
*
* @param i
*
* location_combobox's new selected index
*/
void location_changed(int i);
};
#endif // PROXYDIALOG_H
+130 -130
View File
@@ -1,130 +1,130 @@
/***
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 "replaceclipmediadialog.h"
#include <QVBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QMessageBox>
#include "panels/panels.h"
#include "undo/undostack.h"
#include "rendering/cacher.h"
#include "undo/undo.h"
ReplaceClipMediaDialog::ReplaceClipMediaDialog(QWidget *parent, Media* old_media) :
QDialog(parent),
media(old_media)
{
setWindowTitle(tr("Replace clips using \"%1\"").arg(old_media->get_name()));
resize(300, 400);
QVBoxLayout* layout = new QVBoxLayout(this);
layout->addWidget(new QLabel(tr("Select which media you want to replace this media's clips with:"), this));
tree = new QTreeView(this);
layout->addWidget(tree);
use_same_media_in_points = new QCheckBox(tr("Keep the same media in-points"), this);
use_same_media_in_points->setChecked(true);
layout->addWidget(use_same_media_in_points);
QHBoxLayout* buttons = new QHBoxLayout();
buttons->addStretch();
QPushButton* replace_button = new QPushButton(tr("Replace"), this);
connect(replace_button, SIGNAL(clicked(bool)), this, SLOT(accept()));
buttons->addWidget(replace_button);
QPushButton* cancel_button = new QPushButton(tr("Cancel"), this);
connect(cancel_button, SIGNAL(clicked(bool)), this, SLOT(reject()));
buttons->addWidget(cancel_button);
buttons->addStretch();
layout->addLayout(buttons);
tree->setModel(&olive::project_model);
}
void ReplaceClipMediaDialog::accept() {
QModelIndexList selected_items = tree->selectionModel()->selectedRows();
if (selected_items.size() != 1) {
QMessageBox::critical(
this,
tr("No media selected"),
tr("Please select a media to replace with or click 'Cancel'."),
QMessageBox::Ok
);
} else {
Media* new_item = static_cast<Media*>(selected_items.at(0).internalPointer());
if (media == new_item) {
QMessageBox::critical(
this,
tr("Same media selected"),
tr("You selected the same media that you're replacing. Please select a different one or click 'Cancel'."),
QMessageBox::Ok
);
} else if (new_item->get_type() == MEDIA_TYPE_FOLDER) {
QMessageBox::critical(
this,
tr("Folder selected"),
tr("You cannot replace footage with a folder."),
QMessageBox::Ok
);
} else {
SequencePtr top_sequence = Timeline::GetTopSequence();
if (new_item->get_type() == MEDIA_TYPE_SEQUENCE && top_sequence == new_item->to_sequence()) {
QMessageBox::critical(
this,
tr("Active sequence selected"),
tr("You cannot insert a sequence into itself."),
QMessageBox::Ok
);
} else {
ReplaceClipMediaCommand* rcmc = new ReplaceClipMediaCommand(
media,
new_item,
use_same_media_in_points->isChecked()
);
QVector<Clip*> all_clips = top_sequence->GetAllClips();
for (int i=0;i<all_clips.size();i++) {
Clip* c = all_clips.at(i);
if (c->media() == media) {
rcmc->clips.append(c);
}
}
olive::undo_stack.push(rcmc);
QDialog::accept();
}
}
}
}
/***
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 "replaceclipmediadialog.h"
#include <QVBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QMessageBox>
#include "panels/panels.h"
#include "undo/undostack.h"
#include "rendering/cacher.h"
#include "undo/undo.h"
ReplaceClipMediaDialog::ReplaceClipMediaDialog(QWidget *parent, Media* old_media) :
QDialog(parent),
media(old_media)
{
setWindowTitle(tr("Replace clips using \"%1\"").arg(old_media->get_name()));
resize(300, 400);
QVBoxLayout* layout = new QVBoxLayout(this);
layout->addWidget(new QLabel(tr("Select which media you want to replace this media's clips with:"), this));
tree = new QTreeView(this);
layout->addWidget(tree);
use_same_media_in_points = new QCheckBox(tr("Keep the same media in-points"), this);
use_same_media_in_points->setChecked(true);
layout->addWidget(use_same_media_in_points);
QHBoxLayout* buttons = new QHBoxLayout();
buttons->addStretch();
QPushButton* replace_button = new QPushButton(tr("Replace"), this);
connect(replace_button, SIGNAL(clicked(bool)), this, SLOT(accept()));
buttons->addWidget(replace_button);
QPushButton* cancel_button = new QPushButton(tr("Cancel"), this);
connect(cancel_button, SIGNAL(clicked(bool)), this, SLOT(reject()));
buttons->addWidget(cancel_button);
buttons->addStretch();
layout->addLayout(buttons);
tree->setModel(&olive::project_model);
}
void ReplaceClipMediaDialog::accept() {
QModelIndexList selected_items = tree->selectionModel()->selectedRows();
if (selected_items.size() != 1) {
QMessageBox::critical(
this,
tr("No media selected"),
tr("Please select a media to replace with or click 'Cancel'."),
QMessageBox::Ok
);
} else {
Media* new_item = static_cast<Media*>(selected_items.at(0).internalPointer());
if (media == new_item) {
QMessageBox::critical(
this,
tr("Same media selected"),
tr("You selected the same media that you're replacing. Please select a different one or click 'Cancel'."),
QMessageBox::Ok
);
} else if (new_item->get_type() == MEDIA_TYPE_FOLDER) {
QMessageBox::critical(
this,
tr("Folder selected"),
tr("You cannot replace footage with a folder."),
QMessageBox::Ok
);
} else {
SequencePtr top_sequence = Timeline::GetTopSequence();
if (new_item->get_type() == MEDIA_TYPE_SEQUENCE && top_sequence == new_item->to_sequence()) {
QMessageBox::critical(
this,
tr("Active sequence selected"),
tr("You cannot insert a sequence into itself."),
QMessageBox::Ok
);
} else {
ReplaceClipMediaCommand* rcmc = new ReplaceClipMediaCommand(
media,
new_item,
use_same_media_in_points->isChecked()
);
QVector<Clip*> all_clips = top_sequence->GetAllClips();
for (int i=0;i<all_clips.size();i++) {
Clip* c = all_clips.at(i);
if (c->media() == media) {
rcmc->clips.append(c);
}
}
olive::undo_stack.push(rcmc);
QDialog::accept();
}
}
}
}
+82 -82
View File
@@ -1,82 +1,82 @@
/***
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 REPLACECLIPMEDIADIALOG_H
#define REPLACECLIPMEDIADIALOG_H
#include <QDialog>
#include <QTreeView>
#include <QCheckBox>
#include "ui/sourcetable.h"
#include "project/projectelements.h"
/**
* @brief The ReplaceClipMediaDialog class
*
* A dialog to replace all Clips using a certain Media with a different Media. This dialog can be run from anywhere
* provided it's given a valid Media object.
*/
class ReplaceClipMediaDialog : public QDialog {
Q_OBJECT
public:
/**
* @brief ReplaceClipMediaDialog Constructor
*
* @param parent
*
* QWidget parent. Usually MainWindow or Project panel.
*
* @param old_media
*
* A valid Media object which will be used to scan the currently active Sequence for Clips using it.
*/
ReplaceClipMediaDialog(QWidget* parent, Media* old_media);
private slots:
/**
* @brief Overridden accept for when the user clicks "Replace"
*
* Checks whether the requested replace is valid using the following criteria:
* * Any Media is selected
* * The selected Media is not the same Media that the user is trying to replace
* * The Media is not a folder
* * The Media is not the currently active Sequence
*/
virtual void accept() override;
private:
/**
* @brief Internal pointer to the Media we're replacing
*/
Media* media;
/**
* @brief Tree widget to show Project's media
*/
QTreeView* tree;
/**
* @brief CheckBox for using the same media in points
*
* When the starting point of a Clip is trimmed (i.e. the Clip no longer starts at 0),
*/
QCheckBox* use_same_media_in_points;
};
#endif // REPLACECLIPMEDIADIALOG_H
/***
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 REPLACECLIPMEDIADIALOG_H
#define REPLACECLIPMEDIADIALOG_H
#include <QDialog>
#include <QTreeView>
#include <QCheckBox>
#include "ui/sourcetable.h"
#include "project/projectelements.h"
/**
* @brief The ReplaceClipMediaDialog class
*
* A dialog to replace all Clips using a certain Media with a different Media. This dialog can be run from anywhere
* provided it's given a valid Media object.
*/
class ReplaceClipMediaDialog : public QDialog {
Q_OBJECT
public:
/**
* @brief ReplaceClipMediaDialog Constructor
*
* @param parent
*
* QWidget parent. Usually MainWindow or Project panel.
*
* @param old_media
*
* A valid Media object which will be used to scan the currently active Sequence for Clips using it.
*/
ReplaceClipMediaDialog(QWidget* parent, Media* old_media);
private slots:
/**
* @brief Overridden accept for when the user clicks "Replace"
*
* Checks whether the requested replace is valid using the following criteria:
* * Any Media is selected
* * The selected Media is not the same Media that the user is trying to replace
* * The Media is not a folder
* * The Media is not the currently active Sequence
*/
virtual void accept() override;
private:
/**
* @brief Internal pointer to the Media we're replacing
*/
Media* media;
/**
* @brief Tree widget to show Project's media
*/
QTreeView* tree;
/**
* @brief CheckBox for using the same media in points
*
* When the starting point of a Clip is trimmed (i.e. the Clip no longer starts at 0),
*/
QCheckBox* use_same_media_in_points;
};
#endif // REPLACECLIPMEDIADIALOG_H
+461 -461
View File
@@ -1,461 +1,461 @@
/***
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 "speeddialog.h"
#include <QHBoxLayout>
#include <QGridLayout>
#include <QLabel>
#include <QPushButton>
#include <QDialogButtonBox>
#include "timeline/sequence.h"
#include "project/footage.h"
#include "rendering/renderfunctions.h"
#include "panels/panels.h"
#include "panels/timeline.h"
#include "undo/undo.h"
#include "undo/undostack.h"
#include "nodes/oldeffectnode.h"
#include "project/media.h"
SpeedDialog::SpeedDialog(QWidget *parent, QVector<Clip*> clips) : QDialog(parent) {
setWindowTitle(tr("Speed/Duration"));
clips_ = clips;
QVBoxLayout* main_layout = new QVBoxLayout(this);
QGridLayout* grid = new QGridLayout();
grid->setSpacing(6);
grid->addWidget(new QLabel(tr("Speed:"), this), 0, 0);
percent = new LabelSlider(this);
percent->SetDecimalPlaces(2);
percent->SetDisplayType(LabelSlider::Percent);
percent->SetDefault(1);
grid->addWidget(percent, 0, 1);
grid->addWidget(new QLabel(tr("Frame Rate:"), this), 1, 0);
frame_rate = new LabelSlider(this);
frame_rate->SetDecimalPlaces(3);
grid->addWidget(frame_rate, 1, 1);
grid->addWidget(new QLabel(tr("Duration:"), this), 2, 0);
duration = new LabelSlider(this);
duration->SetDisplayType(LabelSlider::FrameNumber);
duration->SetFrameRate(clips_.first()->track()->sequence()->frame_rate());
grid->addWidget(duration, 2, 1);
main_layout->addLayout(grid);
reverse = new QCheckBox(tr("Reverse"), this);
maintain_pitch = new QCheckBox(tr("Maintain Audio Pitch"), this);
ripple = new QCheckBox(tr("Ripple Changes"), this);
main_layout->addWidget(reverse);
main_layout->addWidget(maintain_pitch);
main_layout->addWidget(ripple);
QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
buttonBox->setCenterButtons(true);
main_layout->addWidget(buttonBox);
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(percent, SIGNAL(valueChanged(double)), this, SLOT(percent_update()));
connect(frame_rate, SIGNAL(valueChanged(double)), this, SLOT(frame_rate_update()));
connect(duration, SIGNAL(valueChanged(double)), this, SLOT(duration_update()));
}
int SpeedDialog::exec() {
bool enable_frame_rate = false;
bool multiple_audio = false;
maintain_pitch->setEnabled(false);
double default_frame_rate = qSNaN();
double current_frame_rate = qSNaN();
double current_percent = qSNaN();
long default_length = -1;
long current_length = -1;
for (int i=0;i<clips_.size();i++) {
Clip* c = clips_.at(i);
double clip_percent;
// get default frame rate/percentage
clip_percent = c->speed().value;
if (c->type() == olive::kTypeVideo) {
bool process_video = true;
if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) {
FootageStream* ms = c->media_stream();
if (ms != nullptr && ms->infinite_length) {
process_video = false;
}
}
if (process_video) {
double media_frame_rate = c->media_frame_rate();
// get "default" frame rate"
if (enable_frame_rate) {
// check if frame rate is equal to default
if (!qIsNaN(default_frame_rate) && !qFuzzyCompare(media_frame_rate, default_frame_rate)) {
default_frame_rate = qSNaN();
}
if (!qIsNaN(current_frame_rate) && !qFuzzyCompare(media_frame_rate*c->speed().value, current_frame_rate)) {
current_frame_rate = qSNaN();
}
} else {
default_frame_rate = media_frame_rate;
current_frame_rate = media_frame_rate*c->speed().value;
}
enable_frame_rate = true;
}
} else if (c->type() == olive::kTypeAudio) {
maintain_pitch->setEnabled(true);
if (!multiple_audio) {
maintain_pitch->setChecked(c->speed().maintain_audio_pitch);
multiple_audio = true;
} else if (!maintain_pitch->isTristate() && maintain_pitch->isChecked() != c->speed().maintain_audio_pitch) {
maintain_pitch->setCheckState(Qt::PartiallyChecked);
maintain_pitch->setTristate(true);
}
}
if (i == 0) {
reverse->setChecked(c->reversed());
} else if (c->reversed() != reverse->isChecked()) {
reverse->setTristate(true);
reverse->setCheckState(Qt::PartiallyChecked);
}
// get default length
long clip_default_length = qRound(c->length() * clip_percent);
if (i == 0) {
current_length = c->length();
default_length = clip_default_length;
current_percent = clip_percent;
} else {
if (current_length != -1 && c->length() != current_length) {
current_length = -1;
}
if (default_length != -1 && clip_default_length != default_length) {
default_length = -1;
}
if (!qIsNaN(current_percent) && !qFuzzyCompare(clip_percent, current_percent)) {
current_percent = qSNaN();
}
}
}
frame_rate->SetMinimum(1);
percent->SetMinimum(0.0001);
duration->SetMinimum(1);
frame_rate->setEnabled(enable_frame_rate);
frame_rate->SetDefault(default_frame_rate);
frame_rate->SetValue(current_frame_rate);
percent->SetValue(current_percent);
duration->SetDefault(default_length);
duration->SetValue((current_length == -1) ? qSNaN() : current_length);
return QDialog::exec();
}
void SpeedDialog::percent_update() {
bool got_fr = false;
double fr_val = qSNaN();
long len_val = -1;
for (int i=0;i<clips_.size();i++) {
Clip* c = clips_.at(i);
// get frame rate
if (frame_rate->isEnabled() && c->type() == olive::kTypeVideo) {
double clip_fr = c->media_frame_rate() * percent->value();
if (got_fr) {
if (!qIsNaN(fr_val) && !qFuzzyCompare(fr_val, clip_fr)) {
fr_val = qSNaN();
}
} else {
fr_val = clip_fr;
got_fr = true;
}
}
// get duration
long clip_default_length = qRound(c->length() * c->speed().value);
long new_clip_length = qRound(clip_default_length / percent->value());
if (i == 0) {
len_val = new_clip_length;
} else if (len_val > -1 && len_val != new_clip_length) {
len_val = -1;
}
}
frame_rate->SetValue(fr_val);
duration->SetValue((len_val == -1) ? qSNaN() : len_val);
}
void SpeedDialog::duration_update() {
double pc_val = qSNaN();
bool got_fr = false;
double fr_val = qSNaN();
for (int i=0;i<clips_.size();i++) {
Clip* c = clips_.at(i);
// get percent
long clip_default_length = qRound(c->length() * c->speed().value);
double clip_pc = clip_default_length / duration->value();
if (i == 0) {
pc_val = clip_pc;
} else if (!qIsNaN(pc_val) && !qFuzzyCompare(clip_pc, pc_val)) {
pc_val = qSNaN();
}
// get frame rate
if (frame_rate->isEnabled() && c->type() == olive::kTypeVideo) {
double clip_fr = c->media_frame_rate() * clip_pc;
if (got_fr) {
if (!qIsNaN(fr_val) && !qFuzzyCompare(fr_val, clip_fr)) {
fr_val = qSNaN();
}
} else {
fr_val = clip_fr;
got_fr = true;
}
}
}
frame_rate->SetValue(fr_val);
percent->SetValue(pc_val);
}
void SpeedDialog::frame_rate_update() {
/*double fr = (frame_rate->value());
double pc = (fr / default_frame_rate);
percent->set_value(pc, false);
duration->set_value(default_length / pc, false);*/
double old_pc_val = qSNaN();
bool got_pc_val = false;
double pc_val = qSNaN();
bool got_len_val = false;
long len_val = -1;
// analyze video clips
for (int i=0;i<clips_.size();i++) {
Clip* c = clips_.at(i);
// check if all selected clips are currently the same speed
if (i == 0) {
old_pc_val = c->speed().value;
} else if (!qIsNaN(old_pc_val) && !qFuzzyCompare(c->speed().value, old_pc_val)) {
old_pc_val = qSNaN();
}
if (c->type() == olive::kTypeVideo) {
// what would the new speed be based on this frame rate
double new_clip_speed = frame_rate->value() / c->media_frame_rate();
if (!got_pc_val) {
pc_val = new_clip_speed;
got_pc_val = true;
} else if (!qIsNaN(pc_val) && !qFuzzyCompare(pc_val, new_clip_speed)) {
pc_val = qSNaN();
}
// what would be the new length based on this speed
long new_clip_len = (c->length() * c->speed().value) / new_clip_speed;
if (!got_len_val) {
len_val = new_clip_len;
got_len_val = true;
} else if (len_val > -1 && new_clip_len != len_val) {
len_val = -1;
}
}
}
// analyze audio clips
for (int i=0;i<clips_.size();i++) {
Clip* c = clips_.at(i);
if (c->type() == olive::kTypeAudio) {
long new_clip_len = (qIsNaN(old_pc_val) || qIsNaN(pc_val)) ?
c->length() : qRound((c->length() * c->speed().value) / pc_val);
if (len_val > -1 && new_clip_len != len_val) {
len_val = -1;
break;
}
}
}
percent->SetValue(pc_val);
duration->SetValue((len_val == -1) ? qSNaN() : len_val);
}
void set_speed(ComboAction* ca, Clip* c, double speed, bool ripple, long& ep, long& lr) {
c->track()->DeselectArea(c->timeline_in(), c->timeline_out());
long proposed_out = c->timeline_out();
double multiplier = (c->speed().value / speed);
proposed_out = qRound(c->timeline_in() + (c->length() * multiplier));
ca->append(new SetSpeedAction(c, speed));
if (!ripple && proposed_out > c->timeline_out()) {
QVector<Clip*> all_clips = c->track()->sequence()->GetAllClips();
for (int i=0;i<all_clips.size();i++) {
Clip* compare = all_clips.at(i);
if (compare != nullptr
&& compare->track() == c->track()
&& compare->timeline_in() >= c->timeline_out() && compare->timeline_in() < proposed_out) {
proposed_out = compare->timeline_in();
}
}
}
ep = qMin(ep, c->timeline_out());
lr = qMax(lr, proposed_out - c->timeline_out());
c->track()->sequence()->MoveClip(c,
ca,
c->timeline_in(),
proposed_out,
qRound(c->clip_in() * multiplier),
c->track());
c->refactor_frame_rate(ca, multiplier, false);
c->track()->SelectArea(c->timeline_in(), proposed_out);
}
void SpeedDialog::accept() {
ComboAction* ca = new ComboAction();
// undoable action for setting "maintain audio pitch"
SetClipProperty* audio_pitch_action = new SetClipProperty(kSetClipPropertyMaintainAudioPitch);
// undoable action for setting "reversed"
SetClipProperty* reversed_action = new SetClipProperty(kSetClipPropertyReversed);
// undoable action for restoring clip selections
Sequence* sequence = clips_.first()->track()->sequence();
QVector<Selection> old_selections = sequence->Selections();
// variables used to calculate ripples
long earliest_point = LONG_MAX;
long longest_ripple = LONG_MIN;
for (int i=0;i<clips_.size();i++) {
Clip* c = clips_.at(i);
// make sure the clip is closed while we're making changes
if (c->IsOpen()) {
c->Close(true);
}
// set maintain audio pitch if the user made a selection
if (c->type() == olive::kTypeAudio
&& maintain_pitch->checkState() != Qt::PartiallyChecked
&& c->speed().maintain_audio_pitch != maintain_pitch->isChecked()) {
audio_pitch_action->AddSetting(c, maintain_pitch->isChecked());
}
// set reverse setting if the user made a selection
if (reverse->checkState() != Qt::PartiallyChecked && c->reversed() != reverse->isChecked()) {
long new_clip_in = (c->media_length() - (c->length() + c->clip_in()));
c->track()->sequence()->MoveClip(c,
ca,
c->timeline_in(),
c->timeline_out(),
new_clip_in,
c->track());
c->set_clip_in(new_clip_in);
reversed_action->AddSetting(c, reverse->isChecked());
}
}
// setting the actual speed
if (!qIsNaN(percent->value())) {
// if we have a percentage value, use that on all the clips
for (int i=0;i<clips_.size();i++) {
Clip* c = clips_.at(i);
set_speed(ca, c, percent->value(), ripple->isChecked(), earliest_point, longest_ripple);
}
} else if (!qIsNaN(frame_rate->value())) {
// if the user changed the speed by changing the frame rate,
bool can_change_all = true;
double cached_speed = clips_.first()->speed().value;
double cached_fr = qSNaN();
// see if we can use the frame rate to change all the speeds
for (int i=0;i<clips_.size();i++) {
Clip* c = clips_.at(i);
if (i > 0 && !qFuzzyCompare(cached_speed, c->speed().value)) {
can_change_all = false;
}
if (c->type() == olive::kTypeVideo) {
if (qIsNaN(cached_fr)) {
cached_fr = c->media_frame_rate();
} else if (!qFuzzyCompare(cached_fr, c->media_frame_rate())) {
can_change_all = false;
break;
}
}
}
// make changes
for (int i=0;i<clips_.size();i++) {
Clip* c = clips_.at(i);
if (c->type() == olive::kTypeVideo) {
set_speed(ca, c, frame_rate->value() / c->media_frame_rate(), ripple->isChecked(), earliest_point, longest_ripple);
} else if (can_change_all) {
set_speed(ca, c, frame_rate->value() / cached_fr, ripple->isChecked(), earliest_point, longest_ripple);
}
}
} else if (!qIsNaN(duration->value())) {
// simply set duration
for (int i=0;i<clips_.size();i++) {
Clip* c = clips_.at(i);
set_speed(ca, c, (c->length() * c->speed().value) / duration->value(), ripple->isChecked(), earliest_point, longest_ripple);
}
}
if (ripple->isChecked()) {
sequence->Ripple(ca, earliest_point, longest_ripple);
}
ca->append(new SetSelectionsCommand(sequence, old_selections, sequence->Selections()));
ca->append(reversed_action);
ca->append(audio_pitch_action);
olive::undo_stack.push(ca);
update_ui(true);
QDialog::accept();
}
/***
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 "speeddialog.h"
#include <QHBoxLayout>
#include <QGridLayout>
#include <QLabel>
#include <QPushButton>
#include <QDialogButtonBox>
#include "timeline/sequence.h"
#include "project/footage.h"
#include "rendering/renderfunctions.h"
#include "panels/panels.h"
#include "panels/timeline.h"
#include "undo/undo.h"
#include "undo/undostack.h"
#include "nodes/oldeffectnode.h"
#include "project/media.h"
SpeedDialog::SpeedDialog(QWidget *parent, QVector<Clip*> clips) : QDialog(parent) {
setWindowTitle(tr("Speed/Duration"));
clips_ = clips;
QVBoxLayout* main_layout = new QVBoxLayout(this);
QGridLayout* grid = new QGridLayout();
grid->setSpacing(6);
grid->addWidget(new QLabel(tr("Speed:"), this), 0, 0);
percent = new LabelSlider(this);
percent->SetDecimalPlaces(2);
percent->SetDisplayType(LabelSlider::Percent);
percent->SetDefault(1);
grid->addWidget(percent, 0, 1);
grid->addWidget(new QLabel(tr("Frame Rate:"), this), 1, 0);
frame_rate = new LabelSlider(this);
frame_rate->SetDecimalPlaces(3);
grid->addWidget(frame_rate, 1, 1);
grid->addWidget(new QLabel(tr("Duration:"), this), 2, 0);
duration = new LabelSlider(this);
duration->SetDisplayType(LabelSlider::FrameNumber);
duration->SetFrameRate(clips_.first()->track()->sequence()->frame_rate());
grid->addWidget(duration, 2, 1);
main_layout->addLayout(grid);
reverse = new QCheckBox(tr("Reverse"), this);
maintain_pitch = new QCheckBox(tr("Maintain Audio Pitch"), this);
ripple = new QCheckBox(tr("Ripple Changes"), this);
main_layout->addWidget(reverse);
main_layout->addWidget(maintain_pitch);
main_layout->addWidget(ripple);
QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
buttonBox->setCenterButtons(true);
main_layout->addWidget(buttonBox);
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(percent, SIGNAL(valueChanged(double)), this, SLOT(percent_update()));
connect(frame_rate, SIGNAL(valueChanged(double)), this, SLOT(frame_rate_update()));
connect(duration, SIGNAL(valueChanged(double)), this, SLOT(duration_update()));
}
int SpeedDialog::exec() {
bool enable_frame_rate = false;
bool multiple_audio = false;
maintain_pitch->setEnabled(false);
double default_frame_rate = qSNaN();
double current_frame_rate = qSNaN();
double current_percent = qSNaN();
long default_length = -1;
long current_length = -1;
for (int i=0;i<clips_.size();i++) {
Clip* c = clips_.at(i);
double clip_percent;
// get default frame rate/percentage
clip_percent = c->speed().value;
if (c->type() == olive::kTypeVideo) {
bool process_video = true;
if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) {
FootageStream* ms = c->media_stream();
if (ms != nullptr && ms->infinite_length) {
process_video = false;
}
}
if (process_video) {
double media_frame_rate = c->media_frame_rate();
// get "default" frame rate"
if (enable_frame_rate) {
// check if frame rate is equal to default
if (!qIsNaN(default_frame_rate) && !qFuzzyCompare(media_frame_rate, default_frame_rate)) {
default_frame_rate = qSNaN();
}
if (!qIsNaN(current_frame_rate) && !qFuzzyCompare(media_frame_rate*c->speed().value, current_frame_rate)) {
current_frame_rate = qSNaN();
}
} else {
default_frame_rate = media_frame_rate;
current_frame_rate = media_frame_rate*c->speed().value;
}
enable_frame_rate = true;
}
} else if (c->type() == olive::kTypeAudio) {
maintain_pitch->setEnabled(true);
if (!multiple_audio) {
maintain_pitch->setChecked(c->speed().maintain_audio_pitch);
multiple_audio = true;
} else if (!maintain_pitch->isTristate() && maintain_pitch->isChecked() != c->speed().maintain_audio_pitch) {
maintain_pitch->setCheckState(Qt::PartiallyChecked);
maintain_pitch->setTristate(true);
}
}
if (i == 0) {
reverse->setChecked(c->reversed());
} else if (c->reversed() != reverse->isChecked()) {
reverse->setTristate(true);
reverse->setCheckState(Qt::PartiallyChecked);
}
// get default length
long clip_default_length = qRound(c->length() * clip_percent);
if (i == 0) {
current_length = c->length();
default_length = clip_default_length;
current_percent = clip_percent;
} else {
if (current_length != -1 && c->length() != current_length) {
current_length = -1;
}
if (default_length != -1 && clip_default_length != default_length) {
default_length = -1;
}
if (!qIsNaN(current_percent) && !qFuzzyCompare(clip_percent, current_percent)) {
current_percent = qSNaN();
}
}
}
frame_rate->SetMinimum(1);
percent->SetMinimum(0.0001);
duration->SetMinimum(1);
frame_rate->setEnabled(enable_frame_rate);
frame_rate->SetDefault(default_frame_rate);
frame_rate->SetValue(current_frame_rate);
percent->SetValue(current_percent);
duration->SetDefault(default_length);
duration->SetValue((current_length == -1) ? qSNaN() : current_length);
return QDialog::exec();
}
void SpeedDialog::percent_update() {
bool got_fr = false;
double fr_val = qSNaN();
long len_val = -1;
for (int i=0;i<clips_.size();i++) {
Clip* c = clips_.at(i);
// get frame rate
if (frame_rate->isEnabled() && c->type() == olive::kTypeVideo) {
double clip_fr = c->media_frame_rate() * percent->value();
if (got_fr) {
if (!qIsNaN(fr_val) && !qFuzzyCompare(fr_val, clip_fr)) {
fr_val = qSNaN();
}
} else {
fr_val = clip_fr;
got_fr = true;
}
}
// get duration
long clip_default_length = qRound(c->length() * c->speed().value);
long new_clip_length = qRound(clip_default_length / percent->value());
if (i == 0) {
len_val = new_clip_length;
} else if (len_val > -1 && len_val != new_clip_length) {
len_val = -1;
}
}
frame_rate->SetValue(fr_val);
duration->SetValue((len_val == -1) ? qSNaN() : len_val);
}
void SpeedDialog::duration_update() {
double pc_val = qSNaN();
bool got_fr = false;
double fr_val = qSNaN();
for (int i=0;i<clips_.size();i++) {
Clip* c = clips_.at(i);
// get percent
long clip_default_length = qRound(c->length() * c->speed().value);
double clip_pc = clip_default_length / duration->value();
if (i == 0) {
pc_val = clip_pc;
} else if (!qIsNaN(pc_val) && !qFuzzyCompare(clip_pc, pc_val)) {
pc_val = qSNaN();
}
// get frame rate
if (frame_rate->isEnabled() && c->type() == olive::kTypeVideo) {
double clip_fr = c->media_frame_rate() * clip_pc;
if (got_fr) {
if (!qIsNaN(fr_val) && !qFuzzyCompare(fr_val, clip_fr)) {
fr_val = qSNaN();
}
} else {
fr_val = clip_fr;
got_fr = true;
}
}
}
frame_rate->SetValue(fr_val);
percent->SetValue(pc_val);
}
void SpeedDialog::frame_rate_update() {
/*double fr = (frame_rate->value());
double pc = (fr / default_frame_rate);
percent->set_value(pc, false);
duration->set_value(default_length / pc, false);*/
double old_pc_val = qSNaN();
bool got_pc_val = false;
double pc_val = qSNaN();
bool got_len_val = false;
long len_val = -1;
// analyze video clips
for (int i=0;i<clips_.size();i++) {
Clip* c = clips_.at(i);
// check if all selected clips are currently the same speed
if (i == 0) {
old_pc_val = c->speed().value;
} else if (!qIsNaN(old_pc_val) && !qFuzzyCompare(c->speed().value, old_pc_val)) {
old_pc_val = qSNaN();
}
if (c->type() == olive::kTypeVideo) {
// what would the new speed be based on this frame rate
double new_clip_speed = frame_rate->value() / c->media_frame_rate();
if (!got_pc_val) {
pc_val = new_clip_speed;
got_pc_val = true;
} else if (!qIsNaN(pc_val) && !qFuzzyCompare(pc_val, new_clip_speed)) {
pc_val = qSNaN();
}
// what would be the new length based on this speed
long new_clip_len = (c->length() * c->speed().value) / new_clip_speed;
if (!got_len_val) {
len_val = new_clip_len;
got_len_val = true;
} else if (len_val > -1 && new_clip_len != len_val) {
len_val = -1;
}
}
}
// analyze audio clips
for (int i=0;i<clips_.size();i++) {
Clip* c = clips_.at(i);
if (c->type() == olive::kTypeAudio) {
long new_clip_len = (qIsNaN(old_pc_val) || qIsNaN(pc_val)) ?
c->length() : qRound((c->length() * c->speed().value) / pc_val);
if (len_val > -1 && new_clip_len != len_val) {
len_val = -1;
break;
}
}
}
percent->SetValue(pc_val);
duration->SetValue((len_val == -1) ? qSNaN() : len_val);
}
void set_speed(ComboAction* ca, Clip* c, double speed, bool ripple, long& ep, long& lr) {
c->track()->DeselectArea(c->timeline_in(), c->timeline_out());
long proposed_out = c->timeline_out();
double multiplier = (c->speed().value / speed);
proposed_out = qRound(c->timeline_in() + (c->length() * multiplier));
ca->append(new SetSpeedAction(c, speed));
if (!ripple && proposed_out > c->timeline_out()) {
QVector<Clip*> all_clips = c->track()->sequence()->GetAllClips();
for (int i=0;i<all_clips.size();i++) {
Clip* compare = all_clips.at(i);
if (compare != nullptr
&& compare->track() == c->track()
&& compare->timeline_in() >= c->timeline_out() && compare->timeline_in() < proposed_out) {
proposed_out = compare->timeline_in();
}
}
}
ep = qMin(ep, c->timeline_out());
lr = qMax(lr, proposed_out - c->timeline_out());
c->track()->sequence()->MoveClip(c,
ca,
c->timeline_in(),
proposed_out,
qRound(c->clip_in() * multiplier),
c->track());
c->refactor_frame_rate(ca, multiplier, false);
c->track()->SelectArea(c->timeline_in(), proposed_out);
}
void SpeedDialog::accept() {
ComboAction* ca = new ComboAction();
// undoable action for setting "maintain audio pitch"
SetClipProperty* audio_pitch_action = new SetClipProperty(kSetClipPropertyMaintainAudioPitch);
// undoable action for setting "reversed"
SetClipProperty* reversed_action = new SetClipProperty(kSetClipPropertyReversed);
// undoable action for restoring clip selections
Sequence* sequence = clips_.first()->track()->sequence();
QVector<Selection> old_selections = sequence->Selections();
// variables used to calculate ripples
long earliest_point = LONG_MAX;
long longest_ripple = LONG_MIN;
for (int i=0;i<clips_.size();i++) {
Clip* c = clips_.at(i);
// make sure the clip is closed while we're making changes
if (c->IsOpen()) {
c->Close(true);
}
// set maintain audio pitch if the user made a selection
if (c->type() == olive::kTypeAudio
&& maintain_pitch->checkState() != Qt::PartiallyChecked
&& c->speed().maintain_audio_pitch != maintain_pitch->isChecked()) {
audio_pitch_action->AddSetting(c, maintain_pitch->isChecked());
}
// set reverse setting if the user made a selection
if (reverse->checkState() != Qt::PartiallyChecked && c->reversed() != reverse->isChecked()) {
long new_clip_in = (c->media_length() - (c->length() + c->clip_in()));
c->track()->sequence()->MoveClip(c,
ca,
c->timeline_in(),
c->timeline_out(),
new_clip_in,
c->track());
c->set_clip_in(new_clip_in);
reversed_action->AddSetting(c, reverse->isChecked());
}
}
// setting the actual speed
if (!qIsNaN(percent->value())) {
// if we have a percentage value, use that on all the clips
for (int i=0;i<clips_.size();i++) {
Clip* c = clips_.at(i);
set_speed(ca, c, percent->value(), ripple->isChecked(), earliest_point, longest_ripple);
}
} else if (!qIsNaN(frame_rate->value())) {
// if the user changed the speed by changing the frame rate,
bool can_change_all = true;
double cached_speed = clips_.first()->speed().value;
double cached_fr = qSNaN();
// see if we can use the frame rate to change all the speeds
for (int i=0;i<clips_.size();i++) {
Clip* c = clips_.at(i);
if (i > 0 && !qFuzzyCompare(cached_speed, c->speed().value)) {
can_change_all = false;
}
if (c->type() == olive::kTypeVideo) {
if (qIsNaN(cached_fr)) {
cached_fr = c->media_frame_rate();
} else if (!qFuzzyCompare(cached_fr, c->media_frame_rate())) {
can_change_all = false;
break;
}
}
}
// make changes
for (int i=0;i<clips_.size();i++) {
Clip* c = clips_.at(i);
if (c->type() == olive::kTypeVideo) {
set_speed(ca, c, frame_rate->value() / c->media_frame_rate(), ripple->isChecked(), earliest_point, longest_ripple);
} else if (can_change_all) {
set_speed(ca, c, frame_rate->value() / cached_fr, ripple->isChecked(), earliest_point, longest_ripple);
}
}
} else if (!qIsNaN(duration->value())) {
// simply set duration
for (int i=0;i<clips_.size();i++) {
Clip* c = clips_.at(i);
set_speed(ca, c, (c->length() * c->speed().value) / duration->value(), ripple->isChecked(), earliest_point, longest_ripple);
}
}
if (ripple->isChecked()) {
sequence->Ripple(ca, earliest_point, longest_ripple);
}
ca->append(new SetSelectionsCommand(sequence, old_selections, sequence->Selections()));
ca->append(reversed_action);
ca->append(audio_pitch_action);
olive::undo_stack.push(ca);
update_ui(true);
QDialog::accept();
}
+132 -132
View File
@@ -1,132 +1,132 @@
/***
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 SPEEDDIALOG_H
#define SPEEDDIALOG_H
#include <QDialog>
#include <QCheckBox>
#include "timeline/clip.h"
#include "ui/labelslider.h"
/**
* @brief The SpeedDialog class
*
* A dialog for setting the speed of one or more Clips. This can be run from anywhere provided it's given a valid
* array of Clips.
*
* It's preferable to
*/
class SpeedDialog : public QDialog
{
Q_OBJECT
public:
/**
* @brief SpeedDialog Constructor
*
* @param parent
*
* QWidget parent. Usually MainWindow or Timeline panel.
*
* @param clips
*
* A valid array of Clips to change the speed of.
*/
SpeedDialog(QWidget* parent, QVector<Clip*> clips);
public slots:
/**
* @brief Override of exec() to set up current Clip speed data just before opening
*
* @return
*
* The result of QDialog::exec(), a DialogCode result.
*/
virtual int exec() override;
private slots:
/**
* @brief Override of accept() to perform the selected changes on the Clips
*/
virtual void accept() override;
/**
* @brief Slot when the speed percentage field is changed by the user
*
* The three fields (percent, duration, and frame rate) all work in tandem to create a speed multipler for the
* Clip. Each has a slot for when one of the fields changes to update the others appropriately so they all have the
* same speed multipler.
*/
void percent_update();
/**
* @brief Slot when the duration field is changed by the user
*
* The three fields (percent, duration, and frame rate) all work in tandem to create a speed multipler for the
* Clip. Each has a slot for when one of the fields changes to update the others appropriately so they all have the
* same speed multipler.
*/
void duration_update();
/**
* @brief Slot when the frame rate field is changed by the user
*
* The three fields (percent, duration, and frame rate) all work in tandem to create a speed multipler for the
* Clip. Each has a slot for when one of the fields changes to update the others appropriately so they all have the
* same speed multipler.
*/
void frame_rate_update();
private:
/**
* @brief Internal array of Clip objects
*/
QVector<Clip*> clips_;
/**
* @brief Speed percentage field
*/
LabelSlider* percent;
/**
* @brief Duration field
*/
LabelSlider* duration;
/**
* @brief Frame rate field
*/
LabelSlider* frame_rate;
/**
* @brief UI widget for setting the Clip's reverse value
*/
QCheckBox* reverse;
/**
* @brief UI widget for setting the Clip's maintain pitch value
*/
QCheckBox* maintain_pitch;
/**
* @brief UI widget for setting whether to ripple Clips around these changes or not
*/
QCheckBox* ripple;
};
#endif // SPEEDDIALOG_H
/***
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 SPEEDDIALOG_H
#define SPEEDDIALOG_H
#include <QDialog>
#include <QCheckBox>
#include "timeline/clip.h"
#include "ui/labelslider.h"
/**
* @brief The SpeedDialog class
*
* A dialog for setting the speed of one or more Clips. This can be run from anywhere provided it's given a valid
* array of Clips.
*
* It's preferable to
*/
class SpeedDialog : public QDialog
{
Q_OBJECT
public:
/**
* @brief SpeedDialog Constructor
*
* @param parent
*
* QWidget parent. Usually MainWindow or Timeline panel.
*
* @param clips
*
* A valid array of Clips to change the speed of.
*/
SpeedDialog(QWidget* parent, QVector<Clip*> clips);
public slots:
/**
* @brief Override of exec() to set up current Clip speed data just before opening
*
* @return
*
* The result of QDialog::exec(), a DialogCode result.
*/
virtual int exec() override;
private slots:
/**
* @brief Override of accept() to perform the selected changes on the Clips
*/
virtual void accept() override;
/**
* @brief Slot when the speed percentage field is changed by the user
*
* The three fields (percent, duration, and frame rate) all work in tandem to create a speed multipler for the
* Clip. Each has a slot for when one of the fields changes to update the others appropriately so they all have the
* same speed multipler.
*/
void percent_update();
/**
* @brief Slot when the duration field is changed by the user
*
* The three fields (percent, duration, and frame rate) all work in tandem to create a speed multipler for the
* Clip. Each has a slot for when one of the fields changes to update the others appropriately so they all have the
* same speed multipler.
*/
void duration_update();
/**
* @brief Slot when the frame rate field is changed by the user
*
* The three fields (percent, duration, and frame rate) all work in tandem to create a speed multipler for the
* Clip. Each has a slot for when one of the fields changes to update the others appropriately so they all have the
* same speed multipler.
*/
void frame_rate_update();
private:
/**
* @brief Internal array of Clip objects
*/
QVector<Clip*> clips_;
/**
* @brief Speed percentage field
*/
LabelSlider* percent;
/**
* @brief Duration field
*/
LabelSlider* duration;
/**
* @brief Frame rate field
*/
LabelSlider* frame_rate;
/**
* @brief UI widget for setting the Clip's reverse value
*/
QCheckBox* reverse;
/**
* @brief UI widget for setting the Clip's maintain pitch value
*/
QCheckBox* maintain_pitch;
/**
* @brief UI widget for setting whether to ripple Clips around these changes or not
*/
QCheckBox* ripple;
};
#endif // SPEEDDIALOG_H
+213 -213
View File
@@ -1,213 +1,213 @@
/***
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 "texteditdialog.h"
#include <QVBoxLayout>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QTimer>
#include <QDebug>
#include "ui/icons.h"
TextEditDialog::TextEditDialog(QWidget *parent, const QString &s, bool rich_text) :
QDialog(parent),
rich_text_(rich_text)
{
setWindowTitle(tr("Edit Text"));
QVBoxLayout* layout = new QVBoxLayout(this);
// Create central text editor object
textEdit = new QTextEdit(this);
textEdit->setUndoRedoEnabled(true);
// Upper toolbar
if (rich_text) {
QHBoxLayout* toolbar = new QHBoxLayout();
// Italic Button
italic_button = new QPushButton();
italic_button->setIcon(olive::icon::CreateIconFromSVG(":/icons/italic.svg", false));
italic_button->setCheckable(true);
connect(italic_button, SIGNAL(clicked(bool)), textEdit, SLOT(setFontItalic(bool)));
toolbar->addWidget(italic_button);
// Underline Button
underline_button = new QPushButton();
underline_button->setIcon(olive::icon::CreateIconFromSVG(":/icons/underline.svg", false));
underline_button->setCheckable(true);
connect(underline_button, SIGNAL(clicked(bool)), textEdit, SLOT(setFontUnderline(bool)));
toolbar->addWidget(underline_button);
// Font Name
font_list = new QFontComboBox();
connect(font_list, SIGNAL(currentIndexChanged(const QString&)), textEdit, SLOT(setFontFamily(const QString&)));
toolbar->addWidget(font_list);
// Font Weight
font_weight = new QComboBox();
font_weight->addItem(tr("Thin"), QFont::Thin);
font_weight->addItem(tr("Extra Light"), QFont::ExtraLight);
font_weight->addItem(tr("Light"), QFont::Light);
font_weight->addItem(tr("Normal"), QFont::Normal);
font_weight->addItem(tr("Medium"), QFont::Medium);
font_weight->addItem(tr("Demi Bold"), QFont::DemiBold);
font_weight->addItem(tr("Bold"), QFont::Bold);
font_weight->addItem(tr("Extra Bold"), QFont::ExtraBold);
font_weight->addItem(tr("Black"), QFont::Black);
connect(font_weight, SIGNAL(currentIndexChanged(int)), this, SLOT(SetFontWeight(int)));
toolbar->addWidget(font_weight);
// Font Size
font_size = new LabelSlider();
connect(font_size, SIGNAL(valueChanged(double)), textEdit, SLOT(setFontPointSize(qreal)));
toolbar->addWidget(font_size);
// Font Color
font_color = new ColorButton();
connect(font_color, SIGNAL(color_changed(const QColor&)), textEdit, SLOT(setTextColor(const QColor &)));
toolbar->addWidget(font_color);
toolbar->addStretch();
// Left Align
left_align_button = new QPushButton();
left_align_button->setIcon(olive::icon::CreateIconFromSVG(":/icons/align-left.svg", false));
left_align_button->setCheckable(true);
left_align_button->setProperty("a", Qt::AlignLeft);
connect(left_align_button, SIGNAL(clicked(bool)), this, SLOT(SetAlignmentFromProperty()));
toolbar->addWidget(left_align_button);
// Center Align
center_align_button = new QPushButton();
center_align_button->setIcon(olive::icon::CreateIconFromSVG(":/icons/align-center.svg", false));
center_align_button->setCheckable(true);
center_align_button->setProperty("a", Qt::AlignCenter);
connect(center_align_button, SIGNAL(clicked(bool)), this, SLOT(SetAlignmentFromProperty()));
toolbar->addWidget(center_align_button);
// Right Align
right_align_button = new QPushButton();
right_align_button->setIcon(olive::icon::CreateIconFromSVG(":/icons/align-right.svg", false));
right_align_button->setCheckable(true);
right_align_button->setProperty("a", Qt::AlignRight);
connect(right_align_button, SIGNAL(clicked(bool)), this, SLOT(SetAlignmentFromProperty()));
toolbar->addWidget(right_align_button);
// Justify Align
justify_align_button = new QPushButton();
justify_align_button->setIcon(olive::icon::CreateIconFromSVG(":/icons/justify-center.svg", false));
justify_align_button->setCheckable(true);
justify_align_button->setProperty("a", Qt::AlignJustify);
connect(justify_align_button, SIGNAL(clicked(bool)), this, SLOT(SetAlignmentFromProperty()));
toolbar->addWidget(justify_align_button);
layout->addLayout(toolbar);
}
layout->addWidget(textEdit);
// Lower toolbar
/*
if (rich_text) {
QHBoxLayout* lower_toolbar = new QHBoxLayout();
lower_toolbar->addWidget(new QLabel(tr("Letter Spacing:")));
letter_spacing = new LabelSlider();
connect(letter_spacing, SIGNAL(valueChanged(double)), this, SLOT(SetLetterSpacing(qreal)));
lower_toolbar->addWidget(letter_spacing);
lower_toolbar->addStretch();
layout->addLayout(lower_toolbar);
}
*/
// Create dialog buttons at the bottom
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
buttons->setCenterButtons(true);
layout->addWidget(buttons);
connect(buttons, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttons, SIGNAL(rejected()), this, SLOT(reject()));
// Connect the cursor position changing to the rich text toolbar buttons updating (so for example, when italic text
// is selected, the italic button will be pressed)
connect(textEdit, SIGNAL(cursorPositionChanged()), this, SLOT(UpdateUIFromTextCursor()));
// Set the widget's text based on the rich text mode
if (rich_text_) {
textEdit->setHtml(s);
} else {
textEdit->setPlainText(s);
}
// Helps ensure the UI elements update correctly at the beginning - when the cursor is at the start, the UI elements
// show up blank. Setting it to the end is probably more expected behavior anyway.
textEdit->moveCursor(QTextCursor::End);
}
const QString& TextEditDialog::get_string() {
return result_str;
}
void TextEditDialog::accept() {
result_str = rich_text_ ? textEdit->toHtml() : textEdit->toPlainText();
QDialog::accept();
}
void TextEditDialog::SetFontWeight(int i)
{
textEdit->setFontWeight(font_weight->itemData(i).toInt());
}
void TextEditDialog::SetAlignmentFromProperty()
{
textEdit->setAlignment(static_cast<Qt::Alignment>(sender()->property("a").toInt()));
UpdateUIFromTextCursor();
}
void TextEditDialog::UpdateUIFromTextCursor()
{
if (rich_text_) {
italic_button->setChecked(textEdit->fontItalic());
underline_button->setChecked(textEdit->fontUnderline());
font_list->setCurrentText(textEdit->fontFamily());
font_size->SetValue(textEdit->fontPointSize());
font_color->set_color(textEdit->textColor());
for (int i=0;i<font_weight->count();i++) {
if (font_weight->itemData(i).toInt() == textEdit->fontWeight()) {
font_weight->blockSignals(true);
font_weight->setCurrentIndex(i);
font_weight->blockSignals(false);
break;
}
}
Qt::Alignment align = textEdit->alignment();
left_align_button->setChecked(align == Qt::AlignLeft);
center_align_button->setChecked(align == Qt::AlignCenter);
right_align_button->setChecked(align == Qt::AlignRight);
justify_align_button->setChecked(align == Qt::AlignJustify);
}
}
/***
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 "texteditdialog.h"
#include <QVBoxLayout>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QTimer>
#include <QDebug>
#include "ui/icons.h"
TextEditDialog::TextEditDialog(QWidget *parent, const QString &s, bool rich_text) :
QDialog(parent),
rich_text_(rich_text)
{
setWindowTitle(tr("Edit Text"));
QVBoxLayout* layout = new QVBoxLayout(this);
// Create central text editor object
textEdit = new QTextEdit(this);
textEdit->setUndoRedoEnabled(true);
// Upper toolbar
if (rich_text) {
QHBoxLayout* toolbar = new QHBoxLayout();
// Italic Button
italic_button = new QPushButton();
italic_button->setIcon(olive::icon::CreateIconFromSVG(":/icons/italic.svg", false));
italic_button->setCheckable(true);
connect(italic_button, SIGNAL(clicked(bool)), textEdit, SLOT(setFontItalic(bool)));
toolbar->addWidget(italic_button);
// Underline Button
underline_button = new QPushButton();
underline_button->setIcon(olive::icon::CreateIconFromSVG(":/icons/underline.svg", false));
underline_button->setCheckable(true);
connect(underline_button, SIGNAL(clicked(bool)), textEdit, SLOT(setFontUnderline(bool)));
toolbar->addWidget(underline_button);
// Font Name
font_list = new QFontComboBox();
connect(font_list, SIGNAL(currentIndexChanged(const QString&)), textEdit, SLOT(setFontFamily(const QString&)));
toolbar->addWidget(font_list);
// Font Weight
font_weight = new QComboBox();
font_weight->addItem(tr("Thin"), QFont::Thin);
font_weight->addItem(tr("Extra Light"), QFont::ExtraLight);
font_weight->addItem(tr("Light"), QFont::Light);
font_weight->addItem(tr("Normal"), QFont::Normal);
font_weight->addItem(tr("Medium"), QFont::Medium);
font_weight->addItem(tr("Demi Bold"), QFont::DemiBold);
font_weight->addItem(tr("Bold"), QFont::Bold);
font_weight->addItem(tr("Extra Bold"), QFont::ExtraBold);
font_weight->addItem(tr("Black"), QFont::Black);
connect(font_weight, SIGNAL(currentIndexChanged(int)), this, SLOT(SetFontWeight(int)));
toolbar->addWidget(font_weight);
// Font Size
font_size = new LabelSlider();
connect(font_size, SIGNAL(valueChanged(double)), textEdit, SLOT(setFontPointSize(qreal)));
toolbar->addWidget(font_size);
// Font Color
font_color = new ColorButton();
connect(font_color, SIGNAL(color_changed(const QColor&)), textEdit, SLOT(setTextColor(const QColor &)));
toolbar->addWidget(font_color);
toolbar->addStretch();
// Left Align
left_align_button = new QPushButton();
left_align_button->setIcon(olive::icon::CreateIconFromSVG(":/icons/align-left.svg", false));
left_align_button->setCheckable(true);
left_align_button->setProperty("a", Qt::AlignLeft);
connect(left_align_button, SIGNAL(clicked(bool)), this, SLOT(SetAlignmentFromProperty()));
toolbar->addWidget(left_align_button);
// Center Align
center_align_button = new QPushButton();
center_align_button->setIcon(olive::icon::CreateIconFromSVG(":/icons/align-center.svg", false));
center_align_button->setCheckable(true);
center_align_button->setProperty("a", Qt::AlignCenter);
connect(center_align_button, SIGNAL(clicked(bool)), this, SLOT(SetAlignmentFromProperty()));
toolbar->addWidget(center_align_button);
// Right Align
right_align_button = new QPushButton();
right_align_button->setIcon(olive::icon::CreateIconFromSVG(":/icons/align-right.svg", false));
right_align_button->setCheckable(true);
right_align_button->setProperty("a", Qt::AlignRight);
connect(right_align_button, SIGNAL(clicked(bool)), this, SLOT(SetAlignmentFromProperty()));
toolbar->addWidget(right_align_button);
// Justify Align
justify_align_button = new QPushButton();
justify_align_button->setIcon(olive::icon::CreateIconFromSVG(":/icons/justify-center.svg", false));
justify_align_button->setCheckable(true);
justify_align_button->setProperty("a", Qt::AlignJustify);
connect(justify_align_button, SIGNAL(clicked(bool)), this, SLOT(SetAlignmentFromProperty()));
toolbar->addWidget(justify_align_button);
layout->addLayout(toolbar);
}
layout->addWidget(textEdit);
// Lower toolbar
/*
if (rich_text) {
QHBoxLayout* lower_toolbar = new QHBoxLayout();
lower_toolbar->addWidget(new QLabel(tr("Letter Spacing:")));
letter_spacing = new LabelSlider();
connect(letter_spacing, SIGNAL(valueChanged(double)), this, SLOT(SetLetterSpacing(qreal)));
lower_toolbar->addWidget(letter_spacing);
lower_toolbar->addStretch();
layout->addLayout(lower_toolbar);
}
*/
// Create dialog buttons at the bottom
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
buttons->setCenterButtons(true);
layout->addWidget(buttons);
connect(buttons, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttons, SIGNAL(rejected()), this, SLOT(reject()));
// Connect the cursor position changing to the rich text toolbar buttons updating (so for example, when italic text
// is selected, the italic button will be pressed)
connect(textEdit, SIGNAL(cursorPositionChanged()), this, SLOT(UpdateUIFromTextCursor()));
// Set the widget's text based on the rich text mode
if (rich_text_) {
textEdit->setHtml(s);
} else {
textEdit->setPlainText(s);
}
// Helps ensure the UI elements update correctly at the beginning - when the cursor is at the start, the UI elements
// show up blank. Setting it to the end is probably more expected behavior anyway.
textEdit->moveCursor(QTextCursor::End);
}
const QString& TextEditDialog::get_string() {
return result_str;
}
void TextEditDialog::accept() {
result_str = rich_text_ ? textEdit->toHtml() : textEdit->toPlainText();
QDialog::accept();
}
void TextEditDialog::SetFontWeight(int i)
{
textEdit->setFontWeight(font_weight->itemData(i).toInt());
}
void TextEditDialog::SetAlignmentFromProperty()
{
textEdit->setAlignment(static_cast<Qt::Alignment>(sender()->property("a").toInt()));
UpdateUIFromTextCursor();
}
void TextEditDialog::UpdateUIFromTextCursor()
{
if (rich_text_) {
italic_button->setChecked(textEdit->fontItalic());
underline_button->setChecked(textEdit->fontUnderline());
font_list->setCurrentText(textEdit->fontFamily());
font_size->SetValue(textEdit->fontPointSize());
font_color->set_color(textEdit->textColor());
for (int i=0;i<font_weight->count();i++) {
if (font_weight->itemData(i).toInt() == textEdit->fontWeight()) {
font_weight->blockSignals(true);
font_weight->setCurrentIndex(i);
font_weight->blockSignals(false);
break;
}
}
Qt::Alignment align = textEdit->alignment();
left_align_button->setChecked(align == Qt::AlignLeft);
center_align_button->setChecked(align == Qt::AlignCenter);
right_align_button->setChecked(align == Qt::AlignRight);
justify_align_button->setChecked(align == Qt::AlignJustify);
}
}
+179 -179
View File
@@ -1,179 +1,179 @@
/***
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 TEXTEDITDIALOG_H
#define TEXTEDITDIALOG_H
#include <QDialog>
#include <QPlainTextEdit>
#include <QFontComboBox>
#include "ui/labelslider.h"
#include "ui/colorbutton.h"
/**
* @brief The TextEditDialog class
*
* A separate window for editing text. This window can be resized arbitrarily and also provides a toolbar for rich text
* editing (if rich text is enabled). This dialog can be run from anywhere. Once the dialog has closed (i.e. returned
* from exec() ), the text entered into it can be retrieved using get_string().
*
* TODO: Add a live signal for updating the calling function.
*/
class TextEditDialog : public QDialog {
Q_OBJECT
public:
/**
* @brief TextEditDialog Constructor
*
* @param parent
*
* QWidget parent. Usually MainWindow.
*
* @param s
*
* The starting string when the dialog opens. It'll be read as rich text HTML or plain text based on the `rich_text`
* parameter (which defaults to rich text HTML). It can also be left empty to start blank.
*
* @param rich_text
*
* Set the editing mode of the editor. If TRUE, the dialog will interpret the string in `s` as rich text HTML and also
* return rich text HTML through get_string(). It'll also show a toolbar with rich text options (i.e. font, italic,
* underline, size, etc.) If FALSE, the dialog will run in plain text mode interpreting the string in `s` as plain
* text and returning plain text through get_string(). It also will not show the rich text editing toolbar.
*/
TextEditDialog(QWidget* parent = nullptr, const QString& s = nullptr, bool rich_text = true);
/**
* @brief Retrieve the current text in the dialog
*
* This function can be called after the user has accepted the dialog (i.e. made changes and clicked OK).
* This will return either plain text or rich text (HTML) depending on the mode it's running in (rich/plain text mode
* is set in the constructor). The value this returns only gets updated when the user clicks OK so it cannot be
* used to retrieve live text updates from the dialog.
*
* @return
*
* The text entered once the user accepted this dialog.
*/
const QString& get_string();
private slots:
/**
* @brief Override of accept() to store the entered text string so it can be retrieved by get_string().
*/
virtual void accept() override;
/**
* @brief Slot for the font_weight combobox to set the font weight based on its data value
*
* @param i
*
* Index of the font_weight to retrieve the desired font weight from
*/
void SetFontWeight(int i);
/**
* @brief Slot for text alignment buttons to set alignment based on their properties
*
* Intended slot for left_align_button, center_align_button, right_align_button, and justify_align_button. Pulls
* from their property("a") value which should be a member of the Qt::Alignment enum.
*/
void SetAlignmentFromProperty();
/**
* @brief Slot for when the text edit widget's cursor moves so the rich text toolbar can stay up to date
*
* In rich text mode, different parts of a text document can be formatted in different ways. As the user moves
* around the text, the UI buttons should be consistent with whatever text is currently selected. This slot should
* therefore be connected to QTextEdit::cursorPositionChanged() and will change the "checked" state of the formatting
* buttons and current index of the comboboxes to match the currently selected text.
*/
void UpdateUIFromTextCursor();
private:
/**
* @brief Internal rich text mode value
*
* This is set in the constructor and cannot be changed during the lifetime of this dialog.
*/
bool rich_text_;
/**
* @brief Internal storage of text entered, saved when the user clicks OK
*/
QString result_str;
/**
* @brief Main text editing widget
*/
QTextEdit* textEdit;
/**
* @brief Toggle button for setting the italic state of the currently selected text
*/
QPushButton* italic_button;
/**
* @brief Toggle button for setting the underlined state of the currently selected text
*/
QPushButton* underline_button;
/**
* @brief ComboBox for the list of font families that the selected text can be set to
*/
QFontComboBox* font_list;
/**
* @brief ComboBox for the list of font weights that the selected text can be set to
*/
QComboBox* font_weight;
/**
* @brief A slider to set the current font size
*/
LabelSlider* font_size;
/**
* @brief A color selector for setting the current text color
*/
ColorButton* font_color;
/**
* @brief Button for setting the current text row(s) to left alignment
*/
QPushButton* left_align_button;
/**
* @brief Button for setting the current text row(s) to center alignment
*/
QPushButton* center_align_button;
/**
* @brief Button for setting the current text row(s) to right alignment
*/
QPushButton* right_align_button;
/**
* @brief Button for setting the current text row(s) to justified alignment
*/
QPushButton* justify_align_button;
};
#endif // TEXTEDITDIALOG_H
/***
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 TEXTEDITDIALOG_H
#define TEXTEDITDIALOG_H
#include <QDialog>
#include <QPlainTextEdit>
#include <QFontComboBox>
#include "ui/labelslider.h"
#include "ui/colorbutton.h"
/**
* @brief The TextEditDialog class
*
* A separate window for editing text. This window can be resized arbitrarily and also provides a toolbar for rich text
* editing (if rich text is enabled). This dialog can be run from anywhere. Once the dialog has closed (i.e. returned
* from exec() ), the text entered into it can be retrieved using get_string().
*
* TODO: Add a live signal for updating the calling function.
*/
class TextEditDialog : public QDialog {
Q_OBJECT
public:
/**
* @brief TextEditDialog Constructor
*
* @param parent
*
* QWidget parent. Usually MainWindow.
*
* @param s
*
* The starting string when the dialog opens. It'll be read as rich text HTML or plain text based on the `rich_text`
* parameter (which defaults to rich text HTML). It can also be left empty to start blank.
*
* @param rich_text
*
* Set the editing mode of the editor. If TRUE, the dialog will interpret the string in `s` as rich text HTML and also
* return rich text HTML through get_string(). It'll also show a toolbar with rich text options (i.e. font, italic,
* underline, size, etc.) If FALSE, the dialog will run in plain text mode interpreting the string in `s` as plain
* text and returning plain text through get_string(). It also will not show the rich text editing toolbar.
*/
TextEditDialog(QWidget* parent = nullptr, const QString& s = nullptr, bool rich_text = true);
/**
* @brief Retrieve the current text in the dialog
*
* This function can be called after the user has accepted the dialog (i.e. made changes and clicked OK).
* This will return either plain text or rich text (HTML) depending on the mode it's running in (rich/plain text mode
* is set in the constructor). The value this returns only gets updated when the user clicks OK so it cannot be
* used to retrieve live text updates from the dialog.
*
* @return
*
* The text entered once the user accepted this dialog.
*/
const QString& get_string();
private slots:
/**
* @brief Override of accept() to store the entered text string so it can be retrieved by get_string().
*/
virtual void accept() override;
/**
* @brief Slot for the font_weight combobox to set the font weight based on its data value
*
* @param i
*
* Index of the font_weight to retrieve the desired font weight from
*/
void SetFontWeight(int i);
/**
* @brief Slot for text alignment buttons to set alignment based on their properties
*
* Intended slot for left_align_button, center_align_button, right_align_button, and justify_align_button. Pulls
* from their property("a") value which should be a member of the Qt::Alignment enum.
*/
void SetAlignmentFromProperty();
/**
* @brief Slot for when the text edit widget's cursor moves so the rich text toolbar can stay up to date
*
* In rich text mode, different parts of a text document can be formatted in different ways. As the user moves
* around the text, the UI buttons should be consistent with whatever text is currently selected. This slot should
* therefore be connected to QTextEdit::cursorPositionChanged() and will change the "checked" state of the formatting
* buttons and current index of the comboboxes to match the currently selected text.
*/
void UpdateUIFromTextCursor();
private:
/**
* @brief Internal rich text mode value
*
* This is set in the constructor and cannot be changed during the lifetime of this dialog.
*/
bool rich_text_;
/**
* @brief Internal storage of text entered, saved when the user clicks OK
*/
QString result_str;
/**
* @brief Main text editing widget
*/
QTextEdit* textEdit;
/**
* @brief Toggle button for setting the italic state of the currently selected text
*/
QPushButton* italic_button;
/**
* @brief Toggle button for setting the underlined state of the currently selected text
*/
QPushButton* underline_button;
/**
* @brief ComboBox for the list of font families that the selected text can be set to
*/
QFontComboBox* font_list;
/**
* @brief ComboBox for the list of font weights that the selected text can be set to
*/
QComboBox* font_weight;
/**
* @brief A slider to set the current font size
*/
LabelSlider* font_size;
/**
* @brief A color selector for setting the current text color
*/
ColorButton* font_color;
/**
* @brief Button for setting the current text row(s) to left alignment
*/
QPushButton* left_align_button;
/**
* @brief Button for setting the current text row(s) to center alignment
*/
QPushButton* center_align_button;
/**
* @brief Button for setting the current text row(s) to right alignment
*/
QPushButton* right_align_button;
/**
* @brief Button for setting the current text row(s) to justified alignment
*/
QPushButton* justify_align_button;
};
#endif // TEXTEDITDIALOG_H