merge of long discussed new pipeline

This commit is contained in:
itsmattkc
2019-05-04 10:48:20 +10:00
382 changed files with 22362 additions and 11653 deletions
+104
View File
@@ -0,0 +1,104 @@
/***
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 "clipboard.h"
#include "timeline/clip.h"
#include "nodes/node.h"
#include "effects/transition.h"
#include "undo/undo.h"
Clipboard::Clipboard() :
type_(CLIPBOARD_TYPE_CLIP)
{
}
void Clipboard::Append(VoidPtr obj)
{
clipboard_.append(obj);
}
void Clipboard::Insert(int pos, VoidPtr obj)
{
clipboard_.insert(pos, obj);
}
void Clipboard::RemoveAt(int pos)
{
clipboard_.removeAt(pos);
}
void Clipboard::Clear()
{
clipboard_.clear();
clipboard_transitions_.clear();
}
int Clipboard::Count()
{
return clipboard_.size();
}
VoidPtr Clipboard::Get(int i)
{
return clipboard_.at(i);
}
void Clipboard::SetType(Clipboard::Type type)
{
if (type == type_) {
return;
}
Clear();
type_ = type;
}
bool Clipboard::IsEmpty()
{
return clipboard_.isEmpty();
}
Clipboard::Type Clipboard::type()
{
return type_;
}
bool Clipboard::DeleteClipsWithMedia(ComboAction *ca, Media *m)
{
if (type_ != CLIPBOARD_TYPE_CLIP) {
return false;
}
int delete_count = 0;
for (int i=0;i<clipboard_.size();i++) {
Clip* c = std::static_pointer_cast<Clip>(clipboard_.at(i)).get();
if (c->media() == m) {
ca->append(new RemoveClipsFromClipboard(i-delete_count));
delete_count++;
}
}
return (delete_count > 0);
}
Clipboard olive::clipboard;
+62
View File
@@ -0,0 +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/>.
***/
#ifndef CLIPBOARD_H
#define CLIPBOARD_H
#include <QVector>
#include "effects/transition.h"
#include "project/media.h"
using VoidPtr = std::shared_ptr<void>;
class Clipboard {
public:
enum Type {
CLIPBOARD_TYPE_CLIP,
CLIPBOARD_TYPE_EFFECT
};
Clipboard();
void Append(VoidPtr obj);
void Insert(int pos, VoidPtr obj);
void RemoveAt(int pos);
void Clear();
int Count();
VoidPtr Get(int i);
void SetType(Type type);
bool IsEmpty();
Type type();
bool DeleteClipsWithMedia(ComboAction* ca, Media* m);
private:
Type type_;
QVector<TransitionPtr> clipboard_transitions_;
QVector<VoidPtr> clipboard_;
};
namespace olive {
extern Clipboard clipboard;
}
#endif // CLIPBOARD_H
+59 -24
View File
@@ -1,20 +1,20 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
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 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.
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
@@ -29,12 +29,11 @@
#include "debug.h"
Config olive::CurrentConfig;
RuntimeConfig olive::CurrentRuntimeConfig;
Config olive::config;
RuntimeConfig olive::runtime_config;
Config::Config()
: show_track_lines(true),
scroll_zooms(false),
: scroll_zooms(false),
edit_tool_selects_links(false),
edit_tool_also_seeks(false),
select_also_seeks(false),
@@ -72,6 +71,7 @@ Config::Config()
thumbnail_resolution(120),
add_default_effects_to_clips(true),
invert_timeline_scroll_axes(true),
enable_color_management(false),
style(olive::styling::kOliveDefaultDark),
use_native_menu_styling(true),
default_sequence_width(1920),
@@ -79,6 +79,10 @@ Config::Config()
default_sequence_framerate(29.97),
default_sequence_audio_frequency(48000),
default_sequence_audio_channel_layout(3),
playback_bit_depth(olive::PIX_FMT_RGBA16F),
export_bit_depth(olive::PIX_FMT_RGBA32F),
dont_use_proxies_on_export(true),
maximum_recent_projects(10),
locked_panels(false)
{}
@@ -90,10 +94,7 @@ void Config::load(QString path) {
while (!stream.atEnd()) {
stream.readNext();
if (stream.isStartElement()) {
if (stream.name() == "ShowTrackLines") {
stream.readNext();
show_track_lines = (stream.text() == "1");
} else if (stream.name() == "ScrollZooms") {
if (stream.name() == "ScrollZooms") {
stream.readNext();
scroll_zooms = (stream.text() == "1");
} else if (stream.name() == "InvertTimelineScrollAxes") {
@@ -219,6 +220,24 @@ void Config::load(QString path) {
} else if (stream.name() == "AddDefaultEffectsToClips") {
stream.readNext();
add_default_effects_to_clips = (stream.text() == "1");
} else if (stream.name() == "EnableColorManagement") {
stream.readNext();
enable_color_management = (stream.text() == "1");
} else if (stream.name() == "OCIOConfigPath") {
stream.readNext();
ocio_config_path = stream.text().toString();
} else if (stream.name() == "OCIODisplay") {
stream.readNext();
ocio_display = stream.text().toString();
} else if (stream.name() == "OCIOView") {
stream.readNext();
ocio_view = stream.text().toString();
} else if (stream.name() == "OCIOLook") {
stream.readNext();
ocio_look = stream.text().toString();
} else if (stream.name() == "OCIODefaultInput") {
stream.readNext();
ocio_default_input_colorspace = stream.text().toString();
} else if (stream.name() == "Style") {
stream.readNext();
style = static_cast<olive::styling::Style>(stream.text().toInt());
@@ -240,6 +259,15 @@ void Config::load(QString path) {
} else if (stream.name() == "DefaultSequenceAudioLayout") {
stream.readNext();
default_sequence_audio_channel_layout = stream.text().toInt();
} else if (stream.name() == "PlaybackBitDepth") {
stream.readNext();
playback_bit_depth = stream.text().toInt();
} else if (stream.name() == "ExportBitDepth") {
stream.readNext();
export_bit_depth = stream.text().toInt();
} else if (stream.name() == "DontUseProxiesOnExport") {
stream.readNext();
dont_use_proxies_on_export = (stream.text() == "1");
} else if (stream.name() == "LockedPanels") {
stream.readNext();
locked_panels = (stream.text() == "1");
@@ -267,7 +295,6 @@ void Config::save(QString path) {
stream.writeStartElement("Configuration"); // configuration
stream.writeTextElement("Version", QString::number(olive::kSaveVersion));
stream.writeTextElement("ShowTrackLines", QString::number(show_track_lines));
stream.writeTextElement("ScrollZooms", QString::number(scroll_zooms));
stream.writeTextElement("InvertTimelineScrollAxes", QString::number(invert_timeline_scroll_axes));
stream.writeTextElement("EditToolSelectsLinks", QString::number(edit_tool_selects_links));
@@ -292,7 +319,7 @@ void Config::save(QString path) {
stream.writeTextElement("HoverFocus", QString::number(hover_focus));
stream.writeTextElement("ProjectViewType", QString::number(project_view_type));
stream.writeTextElement("SetNameWithMarker", QString::number(set_name_with_marker));
stream.writeTextElement("ShowProjectToolbar", QString::number(panel_project->IsToolbarVisible()));
stream.writeTextElement("ShowProjectToolbar", QString::number(panel_project.first()->IsToolbarVisible()));
stream.writeTextElement("PreviousFrameQueueSize", QString::number(previous_queue_size));
stream.writeTextElement("PreviousFrameQueueType", QString::number(previous_queue_type));
stream.writeTextElement("UpcomingFrameQueueSize", QString::number(upcoming_queue_size));
@@ -310,6 +337,12 @@ void Config::save(QString path) {
stream.writeTextElement("ThumbnailResolution", QString::number(thumbnail_resolution));
stream.writeTextElement("WaveformResolution", QString::number(waveform_resolution));
stream.writeTextElement("AddDefaultEffectsToClips", QString::number(add_default_effects_to_clips));
stream.writeTextElement("EnableColorManagement", QString::number(enable_color_management));
stream.writeTextElement("OCIOConfigPath", ocio_config_path);
stream.writeTextElement("OCIODisplay", ocio_display);
stream.writeTextElement("OCIOView", ocio_view);
stream.writeTextElement("OCIOLook", ocio_look);
stream.writeTextElement("OCIODefaultInput", ocio_default_input_colorspace);
stream.writeTextElement("Style", QString::number(style));
stream.writeTextElement("NativeMenuStyling", QString::number(use_native_menu_styling));
stream.writeTextElement("DefaultSequenceWidth", QString::number(default_sequence_width));
@@ -317,6 +350,9 @@ void Config::save(QString path) {
stream.writeTextElement("DefaultSequenceFrameRate", QString::number(default_sequence_framerate));
stream.writeTextElement("DefaultSequenceAudioFrequency", QString::number(default_sequence_audio_frequency));
stream.writeTextElement("DefaultSequenceAudioLayout", QString::number(default_sequence_audio_channel_layout));
stream.writeTextElement("PlaybackBitDepth", QString::number(playback_bit_depth));
stream.writeTextElement("ExportBitDepth", QString::number(export_bit_depth));
stream.writeTextElement("DontUseProxiesOnExport", QString::number(dont_use_proxies_on_export));
stream.writeTextElement("LockedPanels", QString::number(locked_panels));
stream.writeEndElement(); // configuration
@@ -325,6 +361,5 @@ void Config::save(QString path) {
}
RuntimeConfig::RuntimeConfig() :
shaders_are_enabled(true),
disable_blending(false)
shaders_are_enabled(true)
{}
+78 -29
View File
@@ -1,20 +1,20 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
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 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.
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
@@ -24,6 +24,7 @@
#include <QString>
#include "ui/styling.h"
#include "timeline/timelinetools.h"
namespace olive {
/**
@@ -159,13 +160,6 @@ struct Config {
*/
Config();
/**
* @brief Show track lines
*
* **TRUE** if the Timeline should show lines between tracks.
*/
bool show_track_lines;
/**
* @brief The scroll wheel zooms rather than scrolls
*
@@ -519,6 +513,48 @@ struct Config {
*/
bool invert_timeline_scroll_axes;
/**
* @brief Enable color managemennt
*
* **TRUE** if color management through OpenColorIO should be enabled
*/
bool enable_color_management;
/**
* @brief Path to OpenColorIO configuration file
*
* Used if Config::enable_color_management is true.
*/
QString ocio_config_path;
/**
* @brief OpenColorIO Display
*
* Used if Config::enable_color_management is true
*/
QString ocio_display;
/**
* @brief OpenColorIO View
*
* Used if Config::enable_color_management is true
*/
QString ocio_view;
/**
* @brief OpenColorIO Look
*
* Used if Config::enable_color_management is true
*/
QString ocio_look;
/**
* @brief OpenColorIO Default Input Colorspace
*
* The colorspace to default to if no colorspace can be determined from the filename or a manual setting.
*/
QString ocio_default_input_colorspace;
/**
* @brief Style to use when theming Olive.
*
@@ -558,6 +594,26 @@ struct Config {
*/
int default_sequence_audio_channel_layout;
/**
* @brief Playback bit depth (an index of olive::rendering::bit_depths)
*/
int playback_bit_depth;
/**
* @brief Export bit depth (an index of olive::rendering::bit_depths)
*/
int export_bit_depth;
/**
* @brief Don't use proxies on export (use originals instead)
*/
bool dont_use_proxies_on_export;
/**
* @brief The maximum amount of recent projects stored in the Open Recent list
*/
int maximum_recent_projects;
/**
* @brief Sets whether panels should load locked or not
*/
@@ -607,25 +663,18 @@ struct RuntimeConfig {
*/
bool shaders_are_enabled;
/**
* @brief Disable blending modes
*
* Some users had difficulty utilizing blending modes (provided by shaders). Set this to **TRUE** to bypass
* shader-based blending modes and utilize standard (less versatile) OpenGL blending instead.
*/
bool disable_blending;
/**
* @brief Load an external translation file
*
* Overrides Config::language_file and sets the path to a language file to use.
*/
QString external_translation_file;
};
namespace olive {
extern Config CurrentConfig;
extern RuntimeConfig CurrentRuntimeConfig;
extern Config config;
extern RuntimeConfig runtime_config;
}
#endif // CONFIG_H
+64
View File
@@ -0,0 +1,64 @@
/***
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 "crossplatformlib.h"
#include <QDebug>
ModulePtr LibLoad(const QString &filename) {
#ifdef _WIN32
LPCWSTR dll_fn_w = reinterpret_cast<const wchar_t*>(filename.utf16());
return LoadLibrary(dll_fn_w);
#elif defined(__linux__) || defined(__APPLE__) || defined(__HAIKU__)
return dlopen(filename.toUtf8(), RTLD_LAZY);
#else
qWarning() << "Olive doesn't know how to open dynamic libraries on this platform, external libraries will not be functional";
return nullptr;
#endif
}
QStringList LibFilter() {
#ifdef _WIN32
return QStringList("*.dll");
#elif defined(__linux__) || defined(__APPLE__) || defined(__HAIKU__)
return {"*.so", "*.dylib"};
#endif
}
#ifdef __APPLE__
CFBundleRef BundleLoad(const QString &filename) {
CFStringRef bundle_str = CFStringCreateWithCString(NULL, filename.toUtf8(), kCFStringEncodingUTF8);
CFURLRef bundle_url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, bundle_str, kCFURLPOSIXPathStyle, true);
CFBundleRef bundle = NULL;
if (bundle_url != NULL) {
bundle = CFBundleCreate(kCFAllocatorDefault, bundle_url);
} else {
qCritical() << "Failed to create VST URL";
}
CFRelease(bundle_url);
CFRelease(bundle_str);
return bundle;
}
void BundleClose(CFBundleRef bundle) {
CFBundleUnloadExecutable(bundle);
CFRelease(bundle);
}
#endif
+49
View File
@@ -0,0 +1,49 @@
/***
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 CROSSPLATFORMLIB_H
#define CROSSPLATFORMLIB_H
#include <QString>
#ifdef _WIN32
#include <Windows.h>
#define LibAddress GetProcAddress
#define LibClose FreeModule
#define ModulePtr HMODULE
#elif defined(__linux__) || defined(__APPLE__) || defined(__HAIKU__)
#include <dlfcn.h>
#define LibAddress dlsym
#define LibClose dlclose
#define ModulePtr void*
#endif
ModulePtr LibLoad(const QString& filename);
QStringList LibFilter();
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
class NSWindow;
CFBundleRef BundleLoad(const QString& filename);
void BundleClose(CFBundleRef bundle);
#endif
#endif // CROSSPLATFORMLIB_H
+12 -12
View File
@@ -1,20 +1,20 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
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 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.
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
+12 -12
View File
@@ -1,20 +1,20 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
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 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.
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
+409 -51
View File
@@ -1,20 +1,20 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
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 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.
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
@@ -30,6 +30,8 @@
#include "panels/panels.h"
#include "global/path.h"
#include "global/config.h"
#include "global/timing.h"
#include "global/clipboard.h"
#include "rendering/audio.h"
#include "dialogs/demonotice.h"
#include "dialogs/preferencesdialog.h"
@@ -38,12 +40,16 @@
#include "dialogs/aboutdialog.h"
#include "dialogs/speeddialog.h"
#include "dialogs/actionsearch.h"
#include "dialogs/newsequencedialog.h"
#include "dialogs/loaddialog.h"
#include "dialogs/autocutsilencedialog.h"
#include "effects/effectloaders.h"
#include "project/loadthread.h"
#include "project/savethread.h"
#include "timeline/sequence.h"
#include "ui/mediaiconservice.h"
#include "ui/mainwindow.h"
#include "ui/menu.h"
#include "ui/updatenotification.h"
#include "undo/undostack.h"
@@ -52,7 +58,8 @@ QString olive::ActiveProjectFilename;
QString olive::AppName;
OliveGlobal::OliveGlobal() :
changed_since_last_autorecovery(false)
changed_since_last_autorecovery(false),
rendering_(false)
{
// sets current app name
QString version_id;
@@ -108,8 +115,13 @@ void OliveGlobal::check_for_autorecovery_file() {
}
}
void OliveGlobal::set_rendering_state(bool rendering) {
audio_rendering = rendering;
bool OliveGlobal::is_exporting()
{
return rendering_;
}
void OliveGlobal::set_export_state(bool rendering) {
rendering_ = rendering;
if (rendering) {
autorecovery_timer.stop();
} else {
@@ -138,12 +150,12 @@ QString OliveGlobal::get_recent_project_list_file() {
}
void OliveGlobal::load_translation_from_config() {
QString language_file = olive::CurrentRuntimeConfig.external_translation_file.isEmpty() ?
olive::CurrentConfig.language_file :
olive::CurrentRuntimeConfig.external_translation_file;
QString language_file = olive::runtime_config.external_translation_file.isEmpty() ?
olive::config.language_file :
olive::runtime_config.external_translation_file;
// clear runtime language file so if the user sets a different language, we won't load it next time
olive::CurrentRuntimeConfig.external_translation_file.clear();
olive::runtime_config.external_translation_file.clear();
// remove current translation if there is one
QApplication::removeTranslator(translator.get());
@@ -169,16 +181,71 @@ void OliveGlobal::SetNativeStyling(QWidget *w)
w->setStyleSheet("");
w->setPalette(w->style()->standardPalette());
w->setStyle(QStyleFactory::create("windowsvista"));
#else
Q_UNUSED(w)
#endif
}
void OliveGlobal::add_recent_project(const QString &url)
{
bool found = false;
for (int i=0;i<recent_projects.size();i++) {
if (url == recent_projects.at(i)) {
found = true;
recent_projects.move(i, 0);
break;
}
}
if (!found) {
recent_projects.prepend(url);
if (recent_projects.size() > olive::config.maximum_recent_projects) {
recent_projects.removeLast();
}
}
save_recent_projects();
}
void OliveGlobal::load_recent_projects()
{
QFile f(get_recent_project_list_file());
if (f.exists() && f.open(QFile::ReadOnly | QFile::Text)) {
QTextStream text_stream(&f);
while (true) {
QString line = text_stream.readLine();
if (line.isNull()) {
break;
} else {
recent_projects.append(line);
}
}
f.close();
}
}
int OliveGlobal::recent_project_count()
{
return recent_projects.size();
}
const QString &OliveGlobal::recent_project(int index)
{
return recent_projects.at(index);
}
const QString &OliveGlobal::get_autorecovery_filename()
{
return autorecovery_filename;
}
void OliveGlobal::LoadProject(const QString &fn, bool autorecovery)
{
// QSortFilterProxyModels are not thread-safe, and as we'll be loading in another thread, leaving it connected
// can cause glitches in its presentation. Therefore for the duration of the loading process, we disconnect it,
// and reconnect it later once the loading is complete.
panel_project->DisconnectFilterToModel();
for (int i=0;i<panel_project.size();i++) {
panel_project.at(i)->DisconnectFilterToModel();
}
LoadDialog ld(olive::MainWindow);
@@ -192,7 +259,9 @@ void OliveGlobal::LoadProject(const QString &fn, bool autorecovery)
connect(lt, SIGNAL(report_progress(int)), &ld, SLOT(setValue(int)));
lt->start();
panel_project->ConnectFilterToModel();
for (int i=0;i<panel_project.size();i++) {
panel_project.at(i)->ConnectFilterToModel();
}
}
void OliveGlobal::ClearProject()
@@ -204,14 +273,20 @@ void OliveGlobal::ClearProject()
panel_effect_controls->Clear(true);
// clear existing project
olive::Global->set_sequence(nullptr);
Timeline::CloseAll();
panel_footage_viewer->set_media(nullptr);
// delete sequences first because it's important to close all the clips before deleting the media
QVector<Media*> sequences = olive::project_model.GetAllSequences();
for (int i=0;i<sequences.size();i++) {
sequences.at(i)->set_sequence(nullptr);
}
// clear project contents (footage, sequences, etc.)
panel_project->clear();
olive::project_model.clear();
// clear undo stack
olive::UndoStack.clear();
olive::undo_stack.clear();
// empty current project filename
update_project_filename("");
@@ -220,7 +295,195 @@ void OliveGlobal::ClearProject()
update_ui(false);
// set to unmodified
olive::Global->set_modified(false);
set_modified(false);
}
void OliveGlobal::save_recent_projects()
{
// save to file
QFile f(get_recent_project_list_file());
if (f.open(QFile::WriteOnly | QFile::Truncate | QFile::Text)) {
QTextStream out(&f);
for (int i=0;i<recent_projects.size();i++) {
if (i > 0) {
out << "\n";
}
out << recent_projects.at(i);
}
f.close();
} else {
qWarning() << "Could not save recent projects";
}
}
void OliveGlobal::PasteInternal(Sequence *s, bool insert)
{
if (s == nullptr) {
return;
}
if (!olive::clipboard.IsEmpty()) {
if (olive::clipboard.type() == Clipboard::CLIPBOARD_TYPE_CLIP) {
ComboAction* ca = new ComboAction();
// create copies and delete areas that we'll be pasting to
QVector<Selection> delete_areas;
QVector<Clip*> original_clips;
QVector<ClipPtr> pasted_clips;
long paste_start = LONG_MAX;
long paste_end = LONG_MIN;
for (int i=0;i<olive::clipboard.Count();i++) {
ClipPtr c = std::static_pointer_cast<Clip>(olive::clipboard.Get(i));
// create copy of clip and offset by playhead
ClipPtr cc = c->copy(s->GetTrackList(c->track()->type())->TrackAt(c->track()->Index()));
// convert frame rates
cc->set_timeline_in(rescale_frame_number(cc->timeline_in(), c->cached_frame_rate(), s->frame_rate));
cc->set_timeline_out(rescale_frame_number(cc->timeline_out(), c->cached_frame_rate(), s->frame_rate));
cc->set_clip_in(rescale_frame_number(cc->clip_in(), c->cached_frame_rate(), s->frame_rate));
cc->set_timeline_in(cc->timeline_in() + s->playhead);
cc->set_timeline_out(cc->timeline_out() + s->playhead);
cc->set_track(c->track());
paste_start = qMin(paste_start, cc->timeline_in());
paste_end = qMax(paste_end, cc->timeline_out());
original_clips.append(c.get());
pasted_clips.append(cc);
if (!insert) {
delete_areas.append(Selection(cc->timeline_in(), cc->timeline_out(), c->track()));
}
}
if (insert) {
s->SplitAllClipsAtPoint(ca, s->playhead);
s->Ripple(ca, paste_start, paste_end - paste_start);
} else {
s->DeleteAreas(ca, delete_areas, false);
}
// correct linked clips
olive::timeline::RelinkClips(original_clips, pasted_clips);
ca->append(new AddClipCommand(pasted_clips));
olive::undo_stack.push(ca);
update_ui(true);
if (olive::config.paste_seeks) {
panel_sequence_viewer->seek(paste_end);
}
} else if (olive::clipboard.type() == Clipboard::CLIPBOARD_TYPE_EFFECT) {
ComboAction* ca = new ComboAction();
bool replace = false;
bool skip = false;
bool ask_conflict = true;
QVector<Clip*> selected_clips = s->SelectedClips();
for (int i=0;i<selected_clips.size();i++) {
Clip* c = selected_clips.at(i);
for (int j=0;j<olive::clipboard.Count();j++) {
NodePtr e = std::static_pointer_cast<Node>(olive::clipboard.Get(j));
if (c->type() == e->subtype()) {
int found = -1;
if (ask_conflict) {
replace = false;
skip = false;
}
for (int k=0;k<c->effects.size();k++) {
if (c->effects.at(k)->id() == e->id()) {
found = k;
break;
}
}
if (found >= 0 && ask_conflict) {
QMessageBox box(olive::MainWindow);
box.setWindowTitle(tr("Effect already exists"));
box.setText(tr("Clip '%1' already contains a '%2' effect. "
"Would you like to replace it with the pasted one or add it as a separate effect?")
.arg(c->name(), e->name()));
box.setIcon(QMessageBox::Icon::Question);
box.addButton(tr("Add"), QMessageBox::YesRole);
QPushButton* replace_button = box.addButton(tr("Replace"), QMessageBox::NoRole);
QPushButton* skip_button = box.addButton(tr("Skip"), QMessageBox::RejectRole);
QCheckBox* future_box = new QCheckBox(tr("Do this for all conflicts found"), &box);
box.setCheckBox(future_box);
box.exec();
if (box.clickedButton() == replace_button) {
replace = true;
} else if (box.clickedButton() == skip_button) {
skip = true;
}
ask_conflict = !future_box->isChecked();
}
if (found >= 0 && skip) {
// do nothing
} else if (found >= 0 && replace) {
ca->append(new EffectDeleteCommand(c->effects.at(found).get()));
ca->append(new AddEffectCommand(c, e->copy(c), kInvalidNode, found));
} else {
ca->append(new AddEffectCommand(c, e->copy(c), kInvalidNode));
}
}
}
}
if (ca->hasActions()) {
ca->appendPost(new ReloadEffectsCommand());
olive::undo_stack.push(ca);
} else {
delete ca;
}
update_ui(true);
}
}
}
void OliveGlobal::EffectMenuAction(QAction *q)
{
ComboAction* ca = new ComboAction();
NodeType node_type = static_cast<NodeType>(q->data().toInt());
Node* n = olive::node_library[node_type].get();
for (int i=0;i<effect_menu_selected_clips.size();i++) {
Clip* c = effect_menu_selected_clips.at(i);
if (c->type() == n->subtype()) {
if (n->type() == EFFECT_TYPE_TRANSITION) {
if (c->opening_transition == nullptr) {
ca->append(new AddTransitionCommand(c,
nullptr,
nullptr,
node_type,
olive::config.default_transition_length));
}
if (c->closing_transition == nullptr) {
ca->append(new AddTransitionCommand(nullptr,
c,
nullptr,
node_type,
olive::config.default_transition_length));
}
} else {
ca->append(new AddEffectCommand(c, nullptr, node_type));
}
}
}
olive::undo_stack.push(ca);
update_ui(true);
}
void OliveGlobal::ImportProject(const QString &fn)
@@ -251,7 +514,7 @@ void OliveGlobal::open_recent(int index) {
tr("The project '%1' no longer exists. Would you like to remove it from the recent projects list?").arg(recent_url),
QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) {
recent_projects.removeAt(index);
panel_project->save_recent_projects();
save_recent_projects();
}
} else if (can_close_project()) {
OpenProjectWorker(recent_url, false);
@@ -265,7 +528,7 @@ bool OliveGlobal::save_project_as() {
fn += ".ove";
}
update_project_filename(fn);
panel_project->save_project(false);
olive::Save(false);
return true;
}
return false;
@@ -275,7 +538,7 @@ bool OliveGlobal::save_project() {
if (olive::ActiveProjectFilename.isEmpty()) {
return save_project_as();
} else {
panel_project->save_project(false);
olive::Save(false);
return true;
}
}
@@ -301,9 +564,36 @@ bool OliveGlobal::can_close_project() {
return true;
}
void OliveGlobal::open_new_sequence_dialog()
{
NewSequenceDialog nsd(olive::MainWindow);
nsd.set_sequence_name(olive::project_model.GetNextSequenceName());
nsd.exec();
}
void OliveGlobal::open_import_dialog()
{
QFileDialog fd(olive::MainWindow, tr("Import media..."), "", tr("All Files") + " (*)");
fd.setFileMode(QFileDialog::ExistingFiles);
if (fd.exec()) {
QStringList files = fd.selectedFiles();
Media* parent = nullptr;
for (int i=0;i<panel_project.size();i++) {
if (panel_project.at(i)->focused()) {
parent = panel_project.at(i)->get_selected_folder();
break;
}
}
olive::project_model.process_file_list(files, false, nullptr, parent);
}
}
void OliveGlobal::open_export_dialog() {
if (CheckForActiveSequence()) {
ExportDialog e(olive::MainWindow);
ExportDialog e(olive::MainWindow, Timeline::GetTopSequence().get());
e.exec();
}
}
@@ -339,7 +629,7 @@ void OliveGlobal::finished_initialize() {
void OliveGlobal::save_autorecovery_file() {
if (changed_since_last_autorecovery) {
panel_project->save_project(true);
olive::Save(true);
changed_since_last_autorecovery = false;
@@ -355,27 +645,28 @@ void OliveGlobal::open_preferences() {
pd.exec();
}
void OliveGlobal::set_sequence(SequencePtr s)
void OliveGlobal::PrimarySequenceChanged()
{
panel_graph_editor->set_row(nullptr);
panel_effect_controls->Clear(true);
}
olive::ActiveSequence = s;
panel_sequence_viewer->set_main_sequence();
panel_timeline->update_sequence();
panel_timeline->setFocus();
void OliveGlobal::clear_recent_projects()
{
recent_projects.clear();
save_recent_projects();
}
void OliveGlobal::OpenProjectWorker(QString fn, bool autorecovery) {
ClearProject();
update_project_filename(fn);
LoadProject(fn, autorecovery);
olive::UndoStack.clear();
olive::undo_stack.clear();
}
bool OliveGlobal::CheckForActiveSequence(bool show_msg)
{
if (olive::ActiveSequence == nullptr) {
if (Timeline::GetTopSequence() == nullptr) {
if (show_msg) {
QMessageBox::information(olive::MainWindow,
@@ -389,32 +680,99 @@ bool OliveGlobal::CheckForActiveSequence(bool show_msg)
return true;
}
void OliveGlobal::ShowEffectMenu(EffectType type, olive::TrackType subtype, const QVector<Clip*> selected_clips)
{
effect_menu_selected_clips = selected_clips;
olive::effects_loaded.lock();
Menu effects_menu(olive::MainWindow);
effects_menu.setToolTipsVisible(true);
for (int i=0;i<olive::node_library.size();i++) {
NodePtr node = olive::node_library.at(i);
if (node != nullptr && node->type() == type && node->subtype() == subtype) {
QAction* action = new QAction(&effects_menu);
action->setText(node->name());
action->setData(i);
if (!node->description().isEmpty()) {
action->setToolTip(node->description());
}
QMenu* parent = &effects_menu;
if (!node->category().isEmpty()) {
bool found = false;
for (int j=0;j<effects_menu.actions().size();j++) {
QAction* action = effects_menu.actions().at(j);
if (action->menu() != nullptr) {
if (action->menu()->title() == node->category()) {
parent = action->menu();
found = true;
break;
}
}
}
if (!found) {
parent = new Menu(&effects_menu);
parent->setToolTipsVisible(true);
parent->setTitle(node->category());
bool found = false;
for (int i=0;i<effects_menu.actions().size();i++) {
QAction* comp_action = effects_menu.actions().at(i);
if (comp_action->text() > node->category()) {
effects_menu.insertMenu(comp_action, parent);
found = true;
break;
}
}
if (!found) effects_menu.addMenu(parent);
}
}
bool found = false;
for (int i=0;i<parent->actions().size();i++) {
QAction* comp_action = parent->actions().at(i);
if (comp_action->text() > action->text()) {
parent->insertAction(comp_action, action);
found = true;
break;
}
}
if (!found) parent->addAction(action);
}
}
olive::effects_loaded.unlock();
connect(&effects_menu, SIGNAL(triggered(QAction*)), this, SLOT(EffectMenuAction(QAction*)));
effects_menu.exec(QCursor::pos());
}
void OliveGlobal::undo() {
// workaround to prevent crash (and also users should never need to do this)
if (!panel_timeline->importing) {
olive::UndoStack.undo();
if (!Timeline::IsImporting()) {
olive::undo_stack.undo();
update_ui(true);
}
}
void OliveGlobal::redo() {
// workaround to prevent crash (and also users should never need to do this)
if (!panel_timeline->importing) {
olive::UndoStack.redo();
if (!Timeline::IsImporting()) {
olive::undo_stack.redo();
update_ui(true);
}
}
void OliveGlobal::paste() {
if (olive::ActiveSequence != nullptr) {
panel_timeline->paste(false);
}
PasteInternal(Timeline::GetTopSequence().get(), false);
}
void OliveGlobal::paste_insert() {
if (olive::ActiveSequence != nullptr) {
panel_timeline->paste(true);
}
PasteInternal(Timeline::GetTopSequence().get(), true);
}
void OliveGlobal::open_about_dialog() {
@@ -427,9 +785,9 @@ void OliveGlobal::open_debug_log() {
}
void OliveGlobal::open_speed_dialog() {
if (olive::ActiveSequence != nullptr) {
if (Timeline::GetTopSequence() != nullptr) {
QVector<Clip*> selected_clips = olive::ActiveSequence->SelectedClips();
QVector<Clip*> selected_clips = Timeline::GetTopSequence()->SelectedClips();
if (!selected_clips.isEmpty()) {
SpeedDialog s(olive::MainWindow, selected_clips);
@@ -441,7 +799,7 @@ void OliveGlobal::open_speed_dialog() {
void OliveGlobal::open_autocut_silence_dialog() {
if (CheckForActiveSequence()) {
QVector<int> selected_clips = olive::ActiveSequence->SelectedClipIndexes();
QVector<Clip*> selected_clips = Timeline::GetTopSequence()->SelectedClips();
if (selected_clips.isEmpty()) {
QMessageBox::critical(olive::MainWindow,
@@ -457,7 +815,7 @@ void OliveGlobal::open_autocut_silence_dialog() {
}
void OliveGlobal::clear_undo_stack() {
olive::UndoStack.clear();
olive::undo_stack.clear();
}
void OliveGlobal::open_action_search() {
+231 -122
View File
@@ -1,20 +1,20 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
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 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.
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
@@ -34,23 +34,23 @@
* A resource for various global functions used throughout Olive.
*/
class OliveGlobal : public QObject {
Q_OBJECT
Q_OBJECT
public:
/**
/**
* @brief OliveGlobal Constructor
*
* Creates Olive Global object. Also sets some default runtime settings and the application name.
*/
OliveGlobal();
OliveGlobal();
/**
/**
* @brief Returns the file dialog filter used when interfacing with Olive project files.
*
* @return The file filter string used by QFileDialog to limit the files shown to Olive (*.ove) files.
*/
const QString& get_project_file_filter();
const QString& get_project_file_filter();
/**
/**
* @brief Change the current active project filename
*
* Triggered to change the current active project filename. Call this before calling any internal project
@@ -63,18 +63,28 @@ public:
* The URL of the project file to work with. Can be an empty string, in which case Olive will treat the project
* as an unsaved project.
*/
void update_project_filename(const QString& s);
void update_project_filename(const QString& s);
/**
/**
* @brief Check whether an auto-recovery file exists and ask the user if they want to load it.
*
* Usually called on initialization. Checks if an auto-recovery file exists (meaning the last session of Olive
* didn't close correctly). If it finds one, asks the user if they want to load it. If so, loads the auto-recovery
* project.
*/
void check_for_autorecovery_file();
void check_for_autorecovery_file();
/**
/**
* @brief Get whether the project is currently being rendered or not. Useful for determining whether to treat the
* render as online or offline.
*
* @return
*
* TRUE if the project is being exported, FALSE if not.
*/
bool is_exporting();
/**
* @brief Set the application state depending on if the user is exporting a video
*
* Some background functions shouldn't run while Olive is exporting a video. This function will disable/enable them
@@ -90,9 +100,9 @@ public:
*
* **TRUE** if Olive is about to export a video. **FALSE** if Olive has finished exporting.
*/
void set_rendering_state(bool rendering);
void set_export_state(bool rendering);
/**
/**
* @brief Set the application's "modified" state
*
* Primarily controls whether the application prompts the user to save the project upon closing or not. Also
@@ -103,9 +113,9 @@ public:
*
* TRUE if the project has been modified, FALSE if it has not.
*/
void set_modified(bool modified);
void set_modified(bool modified);
/**
/**
* @brief Get application's current "modified" state
*
* Currently just a wrapper around MainWindow::isWindowModified(), but use this instead in case it changes.
@@ -115,9 +125,9 @@ public:
*
* TRUE if the project has been modified since the last save.
*/
bool is_modified();
bool is_modified();
/**
/**
* @brief Set a project to load just after launching
*
* Called by main() if Olive was called with a project file as a running argument. Sets up Olive to load the
@@ -127,49 +137,109 @@ public:
*
* The URL of the project file to load.
*/
void load_project_on_launch(const QString& s);
void load_project_on_launch(const QString& s);
/**
/**
* @brief Retrieves the URL of the config file containing the autorecovery projects
* @return The URL as a string
*/
QString get_recent_project_list_file();
QString get_recent_project_list_file();
/**
/**
* @brief (Re)load translation file from olive::config
*/
void load_translation_from_config();
void load_translation_from_config();
/**
/**
* @brief Set native UI styling on a given widget
*
* @param w
*
* The widget to set styling on.
*/
static void SetNativeStyling(QWidget* w);
static void SetNativeStyling(QWidget* w);
/**
* @brief Adds a project URL to the recent projects list
*
* @param url
*
* The project URL to add
*/
void add_recent_project(const QString& url);
/**
* @brief Load recent projects from file
*
* Should be called on application startup.
*/
void load_recent_projects();
/**
* @brief Total count of recent projects
*
* @return
*
* Number of recent projects in the list
*/
int recent_project_count();
/**
* @brief Get the recent project at a given index
*
* @param index
*
* @return
*
* The recent project at index
*/
const QString& recent_project(int index);
/**
* @brief Retrieves the filename of the autorecovery file to save to during this session
*
* @return
*
* A URL pointing to the autorecovery file
*/
const QString& get_autorecovery_filename();
/**
* @brief Returns whether a Sequence is currently active or not, and optionally displays a messagebox if not
*
* Checks whether a Sequence is active and can display a messagebox if not to inform users to make one active in
* order to perform said action.
*
* @return
*
* TRUE if there is an active Sequence, FALSE if not.
*/
bool CheckForActiveSequence(bool show_msg = true);
void ShowEffectMenu(EffectType type, olive::TrackType subtype, const QVector<Clip*> selected_clips);
public slots:
/**
/**
* @brief Undo user's last action
*/
void undo();
void undo();
/**
/**
* @brief Redo user's last action
*/
void redo();
void redo();
/**
/**
* @brief Paste contents of clipboard
*
* Pastes contents of clipboard. Seeing as several types of data can be copied into the clipboard, this
* function will automatically determine what type of data is in the clipboard and paste it in the correct
* location (e.g. clip data will go to the Timeline, effect data will go to Effect Controls).
*/
void paste();
void paste();
/**
/**
* @brief Paste contents of clipboard, making space for it when possible
*
* Pastes contents of clipboard (same as paste()). If the clipboard contains clip data, the clips are cut at the
@@ -177,25 +247,25 @@ public slots:
* semi-non-destructive as a result (as opposed to paste() overwriting clips). If the clipboard contains effect
* data, the functionality is identical to paste().
*/
void paste_insert();
void paste_insert();
/**
/**
* @brief Create new project.
*
* Confirms whether the current project can be closed, and if so, clears all current project data and resets
* program state. Standard `File > New` behavior.
*/
void new_project();
void new_project();
/**
/**
* @brief Open a project from file.
*
* Confirms whether the current project can be closed, and if so, shows an open file dialog to allow the user to
* select a project file and then triggers a project load with it.
*/
void OpenProject();
void OpenProject();
/**
/**
* @brief Import project from file
*
* Imports an Olive project into the current project, effectively merging them.
@@ -204,9 +274,9 @@ public slots:
*
* The filename of the project to import.
*/
void ImportProject(const QString& fn);
void ImportProject(const QString& fn);
/**
/**
* @brief Open recent project from list
*
* Triggers a project load from the internal recent projects list.
@@ -215,9 +285,9 @@ public slots:
*
* Index in the list of the project file to load
*/
void open_recent(int index);
void open_recent(int index);
/**
/**
* @brief Shows a save file dialog and saves the project as the resulting filename
*
* Shows a save file dialog for the user to save their current project as a different filename from the current
@@ -227,9 +297,9 @@ public slots:
* if a user is closing an unsaved project, clicks "Yes" to save, we know if they actually saved or not and won't
* continue closing the project if they didn't.
*/
bool save_project_as();
bool save_project_as();
/**
/**
* @brief Saves the current project to file
*
* If the project has been saved already, this function will overwrite the project file with the current project
@@ -239,9 +309,9 @@ public slots:
* value of save_project_as(). Useful if the user closing an unsaved project, clicks "Yes" to save, we know if they
* actually saved or not and won't continue closing the project if they didn't.
*/
bool save_project();
bool save_project();
/**
/**
* @brief Determine whether the current project can be closed.
*
* Queried any time the current project is going to be closed (e.g. starting a new project, loading a project,
@@ -253,81 +323,93 @@ public slots:
* returns **TRUE**. If it does and the user clicks YES, this returns the result of save_project(). If the user
* clicks NO, this returns **TRUE**. If the user clicks CANCEL, this returns **FALSE**.
*/
bool can_close_project();
bool can_close_project();
/**
/**
* @brief Opens the NewSequenceDialog to create a new Sequence
*/
void open_new_sequence_dialog();
/**
* @brief Open a file dialog for importing files into the project
*/
void open_import_dialog();
/**
* @brief Open the Export dialog to trigger an export of the current sequence.
*/
void open_export_dialog();
void open_export_dialog();
/**
/**
* @brief Open the About Olive dialog.
*/
void open_about_dialog();
void open_about_dialog();
/**
/**
* @brief Open the Debug Log window.
*/
void open_debug_log();
void open_debug_log();
/**
/**
* @brief Open the Speed/Duration dialog.
*/
void open_speed_dialog();
void open_speed_dialog();
/**
/**
* @brief Open the auto-cut silence dialog.
*/
void open_autocut_silence_dialog();
void open_autocut_silence_dialog();
/**
/**
* @brief Open the Action Search overlay.
*/
void open_action_search();
void open_action_search();
/**
/**
* @brief Clears the current undo stack.
*
* Clears all current commands in the undo stack. Mostly used for debugging.
*/
void clear_undo_stack();
void clear_undo_stack();
/**
/**
* @brief Function called when Olive has finished starting up
*
* Sets up some last things for Olive that must be run after Olive has completed initialization. If a project was
* loaded as a command line argument, it's loaded here.
*/
void finished_initialize();
void finished_initialize();
/**
/**
* @brief Save an auto-recovery file of the current project.
*
* Call this function to save the current state of the project as an auto-recovery project. Called regularly by
* `autorecovery_timer`.
*/
void save_autorecovery_file();
void save_autorecovery_file();
/**
/**
* @brief Opens the Preferences dialog
*/
void open_preferences();
void open_preferences();
/**
* @brief Set the current active Sequence
/**
* @brief Clear the recent projects list
*
* Call this to change the active Sequence (e.g. when the user double clicks a Sequence in the Project panel).
* This will affect panel_timeline, panel_sequence_viewer, and panel_effect_controls and can then be retrieved
* using olive::ActiveSequence.
*
* @param s
*
* The Sequence to set as the active Sequence.
* Also saves the cleared recent projects to the config file making it permanent.
*/
void set_sequence(SequencePtr s);
void clear_recent_projects();
/**
* @brief Slot for when the primary sequence has changed.
*
* Usually by opening a sequence or bringing a corresponding
* Timeline widget on top.
*/
void PrimarySequenceChanged();
private:
/**
/**
* @brief Internal function to handle loading a project from file
*
* Start loading a project. Doesn't check if the current project can be closed, doesn't check if the project exists.
@@ -343,21 +425,9 @@ private:
* beside the original project file so that it does not overwrite the original and so that the user is not working
* on the autorecovery project in Olive's application data directory.
*/
void OpenProjectWorker(QString fn, bool autorecovery);
void OpenProjectWorker(QString fn, bool autorecovery);
/**
* @brief Returns whether a Sequence is currently active or not, and optionally displays a messagebox if not
*
* Checks whether a Sequence is active and can display a messagebox if not to inform users to make one active in
* order to perform said action.
*
* @return
*
* TRUE if there is an active Sequence, FALSE if not.
*/
bool CheckForActiveSequence(bool show_msg = true);
/**
/**
* @brief Create a LoadDialog and start a LoadThread to load data from a project
*
* Loads data from an Olive project file creating a LoadDialog to show visual information and a LoadThread to load
@@ -383,37 +453,49 @@ private:
* TRUE if the current project should be closed before opening, FALSE if the project should be imported into the
* currently open one.
*/
void LoadProject(const QString& fn, bool autorecovery);
void LoadProject(const QString& fn, bool autorecovery);
/**
/**
* @brief Indiscriminately clear the project without prompting the user
*
* Will clear the entire project without prompting to save. This is dangerous, use new_project() instead for
* anything initiated by the user.
*/
void ClearProject();
void ClearProject();
/**
/**
* @brief Saves current recent project list to the configuration file
*
* This should be called whenever the recent projects change so the changes can be persistent.
*/
void save_recent_projects();
/**
* @brief Internal pasting function
*/
void PasteInternal(Sequence* s, bool insert);
/**
* @brief File filter used for any file dialogs relating to Olive project files.
*/
QString project_file_filter;
QString project_file_filter;
/**
/**
* @brief Regular interval to save an auto-recovery project.
*/
QTimer autorecovery_timer;
QTimer autorecovery_timer;
/**
/**
* @brief Internal variable set to **TRUE** by main() if a project file was set as an argument
*/
bool enable_load_project_on_init;
bool enable_load_project_on_init;
/**
/**
* @brief Internal translator object that interfaces with the currently loaded language file
*/
std::unique_ptr<QTranslator> translator;
std::unique_ptr<QTranslator> translator;
/**
/**
* @brief Internal variable for whether the project has changed since the last autorecovery
*
* Set by set_modified(), which should be called alongside any change made to the project file and is "unset" when
@@ -421,30 +503,57 @@ private:
* prevents an autorecovery file saving multiple times if the project hasn't actually changed since the last
* autorecovery, but still hasn't been saved into the original file yet.
*/
bool changed_since_last_autorecovery;
bool changed_since_last_autorecovery;
/**
* @brief Internal variable for rendering state (set by set_rendering_state() and accessed by is_rendering() ).
*/
bool rendering_;
/**
* @brief Internal variable for the filename to the autorecovery project file
*/
QString autorecovery_filename;
/**
* @brief Internal list of recent projects
*/
QStringList recent_projects;
/**
* @brief Internal array of selected clips that a menu created by ShowEffectMenu will act on
*/
QVector<Clip*> effect_menu_selected_clips;
private slots:
/**
* @brief Receiver for a menu initiated by ShowEffectMenu
*
* Adds the selected effect/node to the clips in
*
* @param q
*/
void EffectMenuAction(QAction* q);
};
namespace olive {
/**
/**
* @brief Object resource for various global functions used throughout Olive
*/
extern std::unique_ptr<OliveGlobal> Global;
extern std::unique_ptr<OliveGlobal> Global;
/**
/**
* @brief Currently active project filename
*
* Filename for the currently active project. Empty means the file has not
* been saved yet.
*/
extern QString ActiveProjectFilename;
extern QString ActiveProjectFilename;
/**
/**
* @brief Current application name
*/
extern QString AppName;
extern QString AppName;
}
#endif // OLIVEGLOBAL_H
+18 -12
View File
@@ -1,20 +1,20 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
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 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.
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
@@ -99,3 +99,9 @@ QRect fit_size_into_rect(const QRect &r, int width, int height)
return QRect(r.x(), r.y() + (r.height() / 2 - new_height / 2), r.width(), new_height);
}
}
template<typename T>
const T &clamp(const T &val, T &min, T &max)
{
return qMax(qMin(max, val), min);
}
+19 -12
View File
@@ -1,20 +1,20 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
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 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.
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
@@ -32,10 +32,17 @@ double cubic_from_t(double a, double b, double c, double d, double t);
double cubic_t_from_x(double x_target, double a, double b, double c, double d);
double solveCubicBezier(double p0, double p1, double p2, double p3, double x);
template <typename T>
const T& clamp(const T& val, T& min, T& max);
QRect fit_size_into_rect(const QRect& r, int width, int height);
// decibel conversion functions
double amplitude_to_db(double amplitude);
double db_to_amplitude(double db);
// frame <-> pixel conversion functions
int getScreenPointFromFrame(double zoom, long frame);
long getFrameFromScreenPoint(double zoom, int x);
#endif // MATH_H
+12 -12
View File
@@ -1,20 +1,20 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
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 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.
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
+12 -12
View File
@@ -1,20 +1,20 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
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 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.
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
+169
View File
@@ -0,0 +1,169 @@
#include "timing.h"
#include "timeline/sequence.h"
#include "timeline/clip.h"
#include "global/config.h"
double get_timecode(Clip* c, long playhead) {
return double(playhead_to_clip_frame(c, playhead))/c->track()->sequence()->frame_rate;
}
long rescale_frame_number(long framenumber, double source_frame_rate, double target_frame_rate) {
return qRound((double(framenumber)/source_frame_rate)*target_frame_rate);
}
long playhead_to_clip_frame(Clip* c, long playhead) {
return (qMax(0L, playhead - c->timeline_in(true)) + c->clip_in(true));
}
double playhead_to_clip_seconds(Clip* c, long playhead) {
// returns time in seconds
long clip_frame = playhead_to_clip_frame(c, playhead);
if (c->reversed()) {
clip_frame = c->media_length() - clip_frame - 1;
}
double secs = (double(clip_frame)/c->track()->sequence()->frame_rate)*c->speed().value;
if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) {
secs *= c->media()->to_footage()->speed;
}
return secs;
}
int64_t seconds_to_timestamp(Clip *c, double seconds) {
return qRound64(seconds * av_q2d(av_inv_q(c->time_base())));
}
int64_t playhead_to_timestamp(Clip* c, long playhead) {
return seconds_to_timestamp(c, playhead_to_clip_seconds(c, playhead));
}
bool frame_rate_is_droppable(double rate) {
return (qFuzzyCompare(rate, 23.976)
|| qFuzzyCompare(rate, 29.97)
|| qFuzzyCompare(rate, 59.94));
}
long timecode_to_frame(const QString& s, int view, double frame_rate) {
QList<QString> list = s.split(QRegExp("[:;]"));
if (view == olive::kTimecodeFrames || (list.size() == 1 && view != olive::kTimecodeMilliseconds)) {
return s.toLong();
}
int frRound = qRound(frame_rate);
int hours, minutes, seconds, frames;
if (view == olive::kTimecodeMilliseconds) {
long milliseconds = s.toLong();
hours = milliseconds/3600000;
milliseconds -= (hours*3600000);
minutes = milliseconds/60000;
milliseconds -= (minutes*60000);
seconds = milliseconds/1000;
milliseconds -= (seconds*1000);
frames = qRound64((milliseconds*0.001)*frame_rate);
seconds = qRound64(seconds * frame_rate);
minutes = qRound64(minutes * frame_rate * 60);
hours = qRound64(hours * frame_rate * 3600);
} else {
hours = ((list.size() > 0) ? list.at(0).toInt() : 0) * frRound * 3600;
minutes = ((list.size() > 1) ? list.at(1).toInt() : 0) * frRound * 60;
seconds = ((list.size() > 2) ? list.at(2).toInt() : 0) * frRound;
frames = (list.size() > 3) ? list.at(3).toInt() : 0;
}
int f = (frames + seconds + minutes + hours);
if ((view == olive::kTimecodeDrop || view == olive::kTimecodeMilliseconds) && frame_rate_is_droppable(frame_rate)) {
// return drop
int d;
int m;
int dropFrames = qRound(frame_rate * .066666); //Number of frames to drop on the minute marks is the nearest integer to 6% of the framerate
int framesPer10Minutes = qRound(frame_rate * 60 * 10); //Number of frames per ten minutes
int framesPerMinute = (qRound(frame_rate)*60)- dropFrames; //Number of frames per minute is the round of the framerate * 60 minus the number of dropped frames
d = f / framesPer10Minutes;
f -= dropFrames*9*d;
m = f % framesPer10Minutes;
if (m > dropFrames) {
f -= (dropFrames * ((m - dropFrames) / framesPerMinute));
}
}
// return non-drop
return f;
}
QString frame_to_timecode(long f, int view, double frame_rate) {
if (view == olive::kTimecodeFrames) {
return QString::number(f);
}
// return timecode
int hours = 0;
int mins = 0;
int secs = 0;
int frames = 0;
QString token = ":";
if ((view == olive::kTimecodeDrop || view == olive::kTimecodeMilliseconds) && frame_rate_is_droppable(frame_rate)) {
//CONVERT A FRAME NUMBER TO DROP FRAME TIMECODE
//Code by David Heidelberger, adapted from Andrew Duncan, further adapted for Olive by Olive Team
//Given an int called framenumber and a double called framerate
//Framerate should be 29.97, 59.94, or 23.976, otherwise the calculations will be off.
int d;
int m;
int dropFrames = qRound(frame_rate * .066666); //Number of frames to drop on the minute marks is the nearest integer to 6% of the framerate
int framesPerHour = qRound(frame_rate*60*60); //Number of frqRound64ames in an hour
int framesPer24Hours = framesPerHour*24; //Number of frames in a day - timecode rolls over after 24 hours
int framesPer10Minutes = qRound(frame_rate * 60 * 10); //Number of frames per ten minutes
int framesPerMinute = (qRound(frame_rate)*60)- dropFrames; //Number of frames per minute is the round of the framerate * 60 minus the number of dropped frames
//If framenumber is greater than 24 hrs, next operation will rollover clock
f = f % framesPer24Hours; // % is the modulus operator, which returns a remainder. a % b = the remainder of a/b
d = f / framesPer10Minutes; // \ means integer division, which is a/b without a remainder. Some languages you could use floor(a/b)
m = f % framesPer10Minutes;
//In the original post, the next line read m>1, which only worked for 29.97. Jean-Baptiste Mardelle correctly pointed out that m should be compared to dropFrames.
if (m > dropFrames) {
f = f + (dropFrames*9*d) + dropFrames * ((m - dropFrames) / framesPerMinute);
} else {
f = f + dropFrames*9*d;
}
int frRound = qRound(frame_rate);
frames = f % frRound;
secs = (f / frRound) % 60;
mins = ((f / frRound) / 60) % 60;
hours = (((f / frRound) / 60) / 60);
token = ";";
} else {
// non-drop timecode
int int_fps = qRound(frame_rate);
hours = f / (3600 * int_fps);
mins = f / (60*int_fps) % 60;
secs = f/int_fps % 60;
frames = f%int_fps;
}
if (view == olive::kTimecodeMilliseconds) {
return QString::number((hours*3600000)+(mins*60000)+(secs*1000)+qCeil(frames*1000/frame_rate));
}
return QString(QString::number(hours).rightJustified(2, '0') +
":" + QString::number(mins).rightJustified(2, '0') +
":" + QString::number(secs).rightJustified(2, '0') +
token + QString::number(frames).rightJustified(2, '0')
);
}
+137
View File
@@ -0,0 +1,137 @@
#ifndef TIMING_H
#define TIMING_H
#include <QString>
#include <QtMath>
class Clip;
/**
* @brief Get timecode
*
* Get the current clip/media time from the Timeline playhead in seconds. For instance if the playhead was at the start
* of a clip (whose in point wasn't trimmed), this would be 0.0 as it's the start of the clip/media;
*
* @param c
*
* Clip to get the timecode of
*
* @param playhead
*
* Sequence playhead to convert to a clip/media timecode
*
* @return
*
* Timecode in seconds
*/
double get_timecode(Clip *c, long playhead);
/**
* @brief Rescale a frame number between two frame rates
*
* Converts a frame number from one frame rate to its equivalent in another frame rate
*
* @param framenumber
*
* The frame number to convert
*
* @param source_frame_rate
*
* Frame rate that the frame number is currently in
*
* @param target_frame_rate
*
* Frame rate to convert to
*
* @return
*
* Rescaled frame number
*/
long rescale_frame_number(long framenumber, double source_frame_rate, double target_frame_rate);
/**
* @brief Convert playhead frame number to a clip frame number
*
* Converts a Timeline playhead to a the current clip's frame. Equivalent to
* `PLAYHEAD - CLIP_TIMELINE_IN + CLIP_MEDIA_IN`. All keyframes are in clip frames.
*
* @param c
*
* The clip to get the current frame number of
*
* @param playhead
*
* The current Timeline frame number
*
* @return
*
* The curren frame number of the clip at `playhead`
*/
long playhead_to_clip_frame(Clip* c, long playhead);
/**
* @brief Converts the playhead to clip seconds
*
* Get the current timecode at the playhead in terms of clip seconds.
*
* FIXME: Possible duplicate of get_timecode()? Will need to research this more.
*
* @param c
*
* Clip to return clip seconds of.
*
* @param playhead
*
* Current Timeline playhead to convert to clip seconds
*
* @return
*
* Clip time in seconds
*/
double playhead_to_clip_seconds(Clip *c, long playhead);
/**
* @brief Convert seconds to FFmpeg timestamp
*
* Used for interaction with FFmpeg, converts seconds in a floating-point value to a timestamp in AVStream->time_base
* units.
*
* @param c
*
* Clip to get timestamp of
*
* @param seconds
*
* Clip time in seconds
*
* @return
*
* An FFmpeg-compatible timestamp in AVStream->time_base units.
*/
int64_t seconds_to_timestamp(Clip* c, double seconds);
/**
* @brief Convert Timeline playhead to FFmpeg timestamp
*
* Used for interaction with FFmpeg, converts the Timeline playhead to a timestamp in AVStream->time_base
* units.
*
* @param c
*
* Clip to get timestamp of
*
* @param playhead
*
* Timeline playhead to convert to a timestamp
*
* @return
*
* An FFmpeg-compatible timestamp in AVStream->time_base units.
*/
int64_t playhead_to_timestamp(Clip *c, long playhead);
bool frame_rate_is_droppable(double rate);
long timecode_to_frame(const QString& s, int view, double frame_rate);
QString frame_to_timecode(long f, int view, double frame_rate);
#endif // TIMING_H