From 6fd68feb9a59933adb0b284c48f1b216957cebd2 Mon Sep 17 00:00:00 2001 From: morrolinux Date: Sun, 17 Mar 2019 15:28:18 +0100 Subject: [PATCH 01/35] automated audio cut working --- dialogs/silencedialog.cpp | 192 ++++++++++++++++++++++++++++++++++++++ dialogs/silencedialog.h | 58 ++++++++++++ global/global.cpp | 13 +++ global/global.h | 5 + olive.pro | 2 + panels/timeline.cpp | 19 ++++ panels/timeline.h | 1 + ui/timelinewidget.cpp | 1 + 8 files changed, 291 insertions(+) create mode 100644 dialogs/silencedialog.cpp create mode 100644 dialogs/silencedialog.h diff --git a/dialogs/silencedialog.cpp b/dialogs/silencedialog.cpp new file mode 100644 index 000000000..2bac8e540 --- /dev/null +++ b/dialogs/silencedialog.cpp @@ -0,0 +1,192 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#include "silencedialog.h" + +#include +#include +#include +#include +#include + +#include "timeline/sequence.h" +#include "rendering/renderfunctions.h" +#include "panels/panels.h" +#include "panels/timeline.h" + +SilenceDialog::SilenceDialog(QWidget *parent, QVector clips) : QDialog(parent) { + setWindowTitle(tr("Cut silence")); + + clips_ = clips; + + QVBoxLayout* main_layout = new QVBoxLayout(this); + QGridLayout* grid = new QGridLayout(); + grid->setSpacing(6); + + grid->addWidget(new QLabel(tr("Attack Threshold:"), this), 0, 0); + attack_threshold = new LabelSlider(this); + attack_threshold->SetDecimalPlaces(0); + grid->addWidget(attack_threshold, 0, 1); + + grid->addWidget(new QLabel(tr("Attack Time:"), this), 1, 0); + attack_time = new LabelSlider(this); + attack_time->SetDecimalPlaces(0); + grid->addWidget(attack_time, 1, 1); + + grid->addWidget(new QLabel(tr("Release Threshold:"), this), 2, 0); + release_threshold = new LabelSlider(this); + release_threshold->SetDecimalPlaces(0); + grid->addWidget(release_threshold, 2, 1); + + grid->addWidget(new QLabel(tr("Release Time:"), this), 3, 0); + release_time = new LabelSlider(this); + release_time->SetDecimalPlaces(0); + grid->addWidget(release_time, 3, 1); + + main_layout->addLayout(grid); + + 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())); + + run(); // is it ok to call it here? +} + +void SilenceDialog::run() { + + default_attack_threshold = 5; + current_attack_threshold = 5; + default_attack_time = 2; + current_attack_time = 2; + default_release_threshold = 2; + current_release_threshold = 2; + default_release_time = 5; + current_release_time = 5; + + attack_threshold->SetMinimum(1); + attack_threshold->setEnabled(true); + attack_threshold->SetDefault(default_attack_threshold); + attack_threshold->SetValue(current_attack_threshold); + + attack_time->SetMinimum(1); + attack_time->setEnabled(true); + attack_time->SetDefault(default_attack_time); + attack_time->SetValue(current_attack_time); + + release_threshold->SetMinimum(1); + release_threshold->setEnabled(true); + release_threshold->SetDefault(default_release_threshold); + release_threshold->SetValue(current_release_threshold); + + release_time->SetMinimum(1); + release_time->setEnabled(true); + release_time->SetDefault(default_release_time); + release_time->SetValue(current_release_time); + +} + +void SilenceDialog::accept() { + + current_attack_threshold = attack_threshold->value(); + current_attack_time = attack_time->value(); + current_release_threshold = release_threshold->value(); + current_release_time = release_time->value(); + + cut_silence(); + + update_ui(true); + QDialog::accept(); +} + +void SilenceDialog::cut_silence() { + + Clip* clip = clips_[0]; + int clip_start = clip->timeline_in(); + const FootageStream* ms = clip->media_stream(); + long media_length = clip->media_length(); + int preview_size = ms->audio_preview.length(); + float chunk_size = (float)preview_size/media_length; // how many audio samples to read for each fotogram + + int sample_size = qMax(current_attack_time, current_release_time)+1; + + bool attack = false; // status flags + bool release = false; + + qint8 * vols = NULL; + vols = new qint8[sample_size]; + for(int i=0; iaudio_preview.at(k))))); + } + vols[circular_index] = tmp; + + //for debug: + //qInfo() << "i:" << i <<" - "<< i/30 <<":"<< i%30 << " - volume:" << vols[circular_index] <<"\n"; + + int overthreshold = 0; + int cut_idx = 0; //how much to cut (backwards) + + // if current volume value is above threshold + if (vols[circular_index] >= current_attack_threshold && !attack){ // if we get one sample over the threshold + for(int k=0; k current_attack_threshold){ + overthreshold++; + cut_idx = k+1; + } + } + // if we reached threshold over the set tolerance + if(overthreshold >= current_attack_time){ + panel_timeline->split_at_position(i-cut_idx); // cut at the first occurence + attack = true; + release = false; + //qInfo() << "\n\n Current vol: "<= current_release_time){ // must be <= sample_size + attack = false; + release = true; + panel_timeline->split_at_position(i); + //qInfo() << "\n\n Current vol: "<. + +***/ + +#ifndef SILENCEDIALOG_H +#define SILENCEDIALOG_H + +#include +#include + +#include "timeline/clip.h" +#include "ui/labelslider.h" + +class SilenceDialog : public QDialog +{ + Q_OBJECT +public: + SilenceDialog(QWidget* parent, QVector clips); + + void run(); +private slots: + void cut_silence(); + void accept(); +private: + QVector clips_; + + LabelSlider* attack_threshold; + LabelSlider* release_threshold; + LabelSlider* attack_time; + LabelSlider* release_time; + + int default_attack_threshold; + int current_attack_threshold; + int default_release_threshold; + int current_release_threshold; + int default_attack_time; + int current_attack_time; + int default_release_time; + int current_release_time; +}; + +#endif // SILENCEDIALOG_H diff --git a/global/global.cpp b/global/global.cpp index 16a59c9c6..9477f046c 100644 --- a/global/global.cpp +++ b/global/global.cpp @@ -38,6 +38,7 @@ #include "dialogs/aboutdialog.h" #include "dialogs/speeddialog.h" #include "dialogs/actionsearch.h" +#include "dialogs/silencedialog.h" #include "timeline/sequence.h" #include "ui/mediaiconservice.h" #include "ui/mainwindow.h" @@ -362,6 +363,18 @@ void OliveGlobal::open_speed_dialog() { } } +void OliveGlobal::open_cut_silence_dialog() { + if (olive::ActiveSequence != nullptr) { + + QVector selected_clips = olive::ActiveSequence->SelectedClips(); + + if (!selected_clips.isEmpty()) { + SilenceDialog s(olive::MainWindow, selected_clips); + s.exec(); + } + } +} + void OliveGlobal::clear_undo_stack() { olive::UndoStack.clear(); } diff --git a/global/global.h b/global/global.h index 6a9d57617..4b38f35c7 100644 --- a/global/global.h +++ b/global/global.h @@ -239,6 +239,11 @@ public slots: */ void open_speed_dialog(); + /** + * @brief Open the cut silence dialog. + */ + void open_cut_silence_dialog(); + /** * @brief Open the Action Search overlay. */ diff --git a/olive.pro b/olive.pro index 95509fe66..c36e4910f 100644 --- a/olive.pro +++ b/olive.pro @@ -91,6 +91,7 @@ SOURCES += \ dialogs/demonotice.cpp \ timeline/marker.cpp \ dialogs/speeddialog.cpp \ + dialogs/silencedialog.cpp \ dialogs/mediapropertiesdialog.cpp \ project/projectmodel.cpp \ project/loadthread.cpp \ @@ -221,6 +222,7 @@ HEADERS += \ project/projectmodel.h \ project/loadthread.h \ dialogs/loaddialog.h \ + dialogs/silencedialog.h \ global/debug.h \ global/path.h \ effects/internal/transformeffect.h \ diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 37c276d9b..fe97e7788 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -138,6 +138,25 @@ void Timeline::Retranslate() { UpdateTitle(); } +void Timeline::split_at_position(int pos) { + ComboAction* ca = new ComboAction(); + split_cache.clear(); + + if (olive::ActiveSequence->selections.size() > 0) { + // see if whole clips are selected + QVector pre_clips; + QVector post_clips; + for (int j=0;jclips.size();j++) { + Clip* clip = olive::ActiveSequence->clips.at(j).get(); + if (clip != nullptr && olive::ActiveSequence->IsClipSelected(clip, true)) { + split_clip_and_relink(ca,j,pos,true); + + } + } + olive::UndoStack.push(ca); + } +} + void Timeline::previous_cut() { if (olive::ActiveSequence != nullptr && olive::ActiveSequence->playhead > 0) { diff --git a/panels/timeline.h b/panels/timeline.h index 028c8977f..c3338d370 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -237,6 +237,7 @@ public slots: void deselect(); void toggle_links(); void split_at_playhead(); + void split_at_position(int pos); void ripple_delete(); void ripple_delete_empty_space(); void toggle_enable_on_selected_clips(); diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 2de81a528..18af4faf5 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -122,6 +122,7 @@ void TimelineWidget::show_context_menu(const QPoint& pos) { menu.addSeparator(); menu.addAction(tr("&Speed/Duration"), olive::Global.get(), SLOT(open_speed_dialog())); + menu.addAction(tr("&Cut Silence"), olive::Global.get(), SLOT(open_cut_silence_dialog())); QAction* autoscaleAction = menu.addAction(tr("Auto-s&cale"), this, SLOT(toggle_autoscale())); autoscaleAction->setCheckable(true); From 3a2b47300600cd89f55264a424fef2bd7d74133c Mon Sep 17 00:00:00 2001 From: app4soft Date: Wed, 20 Mar 2019 19:46:17 +0200 Subject: [PATCH 02/35] Delete olive_uk.ts --- ts/olive_uk.ts | 3531 ------------------------------------------------ 1 file changed, 3531 deletions(-) delete mode 100644 ts/olive_uk.ts diff --git a/ts/olive_uk.ts b/ts/olive_uk.ts deleted file mode 100644 index cfecbc67c..000000000 --- a/ts/olive_uk.ts +++ /dev/null @@ -1,3531 +0,0 @@ - - - - - AboutDialog - - - Olive is a non-linear video editor. This software is free and protected by the GNU GPL. - Olive є нелінійним редактором відео. Це програмне забезпечення є вільним і захищено ліцензією GNU GPL. - - - - Olive Team is obliged to inform users that Olive source code is available for download from its website. - Olive Team інформує користувачів про те що джерельний код Olive є доступним для завантаження на сайті проекту. - - - - ActionSearch - - - Search for action... - Знайти дію... - - - - AdvancedVideoDialog - - - Advanced Video Settings - Розширені налаштування відео - - - - Pixel Format: - Формат пікселів: - - - - Threads: - Потоки: - - - - Audio - - - %1 Audio - Потрібно уточнити - %1 Аудіо - - - - Recording %1 - Запис %1 - - - - AudioNoiseEffect - - - Amount - Кількість - - - - Mix - Змішування - - - - ChannelLayoutName - - - Invalid - Уточнити - Некоректний - - - - Mono - Моно - - - - Stereo - Стерео - - - - ClipPropertiesDialog - - - "%1" Properties - "%1" Параметри - - - - Multiple Clip Properties - Уточнити - Параметри множинного кліпа - - - - Name: - Назва: - - - - Duration: - Тривалість: - - - - (multiple) - Уточнити - (множинний) - - - - CollapsibleWidget - - - <untitled> - <без назви> - - - - ColorButton - - - Set Color - Встановити колір - - - - CornerPinEffect - - - Top Left - Верхній Лівий - - - - Top Right - Верхній Правий - - - - Bottom Left - Нижній Лівий - - - - Bottom Right - Нижній Правий - - - - Perspective - Перспектива - - - - DebugDialog - - - Debug Log - Журнал злагодження - - - - DemoNotice - - - - Welcome to Olive! - Ласкаво просимо в Olive! - - - - Olive is a free open-source video editor released under the GNU GPL. If you have paid for this software, you have been scammed. - Olive є вільним нелінійним редактором відео створеним на умовах ліцензії GNU GPL. Якщо ви платили за це програмне забезпечення, то вас обманули. - - - - 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 - Це програмне забезпечення наразі в стадії АЛЬФА і це означає що програма є нестабільною і може працювати некоректно, має помилки та відсутні функції. Ми не несемо відповідальності тож викикористовуйте програму на власний ризик. Будь-ласка, повідомляйте нам про помилки та бажані функції через %1 - - - - Thank you for trying Olive and we hope you enjoy it! - Дякуємо що спробували і маємо надію що вам сподобаєтся Olive! - - - - Effect - - - Invalid effect - Некоректний ефект - - - - No candidate for effect '%1'. This effect may be corrupt. Try reinstalling it or Olive. - Відсутній відповідник для ефекту '%1'. Цей ефект можливо пошкоджений. Спробуйте перевстановити його або ж Olive. - - - - Cu&t - Ви&різати - - - - &Copy - &Копіювати - - - - Move &Up - Перемістити В&гору - - - - Move &Down - Перемістити В&низ - - - - D&elete - Ви&далити - - - - Load Settings From File - Завантажити налаштування з файлу - - - - Save Settings to File - Зберегти налаштування у файл - - - - Save Effect Settings - Зберегти налаштування ефектів - - - - - Effect XML Settings %1 - Файли з налаштуваннями ефектів %1 - - - - Save Settings Failed - Не вдалося зберегти налаштування - - - - Failed to open "%1" for writing. - Не вдалося відкрити "%1" для запису. - - - - Load Effect Settings - Завантажити налаштування ефектів - - - - - Load Settings Failed - Не вдалося завантажити налаштування - - - - Failed to open "%1" for reading. - Не вдалося відкрити "%1" для зчитування. - - - - This settings file doesn't match this effect. - Цей файл налаштувань не підходить для цього ефекта. - - - - EffectControls - - - &Paste - В&ставити - - - - (none) - (пусто) - - - - Effects: - Ефекти: - - - - Add Video Effect - Додати відеоефект - - - - VIDEO EFFECTS - ВІДЕОЕФЕКТИ - - - - Add Video Transition - Додати відеоперехід - - - - Add Audio Effect - Додати аудіоефект - - - - AUDIO EFFECTS - АУДІОЕФЕКТИ - - - - Add Audio Transition - Додати аудіоперехід - - - - (Multiple clips selected) - (виділено множину кліпів) - - - - EffectRow - - - Disable Keyframes - Вимкнути ключові кадри - - - - Disabling keyframes will delete all current keyframes. Are you sure you want to do this? - Вимкнення ключових кадрів видалить усі існуючі ключові кадри. Ви впевнені що хочете зробити це? - - - - EmbeddedFileChooser - - - File: - Файл: - - - - ExportDialog - - - Export "%1" - Експортувати "%1" - - - - Unknown codec name %1 - Невідома назва кодека %1 - - - - Export Failed - Не вдалося експортувати - - - - Export failed - %1 - Не вдалося експортувати - %1 - - - - Invalid dimensions - Некоректні розміри кадра - - - - Export width and height must both be even numbers/divisible by 2. - Для експорту значення ширини та висоти повинні бути цілими парними числами. - - - - Invalid codec - Некоректний кодек - - - - Couldn't determine output parameters for the selected codec. This is a bug, please contact the developers. - Неможливо визначити вихідні параметри для обраного кодека. Це помилка, будь-ласка, зв'яжітся з розробниками. - - - - Invalid format - Некоректний формат - - - - Couldn't determine output format. This is a bug, please contact the developers. - Неможливо визначити вихідний формат. Це помилка, будь-ласка, зв'яжітся з розробниками. - - - - Export Media - Уточнити - Експортувати медіафайл - - - - %p% (Total: %1:%2:%3) - %p% (Час: %1:%2:%3) - - - - %p% (ETA: %1:%2:%3) - %p% (Залишилося: %1:%2:%3) - - - - Quality-based (Constant Rate Factor) - Якість (Constant Rate Factor) - - - - Constant Bitrate - Сталий швидкість потоку - - - - - Invalid Codec - Некоректний кодек - - - - Failed to find a suitable encoder for this codec. Export will likely fail. - Не вдалося знайти відповідний кодувальник для цього кодека. Експорт може бути некоректним. - - - - Failed to find pixel format for this encoder. Export will likely fail. - Не вдалося знайти формат пікселів для цього кодувальника. Експорт може бути некоректним. - - - - Bitrate (Mbps): - Швидкість потока (Мбіт/с): - - - - Quality (CRF): - Якість (CRF): - - - - Quality Factor: - -0 = lossless -17-18 = visually lossless (compressed, but unnoticeable) -23 = high quality -51 = lowest quality possible - Коефіцієнт Якості: - -0 = без втрат -17-18 = візульно без втрат (стиснуто, але майже непомітно) -23 = висока якість -51 = найнижча можлива якість - - - - Target File Size (MB): - Кінцевий розмір файла (Мб): - - - - Format: - Формат: - - - - Range: - Діапазон: - - - - Entire Sequence - Уточнити - Вся послідовність - - - - In to Out - Від входу до виходу - - - - Video - Відео - - - - - Codec: - Кодек: - - - - Width: - Ширина: - - - - Height: - Висота: - - - - Frame Rate: - Частота кадрів: - - - - Compression Type: - Тип cтискання: - - - - Advanced - Додатково - - - - Audio - Аудіо - - - - Sampling Rate: - Частота дискретизації: - - - - Bitrate (Kbps/CBR): - Швидкість потока (Кбіт/с / CBR): - - - - ExportThread - - - failed to send frame to encoder (%1) - не вдалося надіслати кадр до кодувальника (%1) - - - - failed to receive packet from encoder (%1) - не вдалося отримати пакет від кодувальника (%1) - - - - could not video encoder for %1 - не вдалося знайти кодувальник відео для %1 - - - - could not allocate video stream - не вдалося встановити поток відео - - - - could not allocate video encoding context - не вдалося встановити контекст кодувльника відео - - - - could not open output video encoder (%1) - не вдалося відкрити вихідний кодувальник відео (%1) - - - - could not copy video encoder parameters to output stream (%1) - не вдалося скопіювати параметри кодувальника відео для вихідного потоку (%1) - - - - could not audio encoder for %1 - не вдалося знайти кодувальник аудіо для %1 - - - - could not allocate audio stream - не вдалося встановити поток аудіо - - - - could not allocate audio encoding context - не вдалося встановити контекст кодувльника аудіо - - - - could not open output audio encoder (%1) - не вдалося відкрити вихідний кодувальник аудіо (%1) - - - - could not copy audio encoder parameters to output stream (%1) - не вдалося скопіювати параметри кодувальника аудіо для вихідного потоку (%1) - - - - could not allocate audio buffer (%1) - не вдалося встановити буфер аудіо (%1) - - - - could not create output format context - не вдалося створити контекст вихідного формату - - - - could not open output file (%1) - не вдалося відкрити вихідний файл (%1) - - - - could not write output file header (%1) - не вдалося записати заголовок вихідного файлу (%1) - - - - could not write output file trailer (%1) - Уточнити - не вдалося записати кінець вихідного файлу (%1) - - - - FillLeftRightEffect - - - Type - Тип - - - - Fill Left with Right - Заповнити лівий канал правим - - - - Fill Right with Left - Заповнити правий канал лівим - - - - Frei0rEffect - - - Failed to load Frei0r plugin "%1": %2 - Не вдалося завантажити плагін Frei0r "%1": %2 - - - - NOTE: You can't load 32-bit Frei0r plugins into a 64-bit build of Olive. Please find a 64-bit version of this plugin or switch to a 32-bit build of Olive. - ПРИМІТКА: Ви не можете завантажувати 32-розрядні плагіни Frei0r у 64-розрядний Olive. Знайдіть 64-розрядну версію цього плагіна або встановіть 32-розрядну версію Olive. - - - - NOTE: You can't load 64-bit Frei0r plugins into a 32-bit build of Olive. Please find a 32-bit version of this plugin or switch to a 64-bit build of Olive. - ПРИМІТКА: Ви не можете завантажувати 64-розрядні плагіни Frei0r у 32-розрядний Olive. Знайдіть 64-розрядну версію цього плагіна або встановіть 64-розрядну версію Olive. - - - - Error loading Frei0r plugin - Помилка при завантаженні плагіна Frei0r - - - - GraphEditor - - - Graph Editor - Редактор графів - - - - Linear - Лінійний - - - - Bezier - Безьє - - - - Hold - Стала - - - - GraphView - - - Zoom to Selection - Масштабувати до виділеного - - - - Zoom to Show All - Масштабувати і показати все - - - - Reset View - Скинути масштабування - - - - InterlacingName - - - None (Progressive) - Ні (прогресивно) - - - - Top Field First - Спочатку верхне поле - - - - Bottom Field First - Спочатку нижнє поле - - - - Invalid - Некоректно - - - - KeyframeNavigator - - - Enable Keyframes - Увімкнути ключові кадри - - - - KeyframeView - - - Linear - Лінійний - - - - Bezier - Безьє - - - - Hold - Стала - - - - LabelSlider - - - &Edit - &Редагувати - - - - &Reset to Default - Уточнити - &Скинути до стандартних - - - - - Set Value - Встановити значення - - - - - New value: - Нове значення: - - - - LoadDialog - - - Loading... - Завантаження... - - - - Loading '%1'... - Завантажується '%1'... - - - - Cancel - Відміна - - - - LoadThread - - - Version Mismatch - Невідповіність версій - - - - This project was saved in a different version of Olive and may not be fully compatible with this version. Would you like to attempt loading it anyway? - Цей проект булр збережено в іншій версії Olive, котра неповністью сумісна з наявною версією. Ви все ж хочете спробувати завантажити цей проект? - - - - Invalid Clip Link - Некоректний зв'язок кліпів - - - - This project contains an invalid clip link. It may be corrupt. Would you like to continue loading it? - У проекті виявлено некоректний зв'язок кліпів. Ви хочете продовжити завантаження? - - - - %1 - Line: %2 Col: %3 - %1 - Рядок: %2 Стовпчик: %3 - - - - User aborted loading - Завантаження зупинено користувачем - - - - XML Parsing Error - Помилка розбору XML - - - - Couldn't load '%1'. %2 - Не вдалося завантажити '%1'. %2 - - - - Project Load Error - Помилка при завантаженні проекта - - - - Error loading project: %1 - Помилка при завантаженні проекта: %1 - - - - MainWindow - - - Welcome to %1 - Вітаємо в %1 - - - - &File - &Файл - - - - &New - &Новий - - - - &Open Project - &Відкрити проект - - - - Clear Recent List - Очистити історію - - - - Open Recent - Відкрити недавній - - - - &Save Project - &Зберегти проект - - - - Save Project &As - Зберегти проект &як - - - - &Import... - &Імпортувати... - - - - &Export... - &Експортувати... - - - - E&xit - Ви&хід - - - - &Edit - &Редагування - - - - &Undo - &Відмінити - - - - Redo - Повернути - - - - Select &All - Виділити &усе - - - - Deselect All - Скасувати виділення - - - - Ripple to In Point - Зсунути до точки входу - - - - Ripple to Out Point - Зсунути до точки виходу - - - - Edit to In Point - Редагування до точки входу - - - - Edit to Out Point - Редагування до точки виходу - - - - Delete In/Out Point - Видалити точку входу/виходу - - - - Ripple Delete In/Out Point - Видалити зі зміщенням точку входу/виходу - - - - Set/Edit Marker - Встановити/Редагувати маркер - - - - &View - &Вигляд - - - - Zoom In - Наблизити - - - - Zoom Out - Віддалити - - - - Increase Track Height - Збільшити висоту доріжки - - - - Decrease Track Height - Зменшити висоту доріжки - - - - Toggle Show All - Уточнити - Показувати увесь проект - - - - Track Lines - Лінії доріжок - - - - Rectified Waveforms - Хвильова форма від низу - - - - Frames - Кадри - - - - Drop Frame - З пропусканням кадрів - - - - Non-Drop Frame - Без пропускання кадрів - - - - Milliseconds - Мілісекунди - - - - Title/Action Safe Area - Уточнити - Безпечна зона титрів/ефекта - - - - Off - Вимк. - - - - Default - Типово - - - - 4:3 - 4:3 - - - - 16:9 - 16:9 - - - - Custom - Інше - - - - Full Screen - Повноекранний режим - - - - Full Screen Viewer - Перегляд в повноекранному режимі - - - - &Playback - Від&творення - - - - Go to Start - На початок - - - - Previous Frame - Попередній кадр - - - - Play/Pause - Відтворення/Пауза - - - - Play In to Out - Відтворити від входу до виходу - - - - Next Frame - Наступний кадр - - - - Go to End - У кінець - - - - Go to Previous Cut - До попереднього розрізу - - - - Go to Next Cut - До наступного розрізу - - - - Go to In Point - До точки входу - - - - Go to Out Point - До точки виходу - - - - Shuttle Left - Уточнити - Зменшити швидкість - - - - Shuttle Stop - Уточнити - Пауза - - - - Shuttle Right - Уточнити - Збільшити швидкість - - - - Loop - Петля - - - - &Window - &Вікно - - - - Project - Проект - - - - Effect Controls - Керування ефектами - - - - Timeline - Монтажний стіл - - - - Graph Editor - Редактор графів - - - - Media Viewer - Уточнити - Переглядач медіа файлів - - - - Sequence Viewer - Уточнити - Переглядач послідовності - - - - Maximize Panel - Розгорнути панель - - - - Lock Panels - Зафіксувати панель - - - - Reset to Default Layout - Повернути початкове розташування панелей - - - - &Tools - &Інструменти - - - - Pointer Tool - Уточнити - Вказівник - - - - Edit Tool - Виділення - - - - Ripple Tool - Монтаж зі зсувом - - - - Razor Tool - Підрізка - - - - Slip Tool - Прокручування зі зміщенням - - - - Slide Tool - Прокручування - - - - Hand Tool - Уточнити - Навігація - - - - Transition Tool - Перехід - - - - Enable Snapping - Увімкнути прилипання - - - - Selecting Also Seeks - Виділення з прокручуванням - - - - Edit Tool Also Seeks - Уточнити - Виділення з прокручуванням - - - - Edit Tool Selects Links - Виділення обирає зв'язки - - - - Seek Also Selects - Прокручування з виділенням - - - - Seek to the End of Pastes - Прокручування до кінця вставок - - - - Scroll Wheel Zooms - Уточнити - Колесо миші масштабує монтажний стіл - - - - Hold CTRL to toggle this setting - Утримуйте CTRL для перемикання цього ноалаштування - - - - Invert Timeline Scroll Axes - Уточнити - Інвертувати напрямки прокручування монтажного столу - - - - Enable Drag Files to Timeline - Уточнити - Дозволити переміщення файлів на монтажний стіл - - - - Auto-Scale By Default - Автомасштабування за умовчанням - - - - Enable Seek to Import - Уточнити - Увімкнути прокручування для імпортування - - - - Audio Scrubbing - Відтворювати звук під час прокручування - - - - Enable Drop on Media to Replace - Уточнити - Увімкнути переміщення на медіа для заміни - - - - Enable Hover Focus - Увімкнути фокус наведенням - - - - Ask For Name When Setting Marker - Запитувати назву маркера при додаванні - - - - No Auto-Scroll - Без автопрокручування - - - - Page Auto-Scroll - Прокручувати перегортанням - - - - Smooth Auto-Scroll - Прокручувати плавно - - - - Preferences - Параметри - - - - Clear Undo - Очистити історію змін - - - - &Help - &Довідка - - - - A&ction Search - По&шук дії - - - - Debug Log - Журнал злагодження - - - - &About... - &Про програму... - - - - <untitled> - <без назви> - - - - Marker - - - Set Marker - Встановити маркер - - - - Set clip marker name: - Назва маркера кліпу: - - - - Set sequence marker name: - Назва маркера послідовності: - - - - Media - - - New Folder - Нова тека - - - - Name: - Назва: - - - - Filename: - Ім'я файла: - - - - Video Dimensions: - Розмір кадрів: - - - - Frame Rate: - Частота кадрів: - - - - %1 field(s) (%2 frame(s)) - полів: %1 (кадрів: %2) - - - - Interlacing: - Черезрядковість: - - - - Audio Frequency: - Частота звука: - - - - Audio Channels: - Звукових каналів: - - - - Name: %1 -Video Dimensions: %2x%3 -Frame Rate: %4 -Audio Frequency: %5 -Audio Layout: %6 - Назва: %1 -Розмер кадрів: %2x%3 -Частота кадрів: %4 -Частота звука: %5 -Звукових каналів: %6 - - - - Name - Назва - - - - Duration - Тривалість - - - - Rate - Частота - - - - MediaPropertiesDialog - - - "%1" Properties - Властивості "%1" - - - - Tracks: - Доріжок: - - - - Video %1: %2x%3 %4FPS - Відео %1: %2x%3 %4к/c - - - - Audio %1: %2Hz %3 - Аудіо %1: %2Гц %3 - - - - %n channel(s) - - %n канал - %n канали - %n каналів - - - - - Conform to Frame Rate: - Підігнати до частоти кадрів: - - - - Alpha is Premultiplied - Уточнити - Альфа-значення помножено у зворотньому порядку - - - - Auto (%1) - Авто (%1) - - - - Interlacing: - Черезрядковість: - - - - Name: - Назва: - - - - MenuHelper - - - &Project - &Проект - - - - &Sequence - П&ослідовність - - - - &Folder - Т&ека - - - - Set In Point - Встановити точку входа - - - - Set Out Point - Встановити точку вихода - - - - Reset In Point - Скинути точку входа - - - - Reset Out Point - Скинути точку вихода - - - - Clear In/Out Point - Очистити точку входа/вихода - - - - Add Default Transition - Додати типовий перехід - - - - Link/Unlink - Зв'язати/Прибрати зв'язок - - - - Enable/Disable - Увімкнути/Вимкнути - - - - Nest - Вкласти - - - - Cu&t - Ви&різати - - - - Cop&y - С&копіювати - - - - &Paste - В&ставити - - - - Paste Insert - Уточнити - Вставити з заміною - - - - Duplicate - Дюблювати - - - - Delete - Видалити - - - - Ripple Delete - Видалити зі зміщенням - - - - Split - Розділити - - - - Invalid aspect ratio - Некоректні пропорції сторін - - - - The aspect ratio '%1' is invalid. Please try again. - Пропорції сторін '%1' є некоректними. Будь-ласка, спробуйте ще раз. - - - - Enter custom aspect ratio - Встановіть інші пропорції сторін - - - - Enter the aspect ratio to use for the title/action safe area (e.g. 16:9): - Встановіть пропорції сторін для безпечної зони титрів/ефекта (наприклад, 16:9): - - - - NewSequenceDialog - - - Editing "%1" - Редагування "%1" - - - - New Sequence - Нова послідовність - - - - Preset: - Уточнити - Профіль: - - - - Film 4K - Фільм 4К - - - - TV 4K (Ultra HD/2160p) - TV 4K (Ultra HD/2160p) - - - - 1080p - 1080p - - - - 720p - 720p - - - - 480p - 480p - - - - 360p - 360p - - - - 240p - 240p - - - - 144p - 144p - - - - NTSC (480i) - NTSC (480i) - - - - PAL (576i) - PAL (576i) - - - - Custom - Інше - - - - Video - Відео - - - - Width: - Ширина: - - - - Height: - Висота: - - - - Frame Rate: - Частота кадрів: - - - - Pixel Aspect Ratio: - Пропорції сторін пікселів: - - - - Square Pixels (1.0) - Квадратні пікселі (1.0) - - - - Interlacing: - Черезрядковість: - - - - None (Progressive) - Ні (прогресивно) - - - - Audio - Аудіо - - - - Sample Rate: - Частота дискретизації: - - - - Name: - Назва: - - - - OliveGlobal - - - Olive Project %1 - Проект Olive %1 - - - - Auto-recovery - Автовідновлення - - - - Olive didn't close properly and an autorecovery file was detected. Would you like to open it? - Olive аварійно завершив роботу і виявив файл автовідновлення. Відкрити його? - - - - Open Project... - Відкрити проект... - - - - Missing recent project - Відсутній недавній проект - - - - The project '%1' no longer exists. Would you like to remove it from the recent projects list? - Проект '%1' більше не існує. Видалити його з історії? - - - - Save Project As... - Зберегти проект як... - - - - Unsaved Project - Незбережений проект - - - - This project has changed since it was last saved. Would you like to save it before closing? - Проект було змінено з момента останнього збереження. Хочете зберегти його перед закриттям? - - - - No active sequence - Немає активних послідовностей - - - - Please open the sequence you wish to export. - Будь-ласка, відкрийте послідовність котру хочете експортувати. - - - - Missing Project File - Відсутній файл проекта - - - - Specified project '%1' does not exist. - Вказаний проект '%1' не існує. - - - - PanEffect - - - Pan - Уточнити - Панорама - - - - PreferencesDialog - - - Preferences - Параметри - - - - Invalid CSS File - Некоректний файл CSS - - - - CSS file '%1' does not exist. - Файл CSS '%1' не існує. - - - - Confirm Reset All Shortcuts - Підтвердіть скидання всіх комбінацій клавіш - - - - Are you sure you wish to reset all keyboard shortcuts to their defaults? - Ви дійсно хочете скинути всі комбінації клавіш до типових значень? - - - - Import Keyboard Shortcuts - Імпортувати комбінації клавіш - - - - - Error saving shortcuts - Помилка при збереженні комбінацій клавіш - - - - Failed to open file for reading - Не вдалося відкрити файл для читання - - - - Export Keyboard Shortcuts - Експортувати комбінації клавіш - - - - Export Shortcuts - Експортувати комбінації клавіш - - - - Shortcuts exported successfully - Комбінації клавіш експортовано - - - - Failed to open file for writing - Не вдалося відкрити файл для запису - - - - Browse for CSS file - Обрати файл CSS - - - - Delete All Previews - Видалити усі мініатюри - - - - Are you sure you want to delete all previews? - Дійсно видалити усі мініатюри? - - - - Previews Deleted - Мініатюри видалено - - - - All previews deleted succesfully. You may have to re-open your current project for changes to take effect. - Уточнити - Усі мініатюри видалено. Можливо знадобится перевідкрити поточний проект для того щоб зміни вступили в силу. - - - - Language: - Мова: - - - - Custom CSS: - Інший CSS: - - - - Browse - Уточнити - Обрати - - - - Image sequence formats: - Формати зображень: - - - - Audio Recording: - Запис звука: - - - - Mono - Моно - - - - Stereo - Стерео - - - - Effect Textbox Lines: - Кількість рядків у полі вводу тексту: - - - - Thumbnail Resolution: - Уточнити - Роздільна здатність мініатюр: - - - - Waveform Resolution: - Роздільна здатність хвильових форм: - - - - Delete Previews - Видалити мініатюри - - - - Use Software Fallbacks When Possible - По можливості використовувати програмну реалізацію - - - - General - Загальні - - - - Behavior - Поведінка - - - - Seeking - Позіціонування - - - - Accurate Seeking -Always show the correct frame (visual may pause briefly as correct frame is retrieved) - Точне позиціонування -Завжди показувати правильний кадр (відображення може уповільнюватися) - - - - Fast Seeking -Seek quickly (may briefly show inaccurate frames when seeking - doesn't affect playback/export) - Швидке позиціонування (можливе неточне відображення кадрів - не впливає на відтворення) - - - - Memory Usage - Використання пам'яті - - - - Upcoming Frame Queue: - Резервування послідуючих кадрів: - - - - - frames - кадрів - - - - - seconds - секунд - - - - Previous Frame Queue: - Резервування попередніх кадрів: - - - - Playback - Відтворення - - - - Output Device: - Пристрій виводу: - - - - - Default - Типово - - - - Input Device: - Пристрій вводу: - - - - Sample Rate: - Частота дискретизації: - - - - Audio - Аудіо - - - - Search for action or shortcut - Знайти дію або комбінацію клавіш - - - - Action - Дія - - - - Shortcut - Комбінація клавіш - - - - Import - Імпортувати - - - - Export - Експортувати - - - - Reset Selected - Скинути виділення - - - - Reset All - Скинути все - - - - Keyboard - Комбінації клавіш - - - - PreviewGenerator - - - Failed to find any valid video/audio streams - Не вдалося знайти коректні відео/аудіо потоки - - - - Could not open file - %1 - Не вдалося відкрити файл — %1 - - - - Could not find stream information - %1 - Не вдалося знайти інформацію потоку — %1 - - - - Project - - - Search media, markers, etc. - Шукати файли, маркери, і т.п. - - - - Project - Проект - - - - Sequence - Послідовність - - - - Replace '%1' - Замінити '%1' - - - - - All Files - Усі файли - - - - - No active sequence - Немає активних послідовностей - - - - No sequence is active, please open the sequence you want to replace clips from. - Немає активних послідовносте. Відкрийте послідовність в якій хочете замінити кліпи. - - - - Active sequence selected - Обрано активну послідовність - - - - You cannot insert a sequence into itself, so no clips of this media would be in this sequence. - Уточнити - Ви не можете вставити послідовність в саму себе, тож кліпи з цих файлов не можуть бути вставлені в цю послідовність. - - - - Rename '%1' - Перейменувати '%1' - - - - Enter new name: - Введіть нову назву: - - - - Delete media in use? - Уточнити - Видалити використані у проекті файли? - - - - The media '%1' is currently used in '%2'. Deleting it will remove all instances in the sequence. Are you sure you want to do this? - Файл '%1' вже використовується у '%2'. Його видалення приведе до видалення усіх його копій у вибраній послідовності. Ви точно цього хочете? - - - - Skip - Пропустити - - - - Import a Project - Імпортувати проект - - - - "%1" is an Olive project file. It will merge with this project. Do you wish to continue? - "%1" є файлом проекту Olive. Його буде об'єднано з поточним проектом. Ви хочете продовжити? - - - - Image sequence detected - Виявлено послідовність зображень - - - - The file '%1' appears to be part of an image sequence. Would you like to import it as such? - Схоже що файл '%1' є частиною послідовності зображень. Імпортувати його як є? - - - - Import media... - Імпортувати медіафайли... - - - - No sequence is active, please open the sequence you want to delete clips from. - Немає активних послідовносте. Відкрийте послідовність з якої хочете видалити кліпи. - - - - ProxyDialog - - - Create Proxy - Створити проксі - - - - Proxy - Проксі - - - - Dimensions: - Розмір: - - - - Same Size as Source - Оригінальний розмір - - - - Half Resolution (1/2) - Половина оригінала (1/2) - - - - Quarter Resolution (1/4) - Четверть оригіналу (1/4) - - - - Eighth Resolution (1/8) - Восьма оригиніалу (1/8) - - - - Sixteenth Resolution (1/16) - Шістнадцята оригіналу (1/16) - - - - Format: - Формат: - - - - ProRes HQ - ProRes HQ - - - - Location: - Розташування: - - - - Same as Source (in "%1" folder) - Як в оригіналі (у теці "%1") - - - - Proxy file exists - Проксі-файл вже існує - - - - The file "%1" already exists. Do you wish to replace it? - Файл "%1" вже існує. Замінити його? - - - - Custom Location - Інше розміщення - - - - ProxyGenerator - - - Finished generating proxy for "%1" - Завершено створення проксі для "%1" - - - - ReplaceClipMediaDialog - - - Replace clips using "%1" - Замінити кліпи на "%1" - - - - Select which media you want to replace this media's clips with: - Оберіть файли, які хочете замінити у кліпах з цими файлами: - - - - Keep the same media in-points - Уточнити - Зберегти існуючі точки входу - - - - Replace - Замінити - - - - Cancel - Відмінити - - - - No media selected - Не обрано медіафайли - - - - Please select a media to replace with or click 'Cancel'. - Оберіть медіафайли для заміни та натисніть «Відміна». - - - - Same media selected - Обрано ті ж самі файли - - - - You selected the same media that you're replacing. Please select a different one or click 'Cancel'. - Ви обрали ті ж самі файли, що й хочете замінити. Оберіть якісь інші файли або ж натисніть «Відміна». - - - - Folder selected - Теку обрано - - - - You cannot replace footage with a folder. - Уточнити - Ви не можете замінити відеоряд текою. - - - - Active sequence selected - Обрано активну послідовність - - - - You cannot insert a sequence into itself. - Ви не можете вставити послідовність в саму себе. - - - - Sequence - - - %1 (copy) - %1 (копія) - - - - ShakeEffect - - - Intensity - Інтенсивність - - - - Rotation - Обертання - - - - Frequency - Частота - - - - SolidEffect - - - Type - Тип - - - - Solid Color - Суцільна заливка - - - - SMPTE Bars - Таблиця SMPTE - - - - Checkerboard - Шахівниця - - - - Opacity - Непрозорість - - - - Color - Колір - - - - Checkerboard Size - Розмір клітинок - - - - SourcesCommon - - - Import... - Імпортувати... - - - - New - Створити - - - - View - Вигляд - - - - Tree View - У вигляді таблиці - - - - Icon View - У вигляді мініатюр - - - - Show Toolbar - Показувати панель - - - - Show Sequences - Показувати послідовності - - - - Replace/Relink Media - Уточнити - Замінити/Перезв'язати файли - - - - Reveal in Explorer - Відкрити у Explorer - - - - Reveal in Finder - Відкрити у Finder - - - - Reveal in File Manager - Відкрити у менеджері файлів - - - - Replace Clips Using This Media - Уточнити - Замінити кліпи з цими файлами - - - - Create Sequence With This Media - Створити послідовність з цими файлами - - - - Duplicate - Дублювати - - - - Delete All Clips Using This Media - Уточнити - Видалити усі кліпи з цими файлами - - - - Proxy - Проксі - - - - Generating proxy: %1% complete - Створення проксі: завершено на %1% - - - - Create/Modify Proxy - Створити/Змінити проксі - - - - Create Proxy - Створити проксі - - - - Modify Proxy - Змінити проксі - - - - Restore Original - Відновити оригінал - - - - Delete - Видалити - - - - Preview in Media Viewer - Переглянути у Переглядачі медіа файлів - - - - Properties... - Властивості... - - - - Replace Media - Замінити медіафайли - - - - You dropped a file onto '%1'. Would you like to replace it with the dropped file? - Ви перетягнули файл на '%1'. Ви хочете замінити на цей файл? - - - - Delete proxy - Видалити проксі - - - - Would you like to delete the proxy file "%1" as well? - Заразом видалити проксі-файл "%1"? - - - - SpeedDialog - - - Dialog - Діалог - - - - - Speed: - Швидкість: - - - - - Frame Rate: - Частота кадрів: - - - - - Duration: - Тривалість: - - - - Speed/Duration - Швидкість/Тривалість - - - - Reverse - Реверс - - - - Maintain Audio Pitch - Зберегти висоту тона - - - - Ripple Changes - Змінювати зі зміщенням - - - - TextEditDialog - - - Edit Text - Змінити текст - - - - TextEffect - - - Text - Текст - - - - Font - Шрифт - - - - Size - Розмір - - - - Color - Колір - - - - Alignment - Вирівнювання - - - - Left - Ліворуч - - - - - Center - По центру - - - - Right - Праворуч - - - - Justify - По ширині - - - - Top - Вгорі - - - - Bottom - Внизу - - - - Word Wrap - Перенесення рядка - - - - Outline - Контури - - - - Outline Color - Колір контурів - - - - Outline Width - Ширина контурів - - - - Shadow - Тінь - - - - Shadow Color - Колір тіні - - - - Shadow Angle - Кут падіння тіні - - - - Shadow Distance - Відстань до тіні - - - - Shadow Softness - Розсіювання тіні - - - - Shadow Opacity - Непрозорість тіні - - - - Sample Text - Зразок тексту - - - - &Edit Text - &Змінити текст - - - - TimecodeEffect - - - Timecode - Тайм-код - - - - Sequence - Послідовність - - - - Media - Файл - - - - Scale - Масштаб - - - - Color - Колір - - - - Background Color - Колір фону - - - - Background Opacity - Непрозорість фону - - - - Offset - Зміщення - - - - Prepend - Префікс - - - - Timeline - - - Pointer Tool - Вказівник - - - - Edit Tool - Виділення - - - - Ripple Tool - Монтаж зі зміщенням - - - - Razor Tool - Підрізання - - - - Slip Tool - Прокручування зі зміщенням - - - - Slide Tool - Прокручування - - - - Hand Tool - Навігація - - - - Transition Tool - Перехід - - - - Snapping - Прилипання - - - - Zoom In - Наблизити - - - - Zoom Out - Віддалити - - - - Record audio - Запис звука - - - - Add title, solid, bars, etc. - Додати титри, заливку, тестову таблицю і т.п. - - - - Nested Sequence - Вкладена послідовність - - - - Effect already exists - Ефект вже додано - - - - Clip '%1' already contains a '%2' effect. Would you like to replace it with the pasted one or add it as a separate effect? - Кліп '%1' вже містить ефект '%2'. Хочете замінити його на вставлюваний чи додати цей ефект як окремий? - - - - Add - Додати - - - - Replace - Замінити - - - - Skip - Пропустити - - - - Do this for all conflicts found - Застосувати для всіх конфліктів - - - - Title... - Титри... - - - - Solid Color... - Суцільна заливка... - - - - Bars... - Тестова таблиця... - - - - Tone... - Звуковой сигнал… - - - - Noise... - Шум... - - - - Unsaved Project - Незбережений проект - - - - You must save this project before you can record audio in it. - Перед записом звука необхідно зберегти проект. - - - - Click on the timeline where you want to start recording (drag to limit the recording to a certain timeframe) - Клікніть на монтажному столі у точці, куди хочете почати запис звука (перетягніть курсор після кліка щоб відразу встановити тривалість запису) - - - - Timeline: - Монтажний стіл: - - - - (none) - (пусто) - - - - TimelineHeader - - - Center Timecodes - Центрувати тайм-код - - - - TimelineWidget - - - &Undo - &Відмінити - - - - &Redo - По&вернути - - - - C&ut - Ви&різати - - - - Cop&y - С&копіювати - - - - &Paste - В&ставити - - - - R&ipple Delete - Ви&далити зі зміщенням - - - - Sequence Settings - Параметри послідовності - - - - &Speed/Duration - &Швидкість/Тривалість - - - - Auto-s&cale - Авто&масштабування - - - - &Reveal in Project - &Показати в проекті - - - - Properties - Властивості - - - - %1 -Start: %2 -End: %3 -Duration: %4 - %1 -Початок: %2 -Кінець: %3 -Тривалість: %4 - - - - Error - Помилка - - - - Couldn't locate media wrapper for sequence. - Уточнити - Не вдається визначити обробник медіа для послідовності. - - - - Title - Титри - - - - Solid Color - Суцільна заливка - - - - Bars - Тестова таблиця - - - - Tone - Звуковой сигнал - - - - Noise - Шум - - - - Duration: - Тривалість: - - - - ToneEffect - - - Type - Тип - - - - Frequency - Частота - - - - Amount - Кількість - - - - Mix - Змішування - - - - TransformEffect - - - Position - Позиція - - - - Scale - Масштаб - - - - Uniform Scale - Зберігати масштаб - - - - Rotation - Обертання - - - - Anchor Point - Якірна точка - - - - Opacity - Непрозорість - - - - Blend Mode - Режим змішування - - - - Normal - Звичайний - - - - Darken - Уточнити - Заміна темним - - - - Multiply - Множення - - - - Color Burn - Затемнення основи - - - - Linear Burn - Лінійне затемнення - - - - Lighten - Заміна світлим - - - - Screen - Екран - - - - Color Dodge - Висвітлення основи - - - - Linear Dodge (Add) - Лінійне освітлення (додати) - - - - Overlay - Перекриття - - - - Soft Light - Розсіяне світло - - - - Hard Light - Напрямлене світло - - - - Vivid Light - Яскраве світло - - - - Linear Light - Лінійне світло - - - - Pin Light - Точкове світло - - - - Hard Mix - Жорстке зміщення - - - - Difference - Різниця - - - - Exclusion - Виключення - - - - Reflect - Відзеркалення - - - - Substract - Віднімання - - - - Average - Середнє - - - - Glow - Свічення - - - - Negation - Уточнити - Відкидання - - - - Phoenix - Фенікс - - - - Transition - - - Length - Тривалість - - - - UpdateNotification - - - An update is available from the Olive website. Visit www.olivevideoeditor.org to download it. - Оновлення доступне на сайті Olive. Відвідайте www.olivevideoeditor.org для завантаження. - - - - VSTHost - - - - - Error loading VST plugin - Помилка при завантаженні плагіна VST - - - - Failed to create VST reference - Не вдалося створити зв'язок VST - - - - Failed to load VST plugin "%1": %2 - Не вдалося завантажити плагін VST "%1": %2 - - - - NOTE: You can't load 32-bit VST plugins into a 64-bit build of Olive. Please find a 64-bit version of this plugin or switch to a 32-bit build of Olive. - ПРИМІТКА: Ви не можете завантажувати 32-розрядні плагіни VST у 64-розрядний Olive. Знайдіть 64-розрядну версію цього плагіна або встановіть 32-розрядну версію Olive. - - - - NOTE: You can't load 64-bit VST plugins into a 32-bit build of Olive. Please find a 32-bit version of this plugin or switch to a 64-bit build of Olive. - ПРИМІТКА: Ви не можете завантажувати 64-розрядні плагіни VST у 32-розрядний Olive. Знайдіть 64-розрядну версію цього плагіна або встановіть 64-розрядну версію Olive. - - - - Failed to locate entry point for dynamic library. - Не вдалося визначити вхідну точку для динамічної бібліотеки. - - - - VST Error - Помилка VST - - - - Plugin's magic number is invalid - Магічний номер плагіна некоректний - - - - Plugin - Плагін - - - - Interface - Інтерфейс - - - - Show - Показати - - - - VST Plugin - Плагін VST - - - - Viewer - - - Sequence Viewer - Переглядач послідовності - - - - Media Viewer - Переглядач медіа файлів - - - - (none) - (пусто) - - - - ViewerWidget - - - Save Frame as Image... - Зберегти кадр як зображення... - - - - Show Fullscreen - Повноекранний режим - - - - Disable - Вимкнути - - - - Screen %1: %2x%3 - Екран %1: %2x%3 - - - - Zoom - Масштаб - - - - Fit - Підігнати - - - - Custom - Інше - - - - Close Media - Закрити файл - - - - Save Frame - Зберегти кадр - - - - Viewer Zoom - Масштаб перегляду - - - - Set Custom Zoom Value: - Інше значення масштаба: - - - - ViewerWindow - - - Exit Fullscreen - Вийти з повноекранного режиму - - - - VoidEffect - - - (unknown) - (невідомо) - - - - Missing Effect - Відсутній ефект - - - - VolumeEffect - - - Volume - Гучність - - - - transition - - - Invalid transition - Некоректний перехід - - - - No candidate for transition '%1'. This transition may be corrupt. Try reinstalling it or Olive. - Немає кандидата для переходу '%1'. Цей перехід може бути некоректний. Спробуйте перевстановити його або ж Olive. - - - From c4f270320bd2d43000383a9fec22a9867e576be1 Mon Sep 17 00:00:00 2001 From: app4soft Date: Wed, 20 Mar 2019 19:49:34 +0200 Subject: [PATCH 03/35] Update olive_uk.ts --- ts/olive_uk.ts | 3623 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3623 insertions(+) create mode 100644 ts/olive_uk.ts diff --git a/ts/olive_uk.ts b/ts/olive_uk.ts new file mode 100644 index 000000000..569c29024 --- /dev/null +++ b/ts/olive_uk.ts @@ -0,0 +1,3623 @@ + + + + + AboutDialog + + + Olive is a non-linear video editor. This software is free and protected by the GNU GPL. + Olive є нелінійним редактором відео. Це програмне забезпечення є вільним і захищено ліцензією GNU GPL. + + + + Olive Team is obliged to inform users that Olive source code is available for download from its website. + Olive Team інформує користувачів про те що джерельний код Olive є доступним для завантаження на сайті проекту. + + + + ActionSearch + + + Search for action... + Знайти дію... + + + + AdvancedVideoDialog + + + Advanced Video Settings + Розширені налаштування відео + + + + Pixel Format: + Формат пікселів: + + + + Threads: + Потоки: + + + + Audio + + + %1 Audio + Уточнити + %1 Аудіо + + + + Recording %1 + Запис %1 + + + + AudioNoiseEffect + + + Amount + Кількість + + + + Mix + Змішування + + + + ChannelLayoutName + + + Invalid + Уточнити + Некоректний + + + + Mono + Моно + + + + Stereo + Стерео + + + + ClipPropertiesDialog + + + "%1" Properties + Уточнити + Параметри "%1" + + + + Multiple Clip Properties + Уточнити + Параметри множинного кліпа + + + + Name: + Назва: + + + + Duration: + Тривалість: + + + + (multiple) + Уточнити + (множинний) + + + + CollapsibleWidget + + + <untitled> + <без назви> + + + + ColorButton + + + Set Color + Визначити колір + + + + CornerPinEffect + + + Top Left + Верхній Лівий + + + + Top Right + Верхній Правий + + + + Bottom Left + Нижній Лівий + + + + Bottom Right + Нижній Правий + + + + Perspective + Перспектива + + + + DebugDialog + + + Debug Log + Журнал злагодження + + + + DemoNotice + + + + Welcome to Olive! + Ласкаво просимо в Olive! + + + + Olive is a free open-source video editor released under the GNU GPL. If you have paid for this software, you have been scammed. + Olive є вільним нелінійним редактором відео створеним на умовах ліцензії GNU GPL. Якщо ви платили за це програмне забезпечення, то вас обманули. + + + + 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 + Це програмне забезпечення наразі в стадії АЛЬФА і це означає що програма є нестабільною і може працювати некоректно, має помилки та відсутні функції. Ми не несемо відповідальності тож викикористовуйте програму на власний ризик. Будь-ласка, повідомляйте нам про помилки та бажані функції через %1 + + + + Thank you for trying Olive and we hope you enjoy it! + Дякуємо що спробували і маємо надію що вам сподобаєтся Olive! + + + + Effect + + + Invalid effect + Некоректний ефект + + + + No candidate for effect '%1'. This effect may be corrupt. Try reinstalling it or Olive. + Відсутній відповідник для ефекту '%1'. Цей ефект можливо пошкоджений. Спробуйте перевстановити його або ж Olive. + + + + Save Effect Settings + Зберегти налаштування ефектів + + + + + Effect XML Settings %1 + Файли з налаштуваннями ефектів %1 + + + + Save Settings Failed + Не вдалося зберегти налаштування + + + + Failed to open "%1" for writing. + Не вдалося відкрити "%1" для запису. + + + + Load Effect Settings + Завантажити налаштування ефектів + + + + + Load Settings Failed + Не вдалося завантажити налаштування + + + + Failed to open "%1" for reading. + Не вдалося відкрити "%1" для зчитування. + + + + This settings file doesn't match this effect. + Цей файл налаштувань не підходить для даного ефекта. + + + + EffectControls + + + (none) + (пусто) + + + + Effects: + Ефекти: + + + + Add Video Effect + Додати відеоефект + + + + VIDEO EFFECTS + ВІДЕОЕФЕКТИ + + + + Add Video Transition + Додати відеоперехід + + + + Add Audio Effect + Додати аудіоефект + + + + AUDIO EFFECTS + АУДІОЕФЕКТИ + + + + Add Audio Transition + Додати аудіоперехід + + + + EffectRow + + + Disable Keyframes + Вимкнути ключові кадри + + + + Disabling keyframes will delete all current keyframes. Are you sure you want to do this? + Вимкнення ключових кадрів видалить усі існуючі ключові кадри. Ви впевнені що хочете зробити це? + + + + EffectUI + + + %1 (Opening) + Уточнити + %1 (Відкривання) + + + + %1 (Closing) + Уточнити + %1 (Закривання) + + + + %1 (multiple) + Уточнити + %1 (множинний) + + + + Cu&t + Ви&різати + + + + &Copy + &Копіювати + + + + Move &Up + Перемістити В&низ + + + + Move &Down + Перемістити В&гору + + + + D&elete + Ви&далити + + + + Load Settings From File + Завантажити налаштування з файла + + + + Save Settings to File + Зберегти налаштування у файл + + + + EmbeddedFileChooser + + + File: + Файл: + + + + ExportDialog + + + Export "%1" + Експортувати "%1" + + + + Unknown codec name %1 + Невідома назва кодека %1 + + + + Export Failed + Не вдалося експортувати + + + + Export failed - %1 + Не вдалося експортувати - %1 + + + + Invalid dimensions + Некоректні розміри кадра + + + + Export width and height must both be even numbers/divisible by 2. + Для експорту значення ширини та висоти повинні бути цілими парними числами. + + + + Invalid codec + Некоректний кодек + + + + Couldn't determine output parameters for the selected codec. This is a bug, please contact the developers. + Неможливо визначити вихідні параметри для обраного кодека. Це помилка, будь-ласка, зв'яжітся з розробниками. + + + + Invalid format + Некоректний формат + + + + Couldn't determine output format. This is a bug, please contact the developers. + Неможливо визначити вихідний формат. Це помилка, будь-ласка, зв'яжітся з розробниками. + + + + Export Media + Уточнити + Експортувати медіафайл + + + + %p% (Total: %1:%2:%3) + Уточнити + %p% (Загалом: %1:%2:%3) + + + + %p% (ETA: %1:%2:%3) + %p% (Залишилося: %1:%2:%3) + + + + Quality-based (Constant Rate Factor) + Уточнити + Якість (Constant Rate Factor) + + + + Constant Bitrate + Стала швидкість потока + + + + + Invalid Codec + Некоректний кодек + + + + Failed to find a suitable encoder for this codec. Export will likely fail. + Не вдалося знайти відповідний кодувальник для цього кодека. Експорт може бути некоректним. + + + + Failed to find pixel format for this encoder. Export will likely fail. + Не вдалося знайти формат пікселів для цього кодувальника. Експорт може бути некоректним. + + + + Bitrate (Mbps): + Швидкість потока (Мбіт/с): + + + + Quality (CRF): + Якість (CRF): + + + + Quality Factor: + +0 = lossless +17-18 = visually lossless (compressed, but unnoticeable) +23 = high quality +51 = lowest quality possible + Коефіцієнт Якості: + +0 = без втрат +17-18 = візульно без втрат (стиснуто, але майже непомітно) +23 = висока якість +51 = найнижча можлива якість + + + + Target File Size (MB): + Кінцевий розмір файла (Мб): + + + + Format: + Формат: + + + + Range: + Діапазон: + + + + Entire Sequence + Уся послідовність + + + + In to Out + Від входу до виходу + + + + Video + Відео + + + + + Codec: + Кодек: + + + + Width: + Ширина: + + + + Height: + Висота: + + + + Frame Rate: + Частота кадрів: + + + + Compression Type: + Тип cтискання: + + + + Advanced + Додатково + + + + Audio + Аудіо + + + + Sampling Rate: + Частота дискретизації: + + + + Bitrate (Kbps/CBR): + Швидкість потока (Кбіт/с / CBR): + + + + ExportThread + + + failed to send frame to encoder (%1) + не вдалося надіслати кадр до кодувальника (%1) + + + + failed to receive packet from encoder (%1) + не вдалося отримати пакет від кодувальника (%1) + + + + could not video encoder for %1 + не вдалося знайти кодувальник відео для %1 + + + + could not allocate video stream + не вдалося встановити поток відео + + + + could not allocate video encoding context + не вдалося встановити контекст кодувльника відео + + + + could not open output video encoder (%1) + не вдалося відкрити вихідний кодувальник відео (%1) + + + + could not copy video encoder parameters to output stream (%1) + не вдалося скопіювати параметри кодувальника відео для вихідного потоку (%1) + + + + could not audio encoder for %1 + не вдалося знайти кодувальник аудіо для %1 + + + + could not allocate audio stream + не вдалося встановити поток аудіо + + + + could not allocate audio encoding context + не вдалося встановити контекст кодувльника аудіо + + + + could not open output audio encoder (%1) + не вдалося відкрити вихідний кодувальник аудіо (%1) + + + + could not copy audio encoder parameters to output stream (%1) + не вдалося скопіювати параметри кодувальника аудіо для вихідного потоку (%1) + + + + could not allocate audio buffer (%1) + не вдалося встановити буфер аудіо (%1) + + + + could not create output format context + не вдалося створити контекст вихідного формату + + + + could not open output file (%1) + не вдалося відкрити вихідний файл (%1) + + + + could not write output file header (%1) + не вдалося записати заголовок вихідного файлу (%1) + + + + could not write output file trailer (%1) + Уточнити + не вдалося записати кінець вихідного файла (%1) + + + + FillLeftRightEffect + + + Type + Тип + + + + Fill Left with Right + Заповнити лівий канал правим + + + + Fill Right with Left + Заповнити правий канал лівим + + + + Frei0rEffect + + + Failed to load Frei0r plugin "%1": %2 + Не вдалося завантажити плагін Frei0r "%1": %2 + + + + NOTE: You can't load 32-bit Frei0r plugins into a 64-bit build of Olive. Please find a 64-bit version of this plugin or switch to a 32-bit build of Olive. + ПРИМІТКА: Ви не можете завантажувати 32-розрядні плагіни Frei0r у 64-розрядний Olive. Знайдіть 64-розрядну версію цього плагіна або встановіть 32-розрядну версію Olive. + + + + NOTE: You can't load 64-bit Frei0r plugins into a 32-bit build of Olive. Please find a 32-bit version of this plugin or switch to a 64-bit build of Olive. + ПРИМІТКА: Ви не можете завантажувати 64-розрядні плагіни Frei0r у 32-розрядний Olive. Знайдіть 64-розрядну версію цього плагіна або встановіть 64-розрядну версію Olive. + + + + Error loading Frei0r plugin + Помилка при завантаженні плагіна Frei0r + + + + GraphEditor + + + Graph Editor + Редактор графів + + + + Linear + Лінійний + + + + Bezier + Безьє + + + + Hold + Уточнити + Стала + + + + GraphView + + + Zoom to Selection + Масштабувати до виділеного + + + + Zoom to Show All + Масштабувати і показати все + + + + Reset View + Скинути масштабування + + + + InterlacingName + + + None (Progressive) + Ні (прогресивно) + + + + Top Field First + Спочатку верхне поле + + + + Bottom Field First + Спочатку нижнє поле + + + + Invalid + Некоректно + + + + KeyframeNavigator + + + Enable Keyframes + Увімкнути ключові кадри + + + + KeyframeView + + + Linear + Лінійний + + + + Bezier + Безьє + + + + Hold + Уточнити + Стала + + + + LabelSlider + + + &Edit + &Редагувати + + + + &Reset to Default + Уточнити + &Скинути до стандартних + + + + + Set Value + Встановити значення + + + + + New value: + Нове значення: + + + + LoadDialog + + + Loading... + Завантаження... + + + + Loading '%1'... + Завантажується '%1'... + + + + Cancel + Уточнити + Відміна + + + + LoadThread + + + Version Mismatch + Невідповіність версій + + + + This project was saved in a different version of Olive and may not be fully compatible with this version. Would you like to attempt loading it anyway? + Цей проект булр збережено в іншій версії Olive, котра неповністью сумісна з наявною версією. Ви все ж хочете спробувати завантажити цей проект? + + + + Invalid Clip Link + Некоректний зв'язок кліпів + + + + This project contains an invalid clip link. It may be corrupt. Would you like to continue loading it? + У проекті виявлено некоректний зв'язок кліпів. Ви хочете продовжити завантаження? + + + + %1 - Line: %2 Col: %3 + %1 - Рядок: %2 Стовпчик: %3 + + + + User aborted loading + Завантаження зупинено користувачем + + + + XML Parsing Error + Помилка розбору XML + + + + Couldn't load '%1'. %2 + Не вдалося завантажити '%1'. %2 + + + + Project Load Error + Помилка при завантаженні проекта + + + + Error loading project: %1 + Помилка при завантаженні проекта: %1 + + + + MainWindow + + + Welcome to %1 + Вітаємо в %1 + + + + &File + &Файл + + + + &New + &Новий + + + + &Open Project + &Відкрити проект + + + + Clear Recent List + Очистити історію + + + + Open Recent + Відкрити недавній + + + + &Save Project + &Зберегти проект + + + + Save Project &As + Зберегти проект &як + + + + &Import... + &Імпортувати... + + + + &Export... + &Експортувати... + + + + E&xit + Ви&хід + + + + &Edit + &Редагування + + + + &Undo + &Відмінити + + + + Redo + Повернути + + + + Select &All + Виділити &усе + + + + Deselect All + Скасувати виділення + + + + Ripple to In Point + Зсунути до точки входу + + + + Ripple to Out Point + Зсунути до точки виходу + + + + Edit to In Point + Редагування до точки входу + + + + Edit to Out Point + Редагування до точки виходу + + + + Delete In/Out Point + Видалити точку входу/виходу + + + + Ripple Delete In/Out Point + Видалити зі зміщенням точку входу/виходу + + + + Set/Edit Marker + Встановити/Редагувати маркер + + + + &View + &Вигляд + + + + Zoom In + Наблизити + + + + Zoom Out + Віддалити + + + + Increase Track Height + Збільшити висоту доріжки + + + + Decrease Track Height + Зменшити висоту доріжки + + + + Toggle Show All + Уточнити + Показувати увесь проект + + + + Track Lines + Лінії доріжок + + + + Rectified Waveforms + Хвильова форма від низу + + + + Frames + Кадри + + + + Drop Frame + З пропусканням кадрів + + + + Non-Drop Frame + Без пропускання кадрів + + + + Milliseconds + Мілісекунди + + + + Title/Action Safe Area + Уточнити + Безпечна зона титрів/ефекта + + + + Off + Вимкнено + + + + Default + Типово + + + + 4:3 + 4:3 + + + + 16:9 + 16:9 + + + + Custom + Інше + + + + Full Screen + Повноекранний режим + + + + Full Screen Viewer + Перегляд в повноекранному режимі + + + + &Playback + Від&творення + + + + Go to Start + На початок + + + + Previous Frame + Попередній кадр + + + + Play/Pause + Відтворення/Пауза + + + + Play In to Out + Відтворити від входу до виходу + + + + Next Frame + Наступний кадр + + + + Go to End + У кінець + + + + Go to Previous Cut + До попереднього розрізу + + + + Go to Next Cut + До наступного розрізу + + + + Go to In Point + До точки входу + + + + Go to Out Point + До точки виходу + + + + Shuttle Left + Уточнити + Зменшити швидкість + + + + Shuttle Stop + Уточнити + Пауза + + + + Shuttle Right + Уточнити + Збільшити швидкість + + + + Loop + Уточнити + Повторення петлі + + + + &Window + &Вікно + + + + Project + Проект + + + + Effect Controls + Керування ефектами + + + + Timeline + Монтажний стіл + + + + Graph Editor + Редактор графів + + + + Media Viewer + Уточнити + Переглядач медіа файлів + + + + Sequence Viewer + Уточнити + Переглядач послідовності + + + + Maximize Panel + Розгорнути панель + + + + Lock Panels + Зафіксувати панель + + + + Reset to Default Layout + Повернути початкове розташування панелей + + + + &Tools + &Інструменти + + + + Pointer Tool + Уточнити + Вказівник + + + + Edit Tool + Виділення + + + + Ripple Tool + Монтаж зі зсувом + + + + Razor Tool + Підрізка + + + + Slip Tool + Прокручування зі зміщенням + + + + Slide Tool + Прокручування + + + + Hand Tool + Уточнити + Навігація + + + + Transition Tool + Перехід + + + + Enable Snapping + Увімкнути прилипання + + + + Selecting Also Seeks + Виділення з прокручуванням + + + + Edit Tool Also Seeks + Уточнити + Виділення з прокручуванням + + + + Edit Tool Selects Links + Виділення обирає зв'язки + + + + Seek Also Selects + Прокручування з виділенням + + + + Seek to the End of Pastes + Прокручування до кінця вставок + + + + Scroll Wheel Zooms + Уточнити + Колесо миші масштабує монтажний стіл + + + + Hold CTRL to toggle this setting + Утримуйте CTRL для перемикання цього налаштування + + + + Invert Timeline Scroll Axes + Уточнити + Інвертувати напрямки прокручування монтажного столу + + + + Enable Drag Files to Timeline + Уточнити + Дозволити переміщення файлів на монтажний стіл + + + + Auto-Scale By Default + Автомасштабування за умовчанням + + + + Enable Seek to Import + Уточнити + Увімкнути прокручування для імпортування + + + + Audio Scrubbing + Відтворювати звук під час прокручування + + + + Enable Drop on Media to Replace + Уточнити + Увімкнути переміщення на медіа для заміни + + + + Enable Hover Focus + Увімкнути фокус наведенням + + + + Ask For Name When Setting Marker + Запитувати назву маркера при додаванні + + + + No Auto-Scroll + Без автопрокручування + + + + Page Auto-Scroll + Авторокручування перегортанням + + + + Smooth Auto-Scroll + Плавне автопрокручування + + + + Preferences + Параметри + + + + Clear Undo + Очистити історію змін + + + + &Help + &Довідка + + + + A&ction Search + По&шук дії + + + + Debug Log + Журнал злагодження + + + + &About... + &Про програму... + + + + <untitled> + <без назви> + + + + Marker + + + Set Marker + Встановити маркер + + + + Set clip marker name: + Назва маркера кліпу: + + + + Set sequence marker name: + Назва маркера послідовності: + + + + Media + + + New Folder + Нова тека + + + + Name: + Назва: + + + + Filename: + Ім'я файла: + + + + Video Dimensions: + Розмір кадрів: + + + + Frame Rate: + Частота кадрів: + + + + %1 field(s) (%2 frame(s)) + Уточнити + полів: %1 (кадрів: %2) + + + + Interlacing: + Черезрядковість: + + + + Audio Frequency: + Частота звука: + + + + Audio Channels: + Звукові канали: + + + + Name: %1 +Video Dimensions: %2x%3 +Frame Rate: %4 +Audio Frequency: %5 +Audio Layout: %6 + Назва: %1 +Розмір кадрів: %2x%3 +Частота кадрів: %4 +Частота звука: %5 +Звукові канали: %6 + + + + Name + Назва + + + + Duration + Тривалість + + + + Rate + Частота + + + + MediaPropertiesDialog + + + "%1" Properties + Властивості "%1" + + + + Tracks: + Доріжок: + + + + Video %1: %2x%3 %4FPS + Відео %1: %2x%3 %4к/c + + + + Audio %1: %2Hz %3 + Аудіо %1: %2Гц %3 + + + + %n channel(s) + + %n канал + %n канали + %n каналів + + + + + Conform to Frame Rate: + Підігнати до частоти кадрів: + + + + Alpha is Premultiplied + Уточнити + Альфа-значення помножено у зворотньому порядку + + + + Auto (%1) + Авто (%1) + + + + Interlacing: + Черезрядковість: + + + + Name: + Назва: + + + + MenuHelper + + + &Project + &Проект + + + + &Sequence + П&ослідовність + + + + &Folder + Т&ека + + + + Set In Point + Встановити точку входа + + + + Set Out Point + Встановити точку вихода + + + + Reset In Point + Скинути точку входа + + + + Reset Out Point + Скинути точку вихода + + + + Clear In/Out Point + Очистити точку входа/вихода + + + + Add Default Transition + Додати типовий перехід + + + + Link/Unlink + Зв'язати/Прибрати зв'язок + + + + Enable/Disable + Увімкнути/Вимкнути + + + + Nest + Вкласти + + + + Cu&t + Ви&різати + + + + Cop&y + С&копіювати + + + + + &Paste + В&ставити + + + + Paste Insert + Уточнити + Вставити з заміною + + + + Duplicate + Дюблювати + + + + Delete + Видалити + + + + Ripple Delete + Видалити зі зміщенням + + + + Split + Розділити + + + + Invalid aspect ratio + Некоректні пропорції сторін + + + + The aspect ratio '%1' is invalid. Please try again. + Пропорції сторін '%1' є некоректними. Будь-ласка, спробуйте ще раз. + + + + Enter custom aspect ratio + Встановіть інші пропорції сторін + + + + Enter the aspect ratio to use for the title/action safe area (e.g. 16:9): + Встановіть пропорції сторін для безпечної зони титрів/ефекта (наприклад, 16:9): + + + + NewSequenceDialog + + + Editing "%1" + Редагування "%1" + + + + New Sequence + Нова послідовність + + + + Preset: + Уточнити + Профіль: + + + + Film 4K + Фільм 4К + + + + TV 4K (Ultra HD/2160p) + TV 4K (Ultra HD/2160p) + + + + 1080p + 1080p + + + + 720p + 720p + + + + 480p + 480p + + + + 360p + 360p + + + + 240p + 240p + + + + 144p + 144p + + + + NTSC (480i) + NTSC (480i) + + + + PAL (576i) + PAL (576i) + + + + Custom + Інше + + + + Video + Відео + + + + Width: + Ширина: + + + + Height: + Висота: + + + + Frame Rate: + Частота кадрів: + + + + Pixel Aspect Ratio: + Пропорції сторін пікселів: + + + + Square Pixels (1.0) + Квадратні пікселі (1.0) + + + + Interlacing: + Черезрядковість: + + + + None (Progressive) + Ні (прогресивно) + + + + Audio + Аудіо + + + + Sample Rate: + Частота дискретизації: + + + + Name: + Назва: + + + + OliveGlobal + + + Olive Project %1 + Olive Проект %1 + + + + Auto-recovery + Автовідновлення + + + + Olive didn't close properly and an autorecovery file was detected. Would you like to open it? + Olive аварійно завершив роботу і виявив файл автовідновлення. Відкрити його? + + + + Open Project... + Відкрити проект... + + + + Missing recent project + Відсутній недавній проект + + + + The project '%1' no longer exists. Would you like to remove it from the recent projects list? + Проект '%1' більше не існує. Видалити його з історії? + + + + Save Project As... + Зберегти проект як... + + + + Unsaved Project + Незбережений проект + + + + This project has changed since it was last saved. Would you like to save it before closing? + Проект було змінено з момента останнього збереження. Хочете зберегти його перед закриттям? + + + + No active sequence + Немає активних послідовностей + + + + Please open the sequence you wish to export. + Будь-ласка, відкрийте послідовність котру хочете експортувати. + + + + Missing Project File + Відсутній файл проекта + + + + Specified project '%1' does not exist. + Вказаний проект '%1' не існує. + + + + PanEffect + + + Pan + Уточнити + Панорама + + + + PreferencesDialog + + + Preferences + Параметри + + + + Invalid CSS File + Некоректний файл CSS + + + + CSS file '%1' does not exist. + Файл CSS '%1' не існує. + + + + Confirm Reset All Shortcuts + Підтвердіть скидання всіх комбінацій клавіш + + + + Are you sure you wish to reset all keyboard shortcuts to their defaults? + Ви дійсно хочете скинути всі комбінації клавіш до типових значень? + + + + Import Keyboard Shortcuts + Імпортувати комбінації клавіш + + + + + Error saving shortcuts + Помилка при збереженні комбінацій клавіш + + + + Failed to open file for reading + Не вдалося відкрити файл для читання + + + + Export Keyboard Shortcuts + Експортувати комбінації клавіш + + + + Export Shortcuts + Експортувати комбінації клавіш + + + + Shortcuts exported successfully + Комбінації клавіш експортовано + + + + Failed to open file for writing + Не вдалося відкрити файл для запису + + + + Browse for CSS file + Обрати файл CSS + + + + Delete All Previews + Видалити усі мініатюри + + + + Are you sure you want to delete all previews? + Дійсно видалити усі мініатюри? + + + + Previews Deleted + Мініатюри видалено + + + + All previews deleted succesfully. You may have to re-open your current project for changes to take effect. + Уточнити + Усі мініатюри видалено. Можливо знадобится перевідкрити поточний проект для того щоб зміни вступили в силу. + + + + Language: + Мова: + + + + Image sequence formats: + Формати зображень: + + + + Thumbnail Resolution: + Розмір мініатюр: + + + + Waveform Resolution: + Деталізація хвильових форм: + + + + Delete Previews + Видалити мініатюри + + + + Use Software Fallbacks When Possible + По можливості використовувати програмну реалізацію + + + + Default Sequence Settings + Типові налаштування послідовності + + + + General + Загальні + + + + Behavior + Поведінка + + + + Appearance + Вигляд + + + + Theme + Тема + + + + Olive Dark (Default) + Olive Dark (типово) + + + + Olive Light + Olive Light + + + + Native + Уточнити + Native + + + + Native (Light Icons) + Уточнити + Native (світлі іконки) + + + + Use Native Menu Styling + Уточнити + Використовувати стиль меню Native + + + + Custom CSS: + Інший CSS: + + + + Browse + Уточнити + Обрати + + + + Effect Textbox Lines: + Кількість рядків у полі вводу тексту: + + + + Seeking + Позиціонування + + + + Accurate Seeking +Always show the correct frame (visual may pause briefly as correct frame is retrieved) + Точне позиціонування +Завжди показувати правильний кадр (відображення може уповільнюватися) + + + + Fast Seeking +Seek quickly (may briefly show inaccurate frames when seeking - doesn't affect playback/export) + Швидке позиціонування +Позиціонувати швидко (можливе неточне відображення кадрів - не впливає на відтворення) + + + + Memory Usage + Використання пам'яті + + + + Upcoming Frame Queue: + Резервування послідуючих кадрів: + + + + + frames + кадрів + + + + + seconds + секунд + + + + Previous Frame Queue: + Резервування попередніх кадрів: + + + + Playback + Відтворення + + + + Output Device: + Пристрій виводу: + + + + + Default + Типово + + + + Input Device: + Пристрій вводу: + + + + Sample Rate: + Частота дискретизації: + + + + Audio Recording: + Запис звука: + + + + Mono + Моно + + + + Stereo + Стерео + + + + Audio + Аудіо + + + + Search for action or shortcut + Знайти дію або комбінацію клавіш + + + + Action + Дія + + + + Shortcut + Комбінація клавіш + + + + Import + Імпортувати + + + + Export + Експортувати + + + + Reset Selected + Скинути виділення + + + + Reset All + Скинути все + + + + Keyboard + Комбінації клавіш + + + + PreviewGenerator + + + Failed to find any valid video/audio streams + Не вдалося знайти коректні відео/аудіо потоки + + + + Could not open file - %1 + Не вдалося відкрити файл — %1 + + + + Could not find stream information - %1 + Не вдалося знайти інформацію потоку — %1 + + + + Project + + + Search media, markers, etc. + Шукати файли, маркери, і т.п. + + + + Project + Проект + + + + Sequence + Послідовність + + + + Replace '%1' + Замінити '%1' + + + + + All Files + Усі файли + + + + + No active sequence + Немає активних послідовностей + + + + No sequence is active, please open the sequence you want to replace clips from. + Немає активних послідовносте. Відкрийте послідовність в якій хочете замінити кліпи. + + + + Active sequence selected + Обрано активну послідовність + + + + You cannot insert a sequence into itself, so no clips of this media would be in this sequence. + Уточнити + Ви не можете вставити послідовність в саму себе, тож кліпи з цих файлів не можуть бути вставлені в цю послідовність. + + + + Rename '%1' + Перейменувати '%1' + + + + Enter new name: + Введіть нову назву: + + + + Delete media in use? + Уточнити + Видалити використані у проекті файли? + + + + The media '%1' is currently used in '%2'. Deleting it will remove all instances in the sequence. Are you sure you want to do this? + Файл '%1' вже використовується у '%2'. Його видалення приведе до видалення усіх його копій у вибраній послідовності. Ви точно цього хочете? + + + + Skip + Пропустити + + + + Import a Project + Імпортувати проект + + + + "%1" is an Olive project file. It will merge with this project. Do you wish to continue? + "%1" є файлом проекту Olive. Його буде об'єднано з поточним проектом. Ви хочете продовжити? + + + + Image sequence detected + Виявлено послідовність зображень + + + + The file '%1' appears to be part of an image sequence. Would you like to import it as such? + Схоже що файл '%1' є частиною послідовності зображень. Імпортувати його як є? + + + + Import media... + Імпортувати медіафайли... + + + + No sequence is active, please open the sequence you want to delete clips from. + Немає активних послідовносте. Відкрийте послідовність з якої хочете видалити кліпи. + + + + ProxyDialog + + + Create Proxy + Створити проксі + + + + Proxy + Проксі + + + + Dimensions: + Розміри: + + + + Same Size as Source + Оригінальний розмір + + + + Half Resolution (1/2) + Половина оригінала (1/2) + + + + Quarter Resolution (1/4) + Чверть оригіналу (1/4) + + + + Eighth Resolution (1/8) + Восьма оригиніалу (1/8) + + + + Sixteenth Resolution (1/16) + Шістнадцята оригіналу (1/16) + + + + Format: + Формат: + + + + ProRes HQ + ProRes HQ + + + + Location: + Розташування: + + + + Same as Source (in "%1" folder) + Як в оригіналі (у теці "%1") + + + + Proxy file exists + Проксі-файл вже існує + + + + The file "%1" already exists. Do you wish to replace it? + Файл "%1" вже існує. Замінити його? + + + + Custom Location + Інше місцезнаходження + + + + ProxyGenerator + + + Finished generating proxy for "%1" + Завершено створення проксі для "%1" + + + + ReplaceClipMediaDialog + + + Replace clips using "%1" + Замінити кліпи на "%1" + + + + Select which media you want to replace this media's clips with: + Оберіть файли, які хочете замінити у кліпах з цими файлами: + + + + Keep the same media in-points + Зберегти існуючі точки входу + + + + Replace + Замінити + + + + Cancel + Відмінити + + + + No media selected + Не обрано медіафайли + + + + Please select a media to replace with or click 'Cancel'. + Оберіть медіафайли для заміни та натисніть «Відміна». + + + + Same media selected + Обрано ті ж самі файли + + + + You selected the same media that you're replacing. Please select a different one or click 'Cancel'. + Ви обрали ті ж самі файли, що й хочете замінити. Оберіть якісь інші файли або ж натисніть «Відміна». + + + + Folder selected + Теку обрано + + + + You cannot replace footage with a folder. + Ви не можете замінити відеоряд текою. + + + + Active sequence selected + Обрано активну послідовність + + + + You cannot insert a sequence into itself. + Ви не можете вставити послідовність в саму себе. + + + + RichTextEffect + + + Text + Текст + + + + Padding + Уточнити + Відступ + + + + Position + Позиція + + + + Vertical Align: + Верктикальне вирівнювання: + + + + Top + Вгорі + + + + Center + По центру + + + + Bottom + Внизу + + + + Auto-Scroll + Автопрокручування + + + + Off + Вимкнено + + + + Up + Вгору + + + + Down + Вниз + + + + Left + Вліво + + + + Right + Вправо + + + + Shadow + Тінь + + + + Shadow Color + Колір тіні + + + + Shadow Angle + Кут падіння тіні + + + + Shadow Distance + Відстань до тіні + + + + Shadow Softness + Розсіювання тіні + + + + Shadow Opacity + Непрозорість тіні + + + + Sequence + + + %1 (copy) + %1 (копія) + + + + ShakeEffect + + + Intensity + Інтенсивність + + + + Rotation + Обертання + + + + Frequency + Частота + + + + SolidEffect + + + Type + Тип + + + + Solid Color + Суцільна заливка + + + + SMPTE Bars + Таблиця SMPTE + + + + Checkerboard + Шахівниця + + + + Opacity + Непрозорість + + + + Color + Колір + + + + Checkerboard Size + Розмір клітинок + + + + SourcesCommon + + + Import... + Імпортувати... + + + + New + Створити + + + + View + Вигляд + + + + Tree View + У вигляді таблиці + + + + Icon View + У вигляді мініатюр + + + + Show Toolbar + Показувати панель + + + + Show Sequences + Показувати послідовності + + + + Replace/Relink Media + Уточнити + Замінити/Перезв'язати файли + + + + Reveal in Explorer + Відкрити у Explorer + + + + Reveal in Finder + Відкрити у Finder + + + + Reveal in File Manager + Відкрити у менеджері файлів + + + + Replace Clips Using This Media + Уточнити + Замінити кліпи з цими файлами + + + + Create Sequence With This Media + Створити послідовність з цими файлами + + + + Duplicate + Дублювати + + + + Delete All Clips Using This Media + Уточнити + Видалити усі кліпи з цими файлами + + + + Proxy + Проксі + + + + Generating proxy: %1% complete + Створення проксі: завершено на %1% + + + + Create/Modify Proxy + Створити/Змінити проксі + + + + Create Proxy + Створити проксі + + + + Modify Proxy + Змінити проксі + + + + Restore Original + Відновити оригінал + + + + Delete + Видалити + + + + Preview in Media Viewer + Переглянути у Переглядачі медіа файлів + + + + Properties... + Властивості... + + + + Replace Media + Замінити медіафайли + + + + You dropped a file onto '%1'. Would you like to replace it with the dropped file? + Ви перетягнули файл на '%1'. Ви хочете замінити на цей файл? + + + + Delete proxy + Видалити проксі + + + + Would you like to delete the proxy file "%1" as well? + Заразом видалити проксі-файл "%1"? + + + + SpeedDialog + + + Speed/Duration + Швидкість/Тривалість + + + + Speed: + Швидкість: + + + + Frame Rate: + Частота кадрів: + + + + Duration: + Тривалість: + + + + Reverse + Реверс + + + + Maintain Audio Pitch + Зберегти висоту тона + + + + Ripple Changes + Змінювати зі зміщенням + + + + TextEditDialog + + + Edit Text + Змінити текст + + + + Thin + Уточнити + Thin + + + + Extra Light + Уточнити + Extra Light + + + + Light + Уточнити + Light + + + + Normal + Уточнити + Normal + + + + Medium + Уточнити + Medium + + + + Demi Bold + Уточнити + Demi Bold + + + + Bold + Уточнити + Bold + + + + Extra Bold + Уточнити + Extra Bold + + + + Black + Уточнити + Black + + + + TextEditEx + + + &Edit Text + &Редагувати Текст + + + + TextEffect + + + Text + Текст + + + + Font + Шрифт + + + + Size + Розмір + + + + Color + Колір + + + + Alignment + Вирівнювання + + + + Left + Ліворуч + + + + + Center + По центру + + + + Right + Праворуч + + + + Justify + По ширині + + + + Top + Вгорі + + + + Bottom + Внизу + + + + Word Wrap + Перенесення слів + + + + Padding + Відступ + + + + Position + Позиція + + + + Outline + Контури + + + + Outline Color + Колір контурів + + + + Outline Width + Ширина контурів + + + + Shadow + Тінь + + + + Shadow Color + Колір тіні + + + + Shadow Angle + Кут падіння тіні + + + + Shadow Distance + Відстань до тіні + + + + Shadow Softness + Розсіювання тіні + + + + Shadow Opacity + Непрозорість тіні + + + + Sample Text + Зразок тексту + + + + TimecodeEffect + + + Timecode + Тайм-код + + + + Sequence + Послідовність + + + + Media + Файл + + + + Scale + Масштаб + + + + Color + Колір + + + + Background Color + Колір фону + + + + Background Opacity + Непрозорість фону + + + + Offset + Зміщення + + + + Prepend + Префікс + + + + Timeline + + + Pointer Tool + Вказівник + + + + Edit Tool + Виділення + + + + Ripple Tool + Монтаж зі зміщенням + + + + Razor Tool + Підрізання + + + + Slip Tool + Прокручування зі зміщенням + + + + Slide Tool + Прокручування + + + + Hand Tool + Навігація + + + + Transition Tool + Перехід + + + + Snapping + Прилипання + + + + Zoom In + Наблизити + + + + Zoom Out + Віддалити + + + + Record audio + Запис звука + + + + Add title, solid, bars, etc. + Додати титри, заливку, тестову таблицю, і т.п. + + + + Nested Sequence + Вкладена послідовність + + + + Effect already exists + Ефект уже додано + + + + Clip '%1' already contains a '%2' effect. Would you like to replace it with the pasted one or add it as a separate effect? + Кліп '%1' уже містить ефект '%2'. Хочете замінити його на вставлюваний чи додати цей ефект як окремий? + + + + Add + Додати + + + + Replace + Замінити + + + + Skip + Пропустити + + + + Do this for all conflicts found + Застосувати для всіх конфліктів + + + + Title... + Титри... + + + + Solid Color... + Суцільна заливка... + + + + Bars... + Тестова таблиця... + + + + Tone... + Звуковой сигнал… + + + + Noise... + Шум... + + + + Unsaved Project + Незбережений проект + + + + You must save this project before you can record audio in it. + Перед записом звука необхідно зберегти проект. + + + + Click on the timeline where you want to start recording (drag to limit the recording to a certain timeframe) + Клікніть на монтажному столі у точці, куди хочете почати запис звука (перетягніть курсор після кліка щоб відразу встановити тривалість запису) + + + + Timeline: + Монтажний стіл: + + + + (none) + (пусто) + + + + TimelineHeader + + + Center Timecodes + Центрувати тайм-код + + + + TimelineWidget + + + &Undo + &Відмінити + + + + &Redo + По&вернути + + + + R&ipple Delete Empty Space + Уточнити + Видалити зі зміщенням порожнє &місце + + + + Sequence Settings + Налаштування послідовності + + + + &Speed/Duration + &Швидкість/Тривалість + + + + Auto-s&cale + Авто&масштабування + + + + &Reveal in Project + Уточнити + &Показати у проекті + + + + Properties + Властивості + + + + %1 +Start: %2 +End: %3 +Duration: %4 + %1 +Початок: %2 +Кінець: %3 +Тривалість: %4 + + + + Error + Помилка + + + + Couldn't locate media wrapper for sequence. + Не вдається визначити обробник медіа для послідовності. + + + + Title + Титри + + + + Solid Color + Суцільна заливка + + + + Bars + Тестова таблиця + + + + Tone + Звуковой сигнал + + + + Noise + Шум + + + + Duration: + Тривалість: + + + + ToneEffect + + + Type + Тип + + + + Sine + Синусоїда + + + + Frequency + Частота + + + + Amount + Кількість + + + + Mix + Змішування + + + + TransformEffect + + + Position + Позиція + + + + Scale + Масштаб + + + + Uniform Scale + Пропорційний масштаб + + + + Rotation + Обертання + + + + Anchor Point + Якірна точка + + + + Opacity + Непрозорість + + + + Blend Mode + Режим змішування + + + + Normal + Звичайний + + + + Transition + + + Length + Тривалість + + + + UpdateNotification + + + An update is available from the Olive website. Visit www.olivevideoeditor.org to download it. + Оновлення доступне на сайті Olive. Відвідайте www.olivevideoeditor.org для завантаження. + + + + VSTHost + + + + + Error loading VST plugin + Помилка при завантаженні плагіна VST + + + + Failed to create VST reference + Не вдалося створити зв'язок VST + + + + Failed to load VST plugin "%1": %2 + Не вдалося завантажити плагін VST "%1": %2 + + + + NOTE: You can't load 32-bit VST plugins into a 64-bit build of Olive. Please find a 64-bit version of this plugin or switch to a 32-bit build of Olive. + ПРИМІТКА: Ви не можете завантажувати 32-розрядні плагіни VST у 64-розрядний Olive. Знайдіть 64-розрядну версію цього плагіна або встановіть 32-розрядну версію Olive. + + + + NOTE: You can't load 64-bit VST plugins into a 32-bit build of Olive. Please find a 32-bit version of this plugin or switch to a 64-bit build of Olive. + ПРИМІТКА: Ви не можете завантажувати 64-розрядні плагіни VST у 32-розрядний Olive. Знайдіть 64-розрядну версію цього плагіна або встановіть 64-розрядну версію Olive. + + + + Failed to locate entry point for dynamic library. + Не вдалося визначити вхідну точку для динамічної бібліотеки. + + + + VST Error + Помилка VST + + + + Plugin's magic number is invalid + Магічний номер плагіна некоректний + + + + VST Plugin + Плагін VST + + + + Plugin + Плагін + + + + Interface + Інтерфейс + + + + Show + Показати + + + + Viewer + + + (none) + (пусто) + + + + Sequence Viewer + Переглядач послідовності + + + + Media Viewer + Переглядач медіа файлів + + + + ViewerWidget + + + Save Frame as Image... + Зберегти кадр як зображення... + + + + Show Fullscreen + Повноекранний режим + + + + Disable + Вимкнути + + + + Screen %1: %2x%3 + Екран %1: %2x%3 + + + + Zoom + Масштаб + + + + Fit + Підігнати + + + + Custom + Інше + + + + Close Media + Закрити файл + + + + Save Frame + Зберегти кадр + + + + Viewer Zoom + Масштаб перегляду + + + + Set Custom Zoom Value: + Інше значення масштаба: + + + + ViewerWindow + + + Exit Fullscreen + Вийти з повноекранного режиму + + + + VoidEffect + + + (unknown) + (невідомо) + + + + Missing Effect + Відсутній ефект + + + + VolumeEffect + + + Volume + Гучність + + + + transition + + + Invalid transition + Некоректний перехід + + + + No candidate for transition '%1'. This transition may be corrupt. Try reinstalling it or Olive. + Немає кандидата для переходу '%1'. Цей перехід може бути некоректний. Спробуйте перевстановити його або ж Olive. + + + From 22b208143be1f50078c61dbb977826057946f174 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 22 Mar 2019 03:33:18 +1100 Subject: [PATCH 04/35] correct threading around clearing the viewer sequences --- panels/viewer.cpp | 63 ++++++++++++++++++++++---------------- project/projectmodel.cpp | 4 +-- rendering/renderthread.cpp | 16 ++++++++++ rendering/renderthread.h | 2 +- ui/viewerwidget.cpp | 9 +++--- ui/viewerwidget.h | 2 +- 6 files changed, 62 insertions(+), 34 deletions(-) diff --git a/panels/viewer.cpp b/panels/viewer.cpp index 9b1685bb5..911df3376 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -120,7 +120,6 @@ bool Viewer::is_main_sequence() { } void Viewer::set_main_sequence() { - clean_created_seq(); set_sequence(true, olive::ActiveSequence); } @@ -720,7 +719,8 @@ void Viewer::set_media(Media* m) { main_sequence = false; media = m; - clean_created_seq(); + SequencePtr new_sequence = nullptr; + if (media != nullptr) { switch (media->get_type()) { case MEDIA_TYPE_FOOTAGE: @@ -729,30 +729,32 @@ void Viewer::set_media(Media* m) { marker_ref = &footage->markers; - seq = std::make_shared(); + new_sequence = std::make_shared(); created_sequence = true; - seq->wrapper_sequence = true; - seq->name = footage->name; + new_sequence->wrapper_sequence = true; + new_sequence->name = footage->name; - seq->using_workarea = footage->using_inout; + new_sequence->using_workarea = footage->using_inout; if (footage->using_inout) { - seq->workarea_in = footage->in; - seq->workarea_out = footage->out; + new_sequence->workarea_in = footage->in; + new_sequence->workarea_out = footage->out; } // FIXME: Move this magic number to Config - seq->frame_rate = 30; + new_sequence->frame_rate = 30; if (footage->video_tracks.size() > 0) { const FootageStream& video_stream = footage->video_tracks.at(0); - seq->width = video_stream.video_width; - seq->height = video_stream.video_height; - if (video_stream.video_frame_rate > 0 && !video_stream.infinite_length) seq->frame_rate = video_stream.video_frame_rate * footage->speed; + new_sequence->width = video_stream.video_width; + new_sequence->height = video_stream.video_height; + if (video_stream.video_frame_rate > 0 && !video_stream.infinite_length) { + new_sequence->frame_rate = video_stream.video_frame_rate * footage->speed; + } - ClipPtr c = std::make_shared(seq.get()); + ClipPtr c = std::make_shared(new_sequence.get()); c->set_media(media, video_stream.file_index); c->set_timeline_in(0); - c->set_timeline_out(footage->get_length_in_frames(seq->frame_rate)); + c->set_timeline_out(footage->get_length_in_frames(new_sequence->frame_rate)); if (c->timeline_out() <= 0) { // FIXME: Move this magic number to Config c->set_timeline_out(150); @@ -760,25 +762,25 @@ void Viewer::set_media(Media* m) { c->set_track(-1); c->set_clip_in(0); c->refresh(); - seq->clips.append(c); + new_sequence->clips.append(c); } else { // FIXME: Move this magic number to Config - seq->width = 1920; - seq->height = 1080; + new_sequence->width = 1920; + new_sequence->height = 1080; } if (footage->audio_tracks.size() > 0) { const FootageStream& audio_stream = footage->audio_tracks.at(0); - seq->audio_frequency = audio_stream.audio_frequency; + new_sequence->audio_frequency = audio_stream.audio_frequency; - ClipPtr c = std::make_shared(seq.get()); + ClipPtr c = std::make_shared(new_sequence.get()); c->set_media(media, audio_stream.file_index); c->set_timeline_in(0); - c->set_timeline_out(footage->get_length_in_frames(seq->frame_rate)); + c->set_timeline_out(footage->get_length_in_frames(new_sequence->frame_rate)); c->set_track(0); c->set_clip_in(0); c->refresh(); - seq->clips.append(c); + new_sequence->clips.append(c); if (footage->video_tracks.size() == 0) { viewer_widget->waveform = true; @@ -788,18 +790,19 @@ void Viewer::set_media(Media* m) { } } else { // FIXME: Move this magic number to Config - seq->audio_frequency = 48000; + new_sequence->audio_frequency = 48000; } - seq->audio_layout = AV_CH_LAYOUT_STEREO; + new_sequence->audio_layout = AV_CH_LAYOUT_STEREO; } break; case MEDIA_TYPE_SEQUENCE: - seq = media->to_sequence(); + new_sequence = media->to_sequence(); break; } } - set_sequence(false, seq); + + set_sequence(false, new_sequence); } void Viewer::update_playhead() { @@ -861,7 +864,9 @@ void Viewer::clean_created_seq() { } */ + // Delete the current sequence seq.reset(); + created_sequence = false; } } @@ -871,13 +876,19 @@ void Viewer::set_sequence(bool main, SequencePtr s) { reset_all_audio(); - main_sequence = main; + viewer_widget->wait_until_render_is_paused(); // If we had a current sequence open, close it if (seq != nullptr) { close_active_clips(seq.get()); } + clean_created_seq(); + + main_sequence = main; + + + seq = (main) ? olive::ActiveSequence : s; bool null_sequence = (seq == nullptr); diff --git a/project/projectmodel.cpp b/project/projectmodel.cpp index 80e87c8d0..56caa3672 100644 --- a/project/projectmodel.cpp +++ b/project/projectmodel.cpp @@ -44,10 +44,10 @@ void ProjectModel::make_root() { void ProjectModel::destroy_root() { if (panel_sequence_viewer != nullptr) { - panel_sequence_viewer->viewer_widget->delete_function(); + panel_sequence_viewer->set_media(nullptr); } if (panel_footage_viewer != nullptr) { - panel_footage_viewer->viewer_widget->delete_function(); + panel_footage_viewer->set_media(nullptr); } root_item_ = std::make_shared(); diff --git a/rendering/renderthread.cpp b/rendering/renderthread.cpp index 1fb88308c..c8d822f56 100644 --- a/rendering/renderthread.cpp +++ b/rendering/renderthread.cpp @@ -273,6 +273,22 @@ void RenderThread::cancel() { wait(); } +void RenderThread::wait_until_paused() +{ + + // Wait for thread to finish whatever it's doing before proceeding. + // + // FIXME: This is slow. Perhaps there's a better way... + + if (wait_lock_.tryLock()) { + wait_lock_.unlock(); + return; + } else { + wait_lock_.lock(); + wait_lock_.unlock(); + } +} + void RenderThread::delete_buffers() { front_buffer_1.Destroy(); front_buffer_2.Destroy(); diff --git a/rendering/renderthread.h b/rendering/renderthread.h index 1f89d3043..b0ce750f6 100644 --- a/rendering/renderthread.h +++ b/rendering/renderthread.h @@ -60,7 +60,7 @@ public: int idivider = 0); bool did_texture_fail(); void cancel(); - + void wait_until_paused(); public slots: // cleanup functions diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index ee2de87b3..6fcdf8d74 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -90,10 +90,6 @@ ViewerWidget::~ViewerWidget() { delete renderer; } -void ViewerWidget::delete_function() { - close_active_clips(viewer->seq.get()); -} - void ViewerWidget::set_waveform_scroll(int s) { if (waveform) { waveform_scroll = s; @@ -381,6 +377,11 @@ void ViewerWidget::close_window() { window->hide(); } +void ViewerWidget::wait_until_render_is_paused() +{ + renderer->wait_until_paused(); +} + void ViewerWidget::draw_waveform_func() { QPainter p(this); if (viewer->seq->using_workarea) { diff --git a/ui/viewerwidget.h b/ui/viewerwidget.h index f01ae7063..0a5fdbbbd 100644 --- a/ui/viewerwidget.h +++ b/ui/viewerwidget.h @@ -48,8 +48,8 @@ public: ViewerWidget(QWidget *parent = nullptr); ~ViewerWidget(); - void delete_function(); void close_window(); + void wait_until_render_is_paused(); void paintGL(); void initializeGL(); From 1168ecf019aa12eb15f8eeeb8b6542fc9c1bdb82 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 22 Mar 2019 03:48:59 +1100 Subject: [PATCH 05/35] fixed faulty project closing code --- global/global.cpp | 70 +++++++++++++++++++++--------------------- global/global.h | 10 +++++- project/loadthread.cpp | 9 ++---- project/loadthread.h | 3 +- 4 files changed, 48 insertions(+), 44 deletions(-) diff --git a/global/global.cpp b/global/global.cpp index 7bde452fa..171f2f34f 100644 --- a/global/global.cpp +++ b/global/global.cpp @@ -166,18 +166,11 @@ void OliveGlobal::SetNativeStyling(QWidget *w) #endif } -void OliveGlobal::LoadProject(const QString &fn, bool autorecovery, bool clear) +void OliveGlobal::LoadProject(const QString &fn, bool autorecovery) { - // Normally, the user will be closing the previous project to load a new one, but just in case the user - // is importing a new project - - if (clear) { - new_project(); - } - LoadDialog ld(olive::MainWindow); - LoadThread* lt = new LoadThread(fn, autorecovery, clear); + LoadThread* lt = new LoadThread(fn, autorecovery); connect(&ld, SIGNAL(cancel()), lt, SLOT(cancel())); connect(lt, SIGNAL(success()), &ld, SLOT(accept())); connect(lt, SIGNAL(error()), &ld, SLOT(reject())); @@ -188,37 +181,43 @@ void OliveGlobal::LoadProject(const QString &fn, bool autorecovery, bool clear) ld.exec(); } +void OliveGlobal::ClearProject() +{ + // clear graph editor + panel_graph_editor->set_row(nullptr); + + // clear effects panel + panel_effect_controls->Clear(true); + + // clear existing project + olive::Global->set_sequence(nullptr); + panel_footage_viewer->set_media(nullptr); + + // clear project contents (footage, sequences, etc.) + panel_project->clear(); + + // clear undo stack + olive::UndoStack.clear(); + + // empty current project filename + update_project_filename(""); + + // full update of all panels + update_ui(false); + + // set to unmodified + olive::Global->set_modified(false); +} + void OliveGlobal::ImportProject(const QString &fn) { - LoadProject(fn, false, false); + LoadProject(fn, false); + set_modified(true); } void OliveGlobal::new_project() { if (can_close_project()) { - // clear graph editor - panel_graph_editor->set_row(nullptr); - - // clear effects panel - panel_effect_controls->Clear(true); - - // clear existing project - olive::Global->set_sequence(nullptr); - panel_footage_viewer->set_media(nullptr); - - // clear project contents (footage, sequences, etc.) - panel_project->clear(); - - // clear undo stack - olive::UndoStack.clear(); - - // empty current project filename - update_project_filename(""); - - // full update of all panels - update_ui(false); - - // set to unmodified - olive::Global->set_modified(false); + ClearProject(); } } @@ -359,8 +358,9 @@ void OliveGlobal::set_sequence(SequencePtr s) } void OliveGlobal::OpenProjectWorker(const QString& fn, bool autorecovery) { + ClearProject(); update_project_filename(fn); - LoadProject(fn, autorecovery, true); + LoadProject(fn, autorecovery); olive::UndoStack.clear(); } diff --git a/global/global.h b/global/global.h index 560295f7c..17c88f535 100644 --- a/global/global.h +++ b/global/global.h @@ -366,7 +366,15 @@ 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, bool clear); + 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(); /** * @brief File filter used for any file dialogs relating to Olive project files. diff --git a/project/loadthread.cpp b/project/loadthread.cpp index 578ac11c9..8cd888d81 100644 --- a/project/loadthread.cpp +++ b/project/loadthread.cpp @@ -37,10 +37,9 @@ #include #include -LoadThread::LoadThread(const QString& filename, bool autorecovery, bool clear) : +LoadThread::LoadThread(const QString& filename, bool autorecovery) : filename_(filename), autorecovery_(autorecovery), - clear_(clear), cancelled_(false) { connect(this, SIGNAL(finished()), this, SLOT(deleteLater())); @@ -779,14 +778,12 @@ void LoadThread::success_func() { counter++; } - if (clear_) { - olive::Global->update_project_filename(orig_filename); - } + olive::Global->update_project_filename(orig_filename); } else { panel_project->add_recent_project(filename_); } - olive::Global->set_modified(autorecovery_ || !clear_); + olive::Global->set_modified(autorecovery_); if (open_seq != nullptr) { olive::Global->set_sequence(open_seq); } diff --git a/project/loadthread.h b/project/loadthread.h index cdf63ae69..2a8d1a07b 100644 --- a/project/loadthread.h +++ b/project/loadthread.h @@ -35,7 +35,7 @@ class LoadThread : public QThread { Q_OBJECT public: - LoadThread(const QString& filename, bool autorecovery, bool clear); + LoadThread(const QString& filename, bool autorecovery); void run(); public slots: void cancel(); @@ -50,7 +50,6 @@ private slots: void success_func(); private: bool autorecovery_; - bool clear_; QString filename_; bool load_worker(QFile& f, QXmlStreamReader& stream, int type); From d0b7004b8f8e97b3f32a9de6b6191bde77579f31 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 22 Mar 2019 10:47:17 +1100 Subject: [PATCH 06/35] fixed folder bug --- project/loadthread.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/project/loadthread.cpp b/project/loadthread.cpp index 8cd888d81..969c23214 100644 --- a/project/loadthread.cpp +++ b/project/loadthread.cpp @@ -608,8 +608,6 @@ Media* LoadThread::find_loaded_folder_by_id(int id) { } void LoadThread::OrganizeFolders(int folder) { - qDebug() << "starting with" << folder; - for (int i=0;itemp_id2; @@ -617,7 +615,7 @@ void LoadThread::OrganizeFolders(int folder) { if (parent_id == folder) { olive::project_model.appendChild(find_loaded_folder_by_id(parent_id), item); - OrganizeFolders(parent_id); + OrganizeFolders(item->temp_id); } } From ca792a7a12f3449833eb1a01be4889de34a251da Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 22 Mar 2019 13:24:51 +1100 Subject: [PATCH 07/35] added buttons to drag just video or just audio --- olive.pro | 6 ++- panels/panels.cpp | 1 + panels/project.cpp | 4 +- panels/project.h | 3 +- panels/timeline.cpp | 57 +++++++++++++------- panels/timeline.h | 3 +- panels/viewer.cpp | 102 ++++++++++++++++++++++++++++++----- panels/viewer.h | 14 +++++ project/sourcescommon.cpp | 2 +- timeline/mediaimportdata.cpp | 17 ++++++ timeline/mediaimportdata.h | 29 ++++++++++ ui/timelinewidget.cpp | 9 ++-- ui/viewerwidget.cpp | 6 +-- 13 files changed, 204 insertions(+), 49 deletions(-) create mode 100644 timeline/mediaimportdata.cpp create mode 100644 timeline/mediaimportdata.h diff --git a/olive.pro b/olive.pro index 3fe5ca515..e86586c3f 100644 --- a/olive.pro +++ b/olive.pro @@ -174,7 +174,8 @@ SOURCES += \ undo/undostack.cpp \ effects/internal/richtexteffect.cpp \ ui/blur.cpp \ - ui/menu.cpp + ui/menu.cpp \ + timeline/mediaimportdata.cpp HEADERS += \ ui/mainwindow.h \ @@ -302,7 +303,8 @@ HEADERS += \ undo/undostack.h \ effects/internal/richtexteffect.h \ ui/blur.h \ - ui/menu.h + ui/menu.h \ + timeline/mediaimportdata.h FORMS += diff --git a/panels/panels.cpp b/panels/panels.cpp index 30af5c7f2..dbb22481a 100644 --- a/panels/panels.cpp +++ b/panels/panels.cpp @@ -87,6 +87,7 @@ void alloc_panels(QWidget* parent) { panel_sequence_viewer->setObjectName("seq_viewer"); panel_footage_viewer = new Viewer(parent); panel_footage_viewer->setObjectName("footage_viewer"); + panel_footage_viewer->show_videoaudio_buttons(true); panel_project = new Project(parent); panel_project->setObjectName("proj_root"); panel_effect_controls = new EffectControls(parent); diff --git a/panels/project.cpp b/panels/project.cpp index 47620459f..3c762ff94 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -245,7 +245,7 @@ QString Project::get_next_sequence_name(QString start) { return name; } -SequencePtr create_sequence_from_media(QVector& media_list) { +SequencePtr create_sequence_from_media(QVector& media_list) { SequencePtr s(new Sequence()); s->name = panel_project->get_next_sequence_name(); @@ -260,7 +260,7 @@ SequencePtr create_sequence_from_media(QVector& media_list) { bool got_video_values = false; bool got_audio_values = false; for (int i=0;iget_type()) { case MEDIA_TYPE_FOOTAGE: { diff --git a/panels/project.h b/panels/project.h index ace9e4404..d2984b7d1 100644 --- a/panels/project.h +++ b/panels/project.h @@ -35,6 +35,7 @@ #include "project/sourcescommon.h" #include "ui/panel.h" #include "ui/sourceiconview.h" +#include "timeline/mediaimportdata.h" #include "undo/undo.h" #include "ui/sourcetable.h" @@ -45,7 +46,7 @@ extern QString autorecovery_filename; extern QStringList recent_projects; -SequencePtr create_sequence_from_media(QVector &media_list); +SequencePtr create_sequence_from_media(QVector &media_list); QString get_channel_layout_name(int channels, uint64_t layout); QString get_interlacing_name(int interlacing); diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 37c276d9b..75caf3148 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -192,14 +192,15 @@ void Timeline::toggle_show_all() { } } -void Timeline::create_ghosts_from_media(Sequence* seq, long entry_point, QVector& media_list) { +void Timeline::create_ghosts_from_media(Sequence* seq, long entry_point, QVector& media_list) { video_ghosts = false; audio_ghosts = false; for (int i=0;iready; if (m->using_inout) { double source_fr = 30; - if (m->video_tracks.size() > 0 && !qIsNull(m->video_tracks.at(0).video_frame_rate)) source_fr = m->video_tracks.at(0).video_frame_rate * m->speed; + if (m->video_tracks.size() > 0 && !qIsNull(m->video_tracks.at(0).video_frame_rate)) { + source_fr = m->video_tracks.at(0).video_frame_rate * m->speed; + } default_clip_in = rescale_frame_number(m->in, source_fr, seq->frame_rate); default_clip_out = rescale_frame_number(m->out, source_fr, seq->frame_rate); } @@ -253,20 +256,27 @@ void Timeline::create_ghosts_from_media(Sequence* seq, long entry_point, QVector } } - for (int j=0;jaudio_tracks.size();j++) { - if (m->audio_tracks.at(j).enabled) { - g.track = j; - g.media_stream = m->audio_tracks.at(j).file_index; - ghosts.append(g); - audio_ghosts = true; + if (import_data.type() == olive::timeline::kImportAudioOnly + || import_data.type() == olive::timeline::kImportBoth) { + for (int j=0;jaudio_tracks.size();j++) { + if (m->audio_tracks.at(j).enabled) { + g.track = j; + g.media_stream = m->audio_tracks.at(j).file_index; + ghosts.append(g); + audio_ghosts = true; + } } } - for (int j=0;jvideo_tracks.size();j++) { - if (m->video_tracks.at(j).enabled) { - g.track = -1-j; - g.media_stream = m->video_tracks.at(j).file_index; - ghosts.append(g); - video_ghosts = true; + + if (import_data.type() == olive::timeline::kImportVideoOnly + || import_data.type() == olive::timeline::kImportBoth) { + for (int j=0;jvideo_tracks.size();j++) { + if (m->video_tracks.at(j).enabled) { + g.track = -1-j; + g.media_stream = m->video_tracks.at(j).file_index; + ghosts.append(g); + video_ghosts = true; + } } } break; @@ -277,10 +287,17 @@ void Timeline::create_ghosts_from_media(Sequence* seq, long entry_point, QVector g.out -= (sequence_length - default_clip_out); } - g.track = -1; - ghosts.append(g); - g.track = 0; - ghosts.append(g); + if (import_data.type() == olive::timeline::kImportVideoOnly + || import_data.type() == olive::timeline::kImportBoth) { + g.track = -1; + ghosts.append(g); + } + + if (import_data.type() == olive::timeline::kImportAudioOnly + || import_data.type() == olive::timeline::kImportBoth) { + g.track = 0; + ghosts.append(g); + } video_ghosts = true; audio_ghosts = true; @@ -446,7 +463,7 @@ void Timeline::nest() { MediaPtr m = panel_project->create_sequence_internal(ca, s, false, nullptr); // add nested sequence to active sequence - QVector media_list; + QVector media_list; media_list.append(m.get()); create_ghosts_from_media(olive::ActiveSequence.get(), earliest_point, media_list); add_clips_from_ghosts(ca, olive::ActiveSequence.get()); diff --git a/panels/timeline.h b/panels/timeline.h index 028c8977f..e1b103e6c 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -29,6 +29,7 @@ #include "ui/timelinetools.h" #include "timeline/selection.h" #include "timeline/clip.h" +#include "timeline/mediaimportdata.h" #include "undo/undo.h" #include "ui/timelineheader.h" #include "ui/resizablescrollbar.h" @@ -125,7 +126,7 @@ public: void edit_to_point_internal(bool in, bool ripple); void delete_in_out_internal(bool ripple); - void create_ghosts_from_media(Sequence *seq, long entry_point, QVector &media_list); + void create_ghosts_from_media(Sequence *seq, long entry_point, QVector &media_list); void add_clips_from_ghosts(ComboAction *ca, Sequence *s); int getTimelineScreenPointFromFrame(long frame); diff --git a/panels/viewer.cpp b/panels/viewer.cpp index 911df3376..3a45fcd3c 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -20,6 +20,21 @@ #include "viewer.h" +extern "C" { +#include +#include +} + +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "rendering/audio.h" #include "timeline.h" #include "panels/project.h" @@ -45,19 +60,6 @@ #define FRAMES_IN_ONE_MINUTE 1798 // 1800 - 2 #define FRAMES_IN_TEN_MINUTES 17978 // (FRAMES_IN_ONE_MINUTE * 10) - 2 -extern "C" { -#include -#include -} - -#include -#include -#include -#include -#include -#include -#include - Viewer::Viewer(QWidget *parent) : Panel(parent), playing(false), @@ -538,6 +540,17 @@ void Viewer::update_viewer() { update_end_timecode(); } +void Viewer::initiate_drag(olive::timeline::MediaImportType drag_type) +{ + // FIXME: This should contain actual metadata rather than fake metadata + + QDrag* drag = new QDrag(this); + QMimeData* mimeData = new QMimeData; + mimeData->setText(QString::number(drag_type)); + drag->setMimeData(mimeData); + drag->exec(); +} + void Viewer::clear_in() { if (seq != nullptr && seq->using_workarea) { @@ -585,6 +598,12 @@ void Viewer::set_panel_name(const QString &n) { update_window_title(); } +void Viewer::show_videoaudio_buttons(bool s) +{ + video_only_button->setVisible(s); + audio_only_button->setVisible(s); +} + void Viewer::update_window_title() { QString name; if (seq == nullptr) { @@ -658,8 +677,12 @@ void Viewer::setup_ui() { QHBoxLayout* lower_control_layout = new QHBoxLayout(lower_controls); lower_control_layout->setMargin(0); - // current time code + QSizePolicy timecode_container_policy(QSizePolicy::Minimum, QSizePolicy::Maximum); + QSizePolicy lower_control_policy(QSizePolicy::Expanding, QSizePolicy::Maximum); + + // Current time code container QWidget* current_timecode_container = new QWidget(); + current_timecode_container->setSizePolicy(timecode_container_policy); QHBoxLayout* current_timecode_container_layout = new QHBoxLayout(current_timecode_container); current_timecode_container_layout->setSpacing(0); current_timecode_container_layout->setMargin(0); @@ -667,11 +690,19 @@ void Viewer::setup_ui() { current_timecode_container_layout->addWidget(current_timecode_slider); lower_control_layout->addWidget(current_timecode_container); + // Left controls container + QWidget* left_controls = new QWidget(); + left_controls->setSizePolicy(lower_control_policy); + lower_control_layout->addWidget(left_controls); + + // Playback controls container QWidget* playback_controls = new QWidget(); + playback_controls->setSizePolicy(lower_control_policy); QHBoxLayout* playback_control_layout = new QHBoxLayout(playback_controls); playback_control_layout->setSpacing(0); playback_control_layout->setMargin(0); + playback_control_layout->addStretch(); go_to_start_button = new QPushButton(); go_to_start_button->setIcon(olive::icon::ViewerGoToStart); @@ -698,9 +729,40 @@ void Viewer::setup_ui() { connect(go_to_end_frame, SIGNAL(clicked(bool)), this, SLOT(go_to_out())); playback_control_layout->addWidget(go_to_end_frame); + playback_control_layout->addStretch(); + lower_control_layout->addWidget(playback_controls); + // Right controls container + QWidget* right_controls = new QWidget(); + right_controls->setSizePolicy(lower_control_policy); + + QHBoxLayout* right_control_layout = new QHBoxLayout(right_controls); + right_control_layout->setSpacing(0); + right_control_layout->setMargin(0); + right_control_layout->addStretch(); + + video_only_button = new QPushButton(); + video_only_button->setToolTip(tr("Drag video only")); + video_only_button->setIcon(olive::icon::MediaVideo); + video_only_button->setVisible(false); + right_control_layout->addWidget(video_only_button); + connect(video_only_button, SIGNAL(pressed()), this, SLOT(drag_video_only())); + + audio_only_button = new QPushButton(); + audio_only_button->setToolTip(tr("Drag audio only")); + audio_only_button->setIcon(olive::icon::MediaAudio); + audio_only_button->setVisible(false); + right_control_layout->addWidget(audio_only_button); + connect(audio_only_button, SIGNAL(pressed()), this, SLOT(drag_audio_only())); + + right_control_layout->addStretch(); + + lower_control_layout->addWidget(right_controls); + + // End time code container QWidget* end_timecode_container = new QWidget(); + end_timecode_container->setSizePolicy(timecode_container_policy); QHBoxLayout* end_timecode_layout = new QHBoxLayout(end_timecode_container); end_timecode_layout->setSpacing(0); @@ -851,6 +913,16 @@ void Viewer::resize_move(double d) { set_zoom_value(headers->get_zoom()*d); } +void Viewer::drag_video_only() +{ + initiate_drag(olive::timeline::kImportVideoOnly); +} + +void Viewer::drag_audio_only() +{ + initiate_drag(olive::timeline::kImportAudioOnly); +} + void Viewer::clean_created_seq() { viewer_widget->waveform = false; @@ -902,6 +974,8 @@ void Viewer::set_sequence(bool main, SequencePtr s) { play_button->setEnabled(!null_sequence); next_frame_button->setEnabled(!null_sequence); go_to_end_frame->setEnabled(!null_sequence); + video_only_button->setEnabled(!null_sequence); + audio_only_button->setEnabled(!null_sequence); if (!null_sequence) { current_timecode_slider->SetFrameRate(seq->frame_rate); diff --git a/panels/viewer.h b/panels/viewer.h index 8376fee6d..a96b2a5b6 100644 --- a/panels/viewer.h +++ b/panels/viewer.h @@ -27,6 +27,7 @@ #include #include "timeline/marker.h" +#include "timeline/mediaimportdata.h" #include "project/media.h" #include "ui/panel.h" @@ -64,6 +65,7 @@ public: void set_out_point(); void set_zoom(bool in); void set_panel_name(const QString& n); + void show_videoaudio_buttons(bool s); // playback functions void seek(long p); @@ -98,6 +100,10 @@ public: TimelineHeader* headers; + + + void initiate_drag(olive::timeline::MediaImportType drag_type); + virtual void Retranslate() override; protected: virtual void resizeEvent(QResizeEvent *event) override; @@ -116,12 +122,17 @@ public slots: void close_media(); void update_viewer(); + + private slots: void update_playhead(); void timer_update(); void recording_flasher_update(); void resize_move(double d); + void drag_video_only(); + void drag_audio_only(); + private: void update_window_title(); @@ -155,6 +166,9 @@ private: QPushButton* next_frame_button; QPushButton* go_to_end_frame; + QPushButton* video_only_button; + QPushButton* audio_only_button; + bool cue_recording_internal; QTimer recording_flasher; diff --git a/project/sourcescommon.cpp b/project/sourcescommon.cpp index 1833271ca..d91850b3c 100644 --- a/project/sourcescommon.cpp +++ b/project/sourcescommon.cpp @@ -57,7 +57,7 @@ SourcesCommon::SourcesCommon(Project* parent) : void SourcesCommon::create_seq_from_selected() { if (!selected_items.isEmpty()) { - QVector media_list; + QVector media_list; for (int i=0;iitem_to_media(selected_items.at(i))); } diff --git a/timeline/mediaimportdata.cpp b/timeline/mediaimportdata.cpp new file mode 100644 index 000000000..1358576e7 --- /dev/null +++ b/timeline/mediaimportdata.cpp @@ -0,0 +1,17 @@ +#include "mediaimportdata.h" + +olive::timeline::MediaImportData::MediaImportData(Media *media, olive::timeline::MediaImportType import_type) : + media_(media), + import_type_(import_type) +{ +} + +Media *olive::timeline::MediaImportData::media() const +{ + return media_; +} + +olive::timeline::MediaImportType olive::timeline::MediaImportData::type() const +{ + return import_type_; +} diff --git a/timeline/mediaimportdata.h b/timeline/mediaimportdata.h new file mode 100644 index 000000000..866ea37dd --- /dev/null +++ b/timeline/mediaimportdata.h @@ -0,0 +1,29 @@ +#ifndef MEDIAIMPORTDATA_H +#define MEDIAIMPORTDATA_H + +#include "project/media.h" + +namespace olive { +namespace timeline { + +enum MediaImportType { + kImportVideoOnly, + kImportAudioOnly, + kImportBoth +}; + +class MediaImportData { +public: + MediaImportData(Media* media = nullptr, MediaImportType import_type = kImportBoth); + Media* media() const; + MediaImportType type() const; +private: + Media* media_; + MediaImportType import_type_; +}; + +} +} + + +#endif // MEDIAIMPORTDATA_H diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index dd2eb82da..684f93f47 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -237,7 +237,7 @@ bool same_sign(int a, int b) { void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) { bool import_init = false; - QVector media_list; + QVector media_list; panel_timeline->importing_files = false; if (event->source() == panel_project->tree_view || event->source() == panel_project->icon_view) { @@ -249,10 +249,13 @@ void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) { import_init = true; } - if (event->source() == panel_footage_viewer->viewer_widget) { + if (event->source() == panel_footage_viewer) { if (panel_footage_viewer->seq != olive::ActiveSequence) { // don't allow nesting the same sequence - media_list.append(panel_footage_viewer->media); + + media_list.append(olive::timeline::MediaImportData(panel_footage_viewer->media, + static_cast(event->mimeData()->text().toInt()))); import_init = true; + } } diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 6fcdf8d74..5847eaa32 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -339,11 +339,7 @@ void ViewerWidget::mouseMoveEvent(QMouseEvent* event) { container->dragScrollMove(event->pos()*container->zoom); } else if (event->buttons() & Qt::LeftButton) { if (gizmos == nullptr) { - QDrag* drag = new QDrag(this); - QMimeData* mimeData = new QMimeData; - mimeData->setText("h"); // QMimeData will fail without some kind of data - drag->setMimeData(mimeData); - drag->exec(); + viewer->initiate_drag(olive::timeline::kImportBoth); dragging = false; } else { move_gizmos(event, false); From bec65b7f2e57faf90aad0b5cc11b39de55cd7085 Mon Sep 17 00:00:00 2001 From: eszlari Date: Fri, 22 Mar 2019 04:30:31 +0100 Subject: [PATCH 08/35] sourceiconview.h: include --- ui/sourceiconview.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/sourceiconview.h b/ui/sourceiconview.h index e561a7a6f..e84d64adc 100644 --- a/ui/sourceiconview.h +++ b/ui/sourceiconview.h @@ -22,6 +22,7 @@ #define SOURCEICONVIEW_H #include +#include class Project; From 0b7e66e429633d8455e0a80af5b360165d803e42 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 22 Mar 2019 18:00:45 +1100 Subject: [PATCH 09/35] more documentation and cleanup --- dialogs/aboutdialog.h | 3 +- dialogs/actionsearch.h | 2 +- dialogs/advancedvideodialog.h | 2 +- dialogs/clippropertiesdialog.h | 3 +- dialogs/debugdialog.h | 6 +- dialogs/demonotice.h | 5 +- dialogs/exportdialog.h | 4 +- dialogs/loaddialog.h | 4 +- dialogs/mediapropertiesdialog.h | 3 +- dialogs/newsequencedialog.h | 2 +- dialogs/preferencesdialog.cpp | 23 +---- dialogs/preferencesdialog.h | 156 ++++++++++++++++++++++++++++- dialogs/proxydialog.h | 3 +- dialogs/replaceclipmediadialog.cpp | 24 ++--- dialogs/replaceclipmediadialog.h | 51 ++++++++-- dialogs/speeddialog.cpp | 14 +-- dialogs/speeddialog.h | 92 +++++++++++++++-- dialogs/texteditdialog.cpp | 42 ++------ dialogs/texteditdialog.h | 131 ++++++++++++++++++++++-- global/config.cpp | 5 - global/config.h | 10 -- ui/icons.cpp | 4 +- 22 files changed, 462 insertions(+), 127 deletions(-) diff --git a/dialogs/aboutdialog.h b/dialogs/aboutdialog.h index f0a5f14bd..08ec184e1 100644 --- a/dialogs/aboutdialog.h +++ b/dialogs/aboutdialog.h @@ -26,7 +26,8 @@ /** * @brief The AboutDialog class * - * The About dialog (accessible through Help > About). Contains license and version information. + * The About dialog (accessible through Help > About). Contains license and version information. This can be run from + * anywhere */ class AboutDialog : public QDialog { diff --git a/dialogs/actionsearch.h b/dialogs/actionsearch.h index e00fb2025..54688a71e 100644 --- a/dialogs/actionsearch.h +++ b/dialogs/actionsearch.h @@ -32,7 +32,7 @@ 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. + * rather than browsing through the menu bar. This can be created from anywhere provided olive::MainWindow is valid. */ class ActionSearch : public QDialog { diff --git a/dialogs/advancedvideodialog.h b/dialogs/advancedvideodialog.h index 0ff8c1fae..e4279092b 100644 --- a/dialogs/advancedvideodialog.h +++ b/dialogs/advancedvideodialog.h @@ -31,7 +31,7 @@ * @brief The AdvancedVideoDialog class * * A dialog for interfacing with VideoCodecParams, a struct for more advanced video settings sometimes specific to - * one codec. + * one codec. Primarily a companion to ExportDialog which will provide the VideoCodecParams reference, */ class AdvancedVideoDialog : public QDialog { Q_OBJECT diff --git a/dialogs/clippropertiesdialog.h b/dialogs/clippropertiesdialog.h index dc169a597..439f870de 100644 --- a/dialogs/clippropertiesdialog.h +++ b/dialogs/clippropertiesdialog.h @@ -10,7 +10,8 @@ /** * @brief The ClipPropertiesDialog class * - * A dialog for setting Clip properties, accessible by right clicking a Clip and clicking "Properties". + * 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 diff --git a/dialogs/debugdialog.h b/dialogs/debugdialog.h index a1b6aab3c..6d5797dc0 100644 --- a/dialogs/debugdialog.h +++ b/dialogs/debugdialog.h @@ -27,7 +27,8 @@ /** * @brief The DebugDialog class * - * A dialog to display the current debug output. + * 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 @@ -69,6 +70,9 @@ private: }; namespace olive { +/** + * @brief Omnipresent instance of DebugDialog to be shown or hidden as the user wants + */ extern DebugDialog* DebugDialog; } diff --git a/dialogs/demonotice.h b/dialogs/demonotice.h index a986e51ab..0407864ab 100644 --- a/dialogs/demonotice.h +++ b/dialogs/demonotice.h @@ -26,7 +26,10 @@ /** * @brief The DemoNotice class * - * Simple dialog shown on startup to introduce Olive as alpha software (in release builds). + * 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 { diff --git a/dialogs/exportdialog.h b/dialogs/exportdialog.h index c39c8af2a..bb5a4e486 100644 --- a/dialogs/exportdialog.h +++ b/dialogs/exportdialog.h @@ -35,7 +35,9 @@ /** * @brief The ExportDialog class * - * The dialog to initiate an export. + * 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 { diff --git a/dialogs/loaddialog.h b/dialogs/loaddialog.h index 5fa357155..ea13f515f 100644 --- a/dialogs/loaddialog.h +++ b/dialogs/loaddialog.h @@ -31,7 +31,9 @@ /** * @brief The LoadDialog class * - * Shows a modal dialog for loading a project. Designed to be connected to a LoadThread object. + * 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 { diff --git a/dialogs/mediapropertiesdialog.h b/dialogs/mediapropertiesdialog.h index c13e2c1f6..5c0fdc839 100644 --- a/dialogs/mediapropertiesdialog.h +++ b/dialogs/mediapropertiesdialog.h @@ -34,7 +34,8 @@ /** * @brief The MediaPropertiesDialog class * - * A dialog for setting properties on Media. + * 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 diff --git a/dialogs/newsequencedialog.h b/dialogs/newsequencedialog.h index 4acd69853..631923647 100644 --- a/dialogs/newsequencedialog.h +++ b/dialogs/newsequencedialog.h @@ -33,7 +33,7 @@ /** * @brief The NewSequenceDialog class * - * A dialog that creates a new (or edits an existing) Sequence object. + * 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 { diff --git a/dialogs/preferencesdialog.cpp b/dialogs/preferencesdialog.cpp index b8742926d..eb5ee4b3a 100644 --- a/dialogs/preferencesdialog.cpp +++ b/dialogs/preferencesdialog.cpp @@ -72,7 +72,7 @@ QString KeySequenceEditor::action_name() { QString KeySequenceEditor::export_shortcut() { QString ks = keySequence().toString(); if (ks != action->property("default")) { - return action->property("id").toString() + "\t" + keySequence().toString(); + return action->property("id").toString() + "\t" + ks; } return nullptr; } @@ -81,12 +81,8 @@ PreferencesDialog::PreferencesDialog(QWidget *parent) : QDialog(parent) { setWindowTitle(tr("Preferences")); - setup_ui(); - accurateSeekButton->setChecked(!olive::CurrentConfig.fast_seeking); - fastSeekButton->setChecked(olive::CurrentConfig.fast_seeking); - recordingComboBox->setCurrentIndex(olive::CurrentConfig.recording_mode - 1); - imgSeqFormatEdit->setText(olive::CurrentConfig.img_seq_formats); + setup_ui(); setup_kbd_shortcuts(olive::MainWindow->menuBar()); } @@ -244,7 +240,6 @@ void PreferencesDialog::accept() { olive::CurrentConfig.recording_mode = recordingComboBox->currentIndex() + 1; olive::CurrentConfig.img_seq_formats = imgSeqFormatEdit->text(); - olive::CurrentConfig.fast_seeking = fastSeekButton->isChecked(); olive::CurrentConfig.upcoming_queue_size = upcoming_queue_spinbox->value(); olive::CurrentConfig.upcoming_queue_type = upcoming_queue_type->currentIndex(); olive::CurrentConfig.previous_queue_size = previous_queue_spinbox->value(); @@ -515,6 +510,7 @@ void PreferencesDialog::setup_ui() { general_layout->addWidget(new QLabel(tr("Image sequence formats:"), this), row, 0); imgSeqFormatEdit = new QLineEdit(general_tab); + imgSeqFormatEdit->setText(olive::CurrentConfig.img_seq_formats); general_layout->addWidget(imgSeqFormatEdit, row, 1, 1, 4); @@ -625,18 +621,6 @@ void PreferencesDialog::setup_ui() { QWidget* playback_tab = new QWidget(this); QVBoxLayout* playback_tab_layout = new QVBoxLayout(playback_tab); - // Playback -> Seeking - QGroupBox* seeking_group = new QGroupBox(playback_tab); - seeking_group->setTitle(tr("Seeking")); - QVBoxLayout* seeking_group_layout = new QVBoxLayout(seeking_group); - accurateSeekButton = new QRadioButton(seeking_group); - accurateSeekButton->setText(tr("Accurate Seeking\nAlways show the correct frame (visual may pause briefly as correct frame is retrieved)")); - seeking_group_layout->addWidget(accurateSeekButton); - fastSeekButton = new QRadioButton(seeking_group); - fastSeekButton->setText(tr("Fast Seeking\nSeek quickly (may briefly show inaccurate frames when seeking - doesn't affect playback/export)")); - seeking_group_layout->addWidget(fastSeekButton); - playback_tab_layout->addWidget(seeking_group); - // Playback -> Memory Usage QGroupBox* memory_usage_group = new QGroupBox(playback_tab); memory_usage_group->setTitle(tr("Memory Usage")); @@ -739,6 +723,7 @@ void PreferencesDialog::setup_ui() { recordingComboBox = new QComboBox(general_tab); recordingComboBox->addItem(tr("Mono")); recordingComboBox->addItem(tr("Stereo")); + recordingComboBox->setCurrentIndex(olive::CurrentConfig.recording_mode - 1); audio_tab_layout->addWidget(recordingComboBox, row, 1); row++; diff --git a/dialogs/preferencesdialog.h b/dialogs/preferencesdialog.h index 347212f4b..67538b7a7 100644 --- a/dialogs/preferencesdialog.h +++ b/dialogs/preferencesdialog.h @@ -41,7 +41,8 @@ class KeySequenceEditor; /** * @brief The PreferencesDialog class * - * A dialog for the global application settings. Mostly an interface for Config. + * A dialog for the global application settings. Mostly an interface for Config. Can be loaded from any part of the + * application. */ class PreferencesDialog : public QDialog { @@ -162,45 +163,192 @@ private: */ void delete_previews(char type); + /** + * @brief UI widget for editing the CSS filename + */ QLineEdit* custom_css_fn; + + /** + * @brief UI widget for editing the list of extensions to detect image sequences from + */ QLineEdit* imgSeqFormatEdit; + + /** + * @brief UI widget for editing the recording channels + */ QComboBox* recordingComboBox; - QRadioButton* accurateSeekButton; - QRadioButton* fastSeekButton; + + /** + * @brief UI widget for editing keyboard shortcuts + */ QTreeWidget* keyboard_tree; + + /** + * @brief UI widget for editing the upcoming queue size + */ QDoubleSpinBox* upcoming_queue_spinbox; + + /** + * @brief UI widget for editing the upcoming queue type + */ QComboBox* upcoming_queue_type; + + /** + * @brief UI widget for editing the previous queue size + */ QDoubleSpinBox* previous_queue_spinbox; + + /** + * @brief UI widget for editing the previous queue type + */ QComboBox* previous_queue_type; + + /** + * @brief UI widget for editing the size of textboxes in the EffectControls panel + */ QSpinBox* effect_textbox_lines_field; + + /** + * @brief UI widget for enabling/disabling software fallbacks + */ QCheckBox* use_software_fallbacks_checkbox; + + /** + * @brief UI widget for selecting the output audio device + */ QComboBox* audio_output_devices; + + /** + * @brief UI widget for selecting the input audio device + */ QComboBox* audio_input_devices; + + /** + * @brief UI widget for selecting the audio sampling rates + */ QComboBox* audio_sample_rate; + + /** + * @brief UI widget for selecting the UI language + */ QComboBox* language_combobox; + + /** + * @brief UI widget for selecting the resolution of the thumbnails to generate + */ QSpinBox* thumbnail_res_spinbox; + + /** + * @brief UI widget for selecting the resolution of the waveforms to generate + */ QSpinBox* waveform_res_spinbox; + + /** + * @brief UI widget for enabling/disabling default effects + */ QCheckBox* add_default_effects_to_clips; + + /** + * @brief UI widget for selecting the current UI style + */ QComboBox* ui_style; - Sequence sequence_settings; #ifdef Q_OS_WIN + /** + * @brief UI widget for forcing native menu styling on Windows + */ QCheckBox* native_menus; #endif + /** + * @brief List of keyboard shortcut actions that can be triggered (links with key_shortcut_items and + * key_shortcut_fields) + */ QVector key_shortcut_actions; + + /** + * @brief List of keyboard shortcut items in keyboard_tree corresponding to existing actions (links with + * key_shortcut_actions and key_shortcut_fields) + */ QVector key_shortcut_items; + + /** + * @brief List of keyboard shortcut editing fields in keyboard_tree corresponding to existing actions (links with + * key_shortcut_actions and key_shortcut_fields) + */ QVector key_shortcut_fields; }; +/** + * @brief The KeySequenceEditor class + * + * Simple derived class of QKeySequenceEdit that attaches to a QAction and provides functions for transferring + * keyboard shortcuts to and from it. + */ class KeySequenceEditor : public QKeySequenceEdit { Q_OBJECT public: + /** + * @brief KeySequenceEditor Constructor + * + * @param parent + * + * QWidget parent. + * + * @param a + * + * The QAction to link to. This cannot be changed throughout the lifetime of a KeySequenceEditor. + */ KeySequenceEditor(QWidget *parent, QAction* a); + + /** + * @brief Sets the attached QAction's shortcut to the shortcut entered in this field. + * + * This is not done automatically in case the user cancels out of the Preferences dialog, in which case the + * expectation is that the changes made will not be saved. Therefore, this needs to be triggered manually when + * PreferencesDialog saves. + */ void set_action_shortcut(); + + /** + * @brief Set this shortcut back to the QAction's default shortcut + * + * Each QAction contains the default shortcut in its `property("default")` and can be used to restore the default + * "hard-coded" shortcut with this function. + * + * This function does not save the default shortcut back into the QAction, it simply loads the default shortcut from + * the QAction into this edit field. To save it into the QAction, it's necessary to call set_action_shortcut() after + * calling this function. + */ void reset_to_default(); + + /** + * @brief Return attached QAction's unique ID + * + * Each of Olive's menu actions has a unique string ID (that, unlike the text, is not translated) for matching with + * an external shortcut configuration file. The ID is stored in the QAction's `property("id")`. This function returns + * that ID. + * + * @return + * + * The QAction's unique ID. + */ QString action_name(); + + /** + * @brief Serialize this shortcut entry into a string that can be saved to a file + * + * @return + * + * A string serialization of this shortcut. The format is "[ID]\t[SEQUENCE]" where [ID] is the attached QAction's + * unique identifier and [SEQUENCE] is the current keyboard shortcut in the field (NOT necessarily the shortcut in + * the QAction). If the entered shortcut is the same as the QAction's default shortcut, the return value is empty + * because a default shortcut does not need to be saved to a file. + */ QString export_shortcut(); private: + /** + * @brief Internal reference to the linked QAction + */ QAction* action; }; diff --git a/dialogs/proxydialog.h b/dialogs/proxydialog.h index 3a7fd579a..6a036d830 100644 --- a/dialogs/proxydialog.h +++ b/dialogs/proxydialog.h @@ -30,7 +30,8 @@ /** * @brief The ProxyDialog class * - * Dialog to set up proxy generation of footage + * 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 diff --git a/dialogs/replaceclipmediadialog.cpp b/dialogs/replaceclipmediadialog.cpp index a8aec4cfd..8efda92a9 100644 --- a/dialogs/replaceclipmediadialog.cpp +++ b/dialogs/replaceclipmediadialog.cpp @@ -50,16 +50,16 @@ ReplaceClipMediaDialog::ReplaceClipMediaDialog(QWidget *parent, Media* old_media use_same_media_in_points->setChecked(true); layout->addWidget(use_same_media_in_points); - QHBoxLayout* buttons = new QHBoxLayout(); + QHBoxLayout* buttons = new QHBoxLayout(); buttons->addStretch(); QPushButton* replace_button = new QPushButton(tr("Replace"), this); - connect(replace_button, SIGNAL(clicked(bool)), this, SLOT(replace())); + 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(close())); + connect(cancel_button, SIGNAL(clicked(bool)), this, SLOT(reject())); buttons->addWidget(cancel_button); buttons->addStretch(); @@ -69,7 +69,7 @@ ReplaceClipMediaDialog::ReplaceClipMediaDialog(QWidget *parent, Media* old_media tree->setModel(&olive::project_model); } -void ReplaceClipMediaDialog::replace() { +void ReplaceClipMediaDialog::accept() { QModelIndexList selected_items = tree->selectionModel()->selectedRows(); if (selected_items.size() != 1) { QMessageBox::critical( @@ -77,23 +77,23 @@ void ReplaceClipMediaDialog::replace() { tr("No media selected"), tr("Please select a media to replace with or click 'Cancel'."), QMessageBox::Ok - ); + ); } else { - Media* new_item = static_cast(selected_items.at(0).internalPointer()); + Media* new_item = static_cast(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 { if (new_item->get_type() == MEDIA_TYPE_SEQUENCE && olive::ActiveSequence == new_item->to_sequence()) { QMessageBox::critical( @@ -101,16 +101,16 @@ void ReplaceClipMediaDialog::replace() { 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() - ); + ); for (int i=0;iclips.size();i++) { - ClipPtr c = olive::ActiveSequence->clips.at(i); + ClipPtr c = olive::ActiveSequence->clips.at(i); if (c != nullptr && c->media() == media) { rcmc->clips.append(c); } @@ -118,7 +118,7 @@ void ReplaceClipMediaDialog::replace() { olive::UndoStack.push(rcmc); - close(); + QDialog::accept(); } } diff --git a/dialogs/replaceclipmediadialog.h b/dialogs/replaceclipmediadialog.h index 7b1867a71..c0695f56f 100644 --- a/dialogs/replaceclipmediadialog.h +++ b/dialogs/replaceclipmediadialog.h @@ -28,16 +28,55 @@ #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 + Q_OBJECT public: - ReplaceClipMediaDialog(QWidget* parent, Media* old_media); + /** + * @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: - void replace(); + /** + * @brief Overrided 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: - Media* media; - QTreeView* tree; - QCheckBox* use_same_media_in_points; + /** + * @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 diff --git a/dialogs/speeddialog.cpp b/dialogs/speeddialog.cpp index c0a08d652..8a87916bc 100644 --- a/dialogs/speeddialog.cpp +++ b/dialogs/speeddialog.cpp @@ -85,16 +85,16 @@ SpeedDialog::SpeedDialog(QWidget *parent, QVector clips) : QDialog(parent connect(duration, SIGNAL(valueChanged(double)), this, SLOT(duration_update())); } -void SpeedDialog::run() { +int SpeedDialog::exec() { bool enable_frame_rate = false; bool multiple_audio = false; maintain_pitch->setEnabled(false); - default_frame_rate = qSNaN(); - current_frame_rate = qSNaN(); - current_percent = qSNaN(); - default_length = -1; - current_length = -1; + 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;iSetDefault(default_length); duration->SetValue((current_length == -1) ? qSNaN() : current_length); - exec(); + return QDialog::exec(); } void SpeedDialog::percent_update() { diff --git a/dialogs/speeddialog.h b/dialogs/speeddialog.h index ac68c51dc..c52b2a862 100644 --- a/dialogs/speeddialog.h +++ b/dialogs/speeddialog.h @@ -27,34 +27,106 @@ #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 ot + */ 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 clips); - - void run(); +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(); - void accept(); private: + /** + * @brief Internal array of Clip objects + */ QVector 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; - QCheckBox* maintain_pitch; - QCheckBox* ripple; - double default_frame_rate; - double current_frame_rate; - double current_percent; - long default_length; - long current_length; + /** + * @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 diff --git a/dialogs/texteditdialog.cpp b/dialogs/texteditdialog.cpp index 185b7c357..e7a5d9fa0 100644 --- a/dialogs/texteditdialog.cpp +++ b/dialogs/texteditdialog.cpp @@ -44,15 +44,6 @@ TextEditDialog::TextEditDialog(QWidget *parent, const QString &s, bool rich_text if (rich_text) { QHBoxLayout* toolbar = new QHBoxLayout(); - // Bold Button - /* - bold_button = new QPushButton(); - bold_button->setIcon(olive::icon::CreateIconFromSVG(":/icons/bold.svg", false)); - bold_button->setCheckable(true); - connect(bold_button, SIGNAL(clicked(bool)), this, SLOT(SetBold(bool))); - toolbar->addWidget(bold_button); - */ - // Italic Button italic_button = new QPushButton(); italic_button->setIcon(olive::icon::CreateIconFromSVG(":/icons/italic.svg", false)); @@ -156,10 +147,14 @@ TextEditDialog::TextEditDialog(QWidget *parent, const QString &s, bool rich_text QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); buttons->setCenterButtons(true); layout->addWidget(buttons); - connect(buttons, SIGNAL(accepted()), this, SLOT(save())); - connect(buttons, SIGNAL(rejected()), this, SLOT(cancel())); + 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 { @@ -167,7 +162,7 @@ TextEditDialog::TextEditDialog(QWidget *parent, const QString &s, bool rich_text } // Helps ensure the UI elements update correctly at the beginning - when the cursor is at the start, the UI elements - // show up blank... + // show up blank. Setting it to the end is probably more expected behavior anyway. textEdit->moveCursor(QTextCursor::End); } @@ -175,21 +170,9 @@ const QString& TextEditDialog::get_string() { return result_str; } -void TextEditDialog::save() { +void TextEditDialog::accept() { result_str = rich_text_ ? textEdit->toHtml() : textEdit->toPlainText(); - accept(); -} - -void TextEditDialog::cancel() { - reject(); -} - -void TextEditDialog::SetBold(bool bold) -{ - QFont f = textEdit->currentFont(); - f.setBold(bold); - textEdit->setCurrentFont(f); - UpdateUIFromTextCursor(); + QDialog::accept(); } void TextEditDialog::SetFontWeight(int i) @@ -197,13 +180,6 @@ void TextEditDialog::SetFontWeight(int i) textEdit->setFontWeight(font_weight->itemData(i).toInt()); } -void TextEditDialog::SetLetterSpacing(qreal spacing) -{ - QFont f = textEdit->currentFont(); - f.setLetterSpacing(f.letterSpacingType(), spacing); - textEdit->setCurrentFont(f); -} - void TextEditDialog::SetAlignmentFromProperty() { textEdit->setAlignment(static_cast(sender()->property("a").toInt())); diff --git a/dialogs/texteditdialog.h b/dialogs/texteditdialog.h index c2ced7d2e..be812dd85 100644 --- a/dialogs/texteditdialog.h +++ b/dialogs/texteditdialog.h @@ -28,36 +28,151 @@ #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); - const QString& get_string(); -signals: - void cursorPositionChanged(); -private slots: - void save(); - void cancel(); - void SetBold(bool bold); + /** + * @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); - void SetLetterSpacing(qreal spacing); + + /** + * @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; }; diff --git a/global/config.cpp b/global/config.cpp index 29ea9be76..d4c548d03 100644 --- a/global/config.cpp +++ b/global/config.cpp @@ -54,7 +54,6 @@ Config::Config() drop_on_media_to_replace(true), autoscroll(olive::AUTOSCROLL_PAGE_SCROLL), audio_rate(48000), - fast_seeking(false), hover_focus(false), project_view_type(olive::PROJECT_VIEW_TREE), set_name_with_marker(true), @@ -150,9 +149,6 @@ void Config::load(QString path) { } else if (stream.name() == "AudioRate") { stream.readNext(); audio_rate = stream.text().toInt(); - } else if (stream.name() == "FastSeeking") { - stream.readNext(); - fast_seeking = (stream.text() == "1"); } else if (stream.name() == "HoverFocus") { stream.readNext(); hover_focus = (stream.text() == "1"); @@ -265,7 +261,6 @@ void Config::save(QString path) { stream.writeTextElement("DropFileOnMediaToReplace", QString::number(drop_on_media_to_replace)); stream.writeTextElement("Autoscroll", QString::number(autoscroll)); stream.writeTextElement("AudioRate", QString::number(audio_rate)); - stream.writeTextElement("FastSeeking", QString::number(fast_seeking)); stream.writeTextElement("HoverFocus", QString::number(hover_focus)); stream.writeTextElement("ProjectViewType", QString::number(project_view_type)); stream.writeTextElement("SetNameWithMarker", QString::number(set_name_with_marker)); diff --git a/global/config.h b/global/config.h index 849acc2e1..f11183ef5 100644 --- a/global/config.h +++ b/global/config.h @@ -317,16 +317,6 @@ struct Config { */ int audio_rate; - /** - * @brief Enable fast seeking - * - * Olive supports a seek mode that shows frames faster with the risk of briefly showing a "best-effort" frame that - * may not be the accurate frame at that point of the Timeline. This does not affect exporting. - * - * Set to **TRUE** if this mode should be enabled. - */ - bool fast_seeking; - /** * @brief Enable hover focus * diff --git a/ui/icons.cpp b/ui/icons.cpp index 5cf63f81e..60997e8c0 100644 --- a/ui/icons.cpp +++ b/ui/icons.cpp @@ -76,8 +76,8 @@ void olive::icon::Initialize() Diamond = CreateIconFromSVG(":/icons/diamond.svg", false); Clock = CreateIconFromSVG(":/icons/clock.svg", false); - MediaVideo = CreateIconFromSVG(":/icons/videosource.svg", false); - MediaAudio = CreateIconFromSVG(":/icons/audiosource.svg", false); + MediaVideo = CreateIconFromSVG(":/icons/videosource.svg"); + MediaAudio = CreateIconFromSVG(":/icons/audiosource.svg"); MediaImage = CreateIconFromSVG(":/icons/imagesource.svg", false); MediaError = CreateIconFromSVG(":/icons/error.svg", false); MediaSequence = CreateIconFromSVG(":/icons/sequence.svg", false); From 057b5fbe5302b477c5a17638f07e77784f256b57 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 22 Mar 2019 22:42:15 +1100 Subject: [PATCH 10/35] documentation of boolfield and buttonfield --- effects/fields/boolfield.h | 49 +++++++++++++++++++++++++++++ effects/fields/buttonfield.h | 60 ++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) diff --git a/effects/fields/boolfield.h b/effects/fields/boolfield.h index 8a7ce1f6f..dc933408c 100644 --- a/effects/fields/boolfield.h +++ b/effects/fields/boolfield.h @@ -12,18 +12,67 @@ class BoolField : public EffectField { Q_OBJECT public: + /** + * @brief See Effect::Effect(). + */ BoolField(EffectRow* parent, const QString& id); + /** + * @brief Get the boolean value at a given timecode + * + * A convenience function, equivalent to GetValueAt(timecode).toBool() + * + * @param timecode + * + * The timecode to retrieve the value at + * + * @return + * + * The boolean value at this timecode + */ bool GetBoolAt(double timecode); + /** + * @brief See EffectField::CreateWidget() + */ virtual QWidget* CreateWidget(QWidget *existing = nullptr) override; + + /** + * @brief See EffectField::UpdateWidgetValue() + */ virtual void UpdateWidgetValue(QWidget* widget, double timecode) override; + /** + * @brief See EffectField::ConvertStringToValue() + */ virtual QVariant ConvertStringToValue(const QString& s) override; + + /** + * @brief See EffectField::ConvertValueToString() + */ virtual QString ConvertValueToString(const QVariant& v) override; signals: + /** + * @brief Emitted whenever the UI widget's boolean value has changed + * + * For any QCheckBox created through this field's CreateWidget() function, this signal is emitted any time the + * checkbox value changes (either through user intervention or keyframing). It is mostly useful for + * enabling/disabling/changing other UI elements based on the checked + * state of this field's value (e.g. enabling other fields if this field is checked). + * + * It is NOT a reliable signal that the value has changed at all, as it is only emitted if a widget (created + * from CreateWidget() ) is currently active. + */ void Toggled(bool); private slots: + /** + * @brief Internal function connected to any QWidget made from CreateWidget() to update the value based on user input + * + * @param b + * + * The current checked state of the QWidget (QCheckBox in this case). Automatically set when this slot is connected + * to the QCheckBox::toggled() signal. + */ void UpdateFromWidget(bool b); }; diff --git a/effects/fields/buttonfield.h b/effects/fields/buttonfield.h index 940e458e5..38afb938d 100644 --- a/effects/fields/buttonfield.h +++ b/effects/fields/buttonfield.h @@ -3,26 +3,86 @@ #include "../effectfield.h" +/** + * @brief The ButtonField class + * + * A UI-type EffectField. This field is largely an EffectField wrapper around a QPushButton and provides no data that's + * usable in the Effect. It's primarily useful for other UI functions (e.g. showing/hiding a dialog or other UI + * elements). This field is not exposed to the external shader API as it requires raw C++ code to connect it to other + * elements. + * + * As with all widgets created from EffectField::CreateWidget(), you should never interface with the resulting widget + * directly (apart from adding it to a layout and deleting it when it's unnecessary). All signals/slots should pass + * through ButtonField instead to keep consistency with every layer involved. + */ class ButtonField : public EffectField { Q_OBJECT public: + /** + * @brief See Effect::Effect(). + */ ButtonField(EffectRow* parent, const QString& string); + /** + * @brief Set whether this pushbutton is checkable + * + * This function is mainly a wrapper around QPushButton::setCheckable(). + * + * "Checkable" means the button can be toggled between a state of being "normal" and being "pressed". In checkable + * mode this field still cannot be used as a value in an Effect. Instead use BoolField (which uses a QCheckBox + * representation) for passing values to the Effect that can only be true or false. + * + * @param c + * + * TRUE if this button should be checkable or not. + */ void SetCheckable(bool c); + + /** + * @brief See EffectField::CreateWidget() + */ virtual QWidget* CreateWidget(QWidget *existing = nullptr) override; public slots: + /** + * @brief A slot for when a widget's (created and connected from CreateWidget() ) checked state is changed + * + * @param c + * + * The current checked state (automatically filled by the QPushButton::toggled() signal) + */ void SetChecked(bool c); signals: + /** + * @brief A signal emitted whenever the field's internal checked state is changed + * + * Primarily used to set any connected widget's checked state to be consistent with the field's. + */ void CheckedChanged(bool); + + /** + * @brief A signal emitted whenever the checked state of a connected widget changes + * + * Any widgets associated with this field will emit this signal when their checked state changes. + */ void Toggled(bool); private: + /** + * @brief Internal button text string passed to widgets created by CreateWidget() + */ bool checkable_; + + /** + * @brief Internal checked value passed to and from widgets created by CreateWidget() + */ bool checked_; + /** + * @brief Internal button text string passed to widgets created by CreateWidget() + */ QString button_text_; }; From fcdd03bf73c7d4ee2ad8a77f182ef510fc97c06a Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 22 Mar 2019 22:42:28 +1100 Subject: [PATCH 11/35] fixed crash when loading shared transition --- project/loadthread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/loadthread.cpp b/project/loadthread.cpp index 969c23214..9e616dfe4 100644 --- a/project/loadthread.cpp +++ b/project/loadthread.cpp @@ -103,7 +103,7 @@ void LoadThread::load_effect(QXmlStreamReader& stream, Clip* c) { c->closing_transition = (sharing_clip->opening_transition); // since this is the closed clip, make this clip the secondary - c->opening_transition->secondary_clip = c; + c->closing_transition->secondary_clip = c; } return; } From 90b089a80b0df3a4f1f9227a73ca9ead6c435443 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 22 Mar 2019 23:19:01 +1100 Subject: [PATCH 12/35] fixed VST loading --- effects/effect.cpp | 3 +++ effects/fields/filefield.cpp | 11 +++++++++++ effects/fields/filefield.h | 1 + effects/internal/vsthost.cpp | 14 ++++++++++++-- effects/internal/vsthost.h | 2 ++ 5 files changed, 29 insertions(+), 2 deletions(-) diff --git a/effects/effect.cpp b/effects/effect.cpp index 60d09f2a4..8e29a468c 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -597,6 +597,9 @@ void Effect::load(QXmlStreamReader& stream) { field->keyframes.append(key); } } + + field->Changed(); + } } } diff --git a/effects/fields/filefield.cpp b/effects/fields/filefield.cpp index bf5125ae8..4e4eab335 100644 --- a/effects/fields/filefield.cpp +++ b/effects/fields/filefield.cpp @@ -1,5 +1,7 @@ #include "filefield.h" +#include + #include "ui/embeddedfilechooser.h" FileField::FileField(EffectRow* parent, const QString &id) : @@ -23,6 +25,15 @@ QWidget *FileField::CreateWidget(QWidget *existing) return efc; } +void FileField::UpdateWidgetValue(QWidget *widget, double timecode) +{ + EmbeddedFileChooser* efc = static_cast(widget); + + efc->blockSignals(true); + efc->setFilename(GetFileAt(timecode)); + efc->blockSignals(false); +} + void FileField::UpdateFromWidget(const QString &s) { KeyframeDataChange* kdc = new KeyframeDataChange(this); diff --git a/effects/fields/filefield.h b/effects/fields/filefield.h index 88c3f0237..317e324bf 100644 --- a/effects/fields/filefield.h +++ b/effects/fields/filefield.h @@ -12,6 +12,7 @@ public: QString GetFileAt(double timecode); virtual QWidget* CreateWidget(QWidget *existing = nullptr) override; + virtual void UpdateWidgetValue(QWidget *widget, double timecode) override; private slots: void UpdateFromWidget(const QString &s); }; diff --git a/effects/internal/vsthost.cpp b/effects/internal/vsthost.cpp index 8a07f69dc..7fe21df0f 100644 --- a/effects/internal/vsthost.cpp +++ b/effects/internal/vsthost.cpp @@ -189,6 +189,7 @@ void VSTHost::loadPlugin() { void VSTHost::freePlugin() { if (plugin != nullptr) { stopPlugin(); + data_cache.clear(); #if defined(__APPLE__) CFBundleUnloadExecutable(bundle); CFRelease(bundle); @@ -268,6 +269,11 @@ void VSTHost::CreateDialogIfNull() } } +void VSTHost::send_data_cache_to_plugin() +{ + dispatcher(plugin, effSetChunk, 0, int32_t(data_cache.size()), static_cast(data_cache.data()), 0); +} + VSTHost::VSTHost(Clip* c, const EffectMeta *em) : Effect(c, em), plugin(nullptr), @@ -284,7 +290,7 @@ VSTHost::VSTHost(Clip* c, const EffectMeta *em) : EffectRow* file_row = new EffectRow(this, tr("Plugin"), true, false); file_field = new FileField(file_row, "filename"); - connect(file_field, SIGNAL(Changed()), this, SLOT(change_plugin())); + connect(file_field, SIGNAL(Changed()), this, SLOT(change_plugin()), Qt::QueuedConnection); EffectRow* interface_row = new EffectRow(this, tr("Interface"), false, false); @@ -346,7 +352,7 @@ void VSTHost::custom_load(QXmlStreamReader &stream) { stream.readNext(); data_cache = QByteArray::fromBase64(stream.text().toUtf8()); if (plugin != nullptr) { - dispatcher(plugin, effSetChunk, 0, int32_t(data_cache.size()), static_cast(data_cache.data()), 0); + send_data_cache_to_plugin(); } } } @@ -394,6 +400,10 @@ void VSTHost::change_plugin() { VSTRect* eRect = nullptr; plugin->dispatcher(plugin, effEditGetRect, 0, 0, &eRect, 0); + if (!data_cache.isEmpty()) { + send_data_cache_to_plugin(); + } + CreateDialogIfNull(); dialog->setFixedSize(eRect->right - eRect->left, eRect->bottom - eRect->top); diff --git a/effects/internal/vsthost.h b/effects/internal/vsthost.h index 5dc06a0cf..9d3b46e21 100644 --- a/effects/internal/vsthost.h +++ b/effects/internal/vsthost.h @@ -68,6 +68,8 @@ private: QDialog* dialog; QByteArray data_cache; + void send_data_cache_to_plugin(); + #if defined(__APPLE__) CFBundleRef bundle; #else From bd4b4f4e1802251ece2b6e83e5da910f01a8057d Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 23 Mar 2019 00:56:54 +1100 Subject: [PATCH 13/35] fixed #661 --- dialogs/preferencesdialog.cpp | 7 ++-- global/config.cpp | 2 +- global/global.cpp | 15 ++++++++- panels/project.cpp | 60 +++++++++++++++++++++++------------ panels/project.h | 22 ++++++++----- panels/viewer.cpp | 6 +++- project/sourcescommon.cpp | 15 +++++---- project/sourcescommon.h | 5 ++- ui/mainwindow.cpp | 6 ++-- ui/sourceiconview.cpp | 14 ++++---- ui/sourceiconview.h | 26 ++++++++------- ui/sourcetable.cpp | 12 +++---- ui/sourcetable.h | 6 +++- ui/timelinewidget.cpp | 2 +- 14 files changed, 125 insertions(+), 73 deletions(-) diff --git a/dialogs/preferencesdialog.cpp b/dialogs/preferencesdialog.cpp index eb5ee4b3a..4703e0ae8 100644 --- a/dialogs/preferencesdialog.cpp +++ b/dialogs/preferencesdialog.cpp @@ -190,6 +190,7 @@ void PreferencesDialog::accept() { if (olive::CurrentConfig.use_software_fallback != use_software_fallbacks_checkbox->isChecked() || olive::CurrentConfig.thumbnail_resolution != thumbnail_res_spinbox->value() || olive::CurrentConfig.waveform_resolution != waveform_res_spinbox->value() + || olive::CurrentConfig.css_path != custom_css_fn->text() #ifdef Q_OS_WIN32 || olive::CurrentConfig.use_native_menu_styling != native_menus->isChecked() #endif @@ -233,11 +234,7 @@ void PreferencesDialog::accept() { } // save settings from UI to backend - if (olive::CurrentConfig.css_path != custom_css_fn->text()) { - olive::CurrentConfig.css_path = custom_css_fn->text(); - olive::MainWindow->Restyle(); - } - + olive::CurrentConfig.css_path = custom_css_fn->text(); olive::CurrentConfig.recording_mode = recordingComboBox->currentIndex() + 1; olive::CurrentConfig.img_seq_formats = imgSeqFormatEdit->text(); olive::CurrentConfig.upcoming_queue_size = upcoming_queue_spinbox->value(); diff --git a/global/config.cpp b/global/config.cpp index d4c548d03..14377d672 100644 --- a/global/config.cpp +++ b/global/config.cpp @@ -264,7 +264,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->toolbar_widget->isVisible())); + stream.writeTextElement("ShowProjectToolbar", QString::number(panel_project->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)); diff --git a/global/global.cpp b/global/global.cpp index 171f2f34f..8980721d9 100644 --- a/global/global.cpp +++ b/global/global.cpp @@ -91,7 +91,12 @@ void OliveGlobal::check_for_autorecovery_file() { // detect auto-recovery file autorecovery_filename = data_dir + "/autorecovery.ove"; if (QFile::exists(autorecovery_filename)) { - if (QMessageBox::question(nullptr, tr("Auto-recovery"), tr("Olive didn't close properly and an autorecovery file was detected. Would you like to open it?"), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) { + if (QMessageBox::question(nullptr, + tr("Auto-recovery"), + tr("Olive didn't close properly and an autorecovery file " + "was detected. Would you like to open it?"), + QMessageBox::Yes, + QMessageBox::No) == QMessageBox::Yes) { enable_load_project_on_init = false; OpenProjectWorker(autorecovery_filename, true); } @@ -168,6 +173,12 @@ void OliveGlobal::SetNativeStyling(QWidget *w) 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(); + LoadDialog ld(olive::MainWindow); LoadThread* lt = new LoadThread(fn, autorecovery); @@ -179,6 +190,8 @@ void OliveGlobal::LoadProject(const QString &fn, bool autorecovery) lt->start(); ld.exec(); + + panel_project->ConnectFilterToModel(); } void OliveGlobal::ClearProject() diff --git a/panels/project.cpp b/panels/project.cpp index 3c762ff94..93e5005b3 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -78,7 +78,9 @@ QString autorecovery_filename; QStringList recent_projects; Project::Project(QWidget *parent) : - Panel(parent) + Panel(parent), + sorter(this), + sources_common(this, sorter) { QWidget* dockWidgetContents = new QWidget(this); @@ -88,10 +90,7 @@ Project::Project(QWidget *parent) : setWidget(dockWidgetContents); - sources_common = new SourcesCommon(this); - - sorter = new ProjectFilter(this); - sorter->setSourceModel(&olive::project_model); + ConnectFilterToModel(); // optional toolbar toolbar_widget = new QWidget(); @@ -134,7 +133,7 @@ Project::Project(QWidget *parent) : toolbar_search = new QLineEdit(); toolbar_search->setClearButtonEnabled(true); - connect(toolbar_search, SIGNAL(textChanged(QString)), sorter, SLOT(update_search_filter(const QString&))); + connect(toolbar_search, SIGNAL(textChanged(QString)), &sorter, SLOT(update_search_filter(const QString&))); toolbar->addWidget(toolbar_search); QPushButton* toolbar_tree_view = new QPushButton(); @@ -152,9 +151,9 @@ Project::Project(QWidget *parent) : verticalLayout->addWidget(toolbar_widget); // tree view - tree_view = new SourceTable(); + tree_view = new SourceTable(sources_common); tree_view->project_parent = this; - tree_view->setModel(sorter); + tree_view->setModel(&sorter); verticalLayout->addWidget(tree_view); // Set the first column width @@ -189,9 +188,9 @@ Project::Project(QWidget *parent) : icon_view_container_layout->addLayout(icon_view_controls); - icon_view = new SourceIconView(); + icon_view = new SourceIconView(sources_common); icon_view->project_parent = this; - icon_view->setModel(sorter); + icon_view->setModel(&sorter); icon_view->setIconSize(QSize(100, 100)); icon_view->setViewMode(QListView::IconMode); icon_view->setUniformItemSizes(true); @@ -212,8 +211,14 @@ Project::Project(QWidget *parent) : Retranslate(); } -Project::~Project() { - delete sorter; +void Project::ConnectFilterToModel() +{ + sorter.setSourceModel(&olive::project_model); +} + +void Project::DisconnectFilterToModel() +{ + sorter.setSourceModel(nullptr); } void Project::Retranslate() { @@ -418,10 +423,10 @@ void Project::new_folder() { QModelIndex index = olive::project_model.create_index(m->row(), 0, m.get()); switch (olive::CurrentConfig.project_view_type) { case olive::PROJECT_VIEW_TREE: - tree_view->edit(sorter->mapFromSource(index)); + tree_view->edit(sorter.mapFromSource(index)); break; case olive::PROJECT_VIEW_ICON: - icon_view->edit(sorter->mapFromSource(index)); + icon_view->edit(sorter.mapFromSource(index)); break; } } @@ -475,7 +480,7 @@ MediaPtr Project::create_folder_internal(QString name) { } Media* Project::item_to_media(const QModelIndex &index) { - return static_cast(sorter->mapToSource(index).internalPointer()); + return static_cast(sorter.mapToSource(index).internalPointer()); } MediaPtr Project::item_to_media_ptr(const QModelIndex &index) { @@ -503,6 +508,21 @@ void Project::get_all_media_from_table(QList& items, QList& list } } +bool Project::IsToolbarVisible() +{ + return toolbar_widget->isVisible(); +} + +void Project::SetToolbarVisible(bool visible) +{ + toolbar_widget->setVisible(visible); +} + +bool Project::IsProjectWidget(QObject *child) +{ + return (child == tree_view || child == icon_view); +} + bool delete_clips_in_clipboard_with_media(ComboAction* ca, Media* m) { int delete_count = 0; if (clipboard_type == CLIPBOARD_TYPE_CLIP) { @@ -939,7 +959,7 @@ bool Project::reveal_media(Media *media, QModelIndex parent) { // if m == media, then we found the media object we were looking for // get sorter proxy item (the item that's "visible") - QModelIndex sorted_index = sorter->mapFromSource(item); + QModelIndex sorted_index = sorter.mapFromSource(item); // retrieve its parent item QModelIndex hierarchy = sorted_index.parent(); @@ -954,8 +974,8 @@ bool Project::reveal_media(Media *media, QModelIndex parent) { // select item (requires a QItemSelection object to select the whole row) QItemSelection row_select( - sorter->index(sorted_index.row(), 0, sorted_index.parent()), - sorter->index(sorted_index.row(), sorter->columnCount()-1, sorted_index.parent()) + sorter.index(sorted_index.row(), 0, sorted_index.parent()), + sorter.index(sorted_index.row(), sorter.columnCount()-1, sorted_index.parent()) ); tree_view->selectionModel()->select(row_select, QItemSelectionModel::Select); @@ -1306,10 +1326,10 @@ void Project::update_view_type() { switch (olive::CurrentConfig.project_view_type) { case olive::PROJECT_VIEW_TREE: - sources_common->view = tree_view; + sources_common.view = tree_view; break; case olive::PROJECT_VIEW_ICON: - sources_common->view = icon_view; + sources_common.view = icon_view; break; } } diff --git a/panels/project.h b/panels/project.h index d2984b7d1..4cf77fe95 100644 --- a/panels/project.h +++ b/panels/project.h @@ -55,7 +55,9 @@ class Project : public Panel { Q_OBJECT public: explicit Project(QWidget *parent = nullptr); - ~Project(); + + void ConnectFilterToModel(); + void DisconnectFilterToModel(); bool is_focused(); void clear(); @@ -78,19 +80,14 @@ public: QVector list_all_project_sequences(); - SourceTable* tree_view; - SourceIconView* icon_view; - SourcesCommon* sources_common; - - ProjectFilter* sorter; - QVector last_imported_media; QModelIndexList get_current_selected(); void get_all_media_from_table(QList &items, QList &list, int type = -1); - QWidget* toolbar_widget; + bool IsToolbarVisible(); + bool IsProjectWidget(QObject *child); virtual void Retranslate() override; protected: @@ -104,6 +101,8 @@ public slots: void open_properties(); void new_folder(); void new_sequence(); + + void SetToolbarVisible(bool visible); private: void save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only, const QModelIndex &parent = QModelIndex()); int folder_id; @@ -115,6 +114,13 @@ private: QWidget* icon_view_container; QPushButton* directory_up; QLineEdit* toolbar_search; + + QWidget* toolbar_widget; + SourceTable* tree_view; + SourceIconView* icon_view; + + ProjectFilter sorter; + SourcesCommon sources_common; private slots: void update_view_type(); void set_icon_view(); diff --git a/panels/viewer.cpp b/panels/viewer.cpp index 3a45fcd3c..510bc6263 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -875,7 +875,11 @@ void Viewer::timer_update() { previous_playhead = seq->playhead; seq->playhead = qMax(0, qRound(playhead_start + ((QDateTime::currentMSecsSinceEpoch()-start_msecs) * 0.001 * seq->frame_rate * playback_speed))); - if (olive::CurrentConfig.seek_also_selects) panel_timeline->select_from_playhead(); + + if (olive::CurrentConfig.seek_also_selects) { + panel_timeline->select_from_playhead(); + } + update_parents(olive::CurrentConfig.seek_also_selects); if (playing) { diff --git a/project/sourcescommon.cpp b/project/sourcescommon.cpp index d91850b3c..e0e80746c 100644 --- a/project/sourcescommon.cpp +++ b/project/sourcescommon.cpp @@ -47,9 +47,10 @@ #include "ui/menu.h" #include "undo/undostack.h" -SourcesCommon::SourcesCommon(Project* parent) : +SourcesCommon::SourcesCommon(Project* parent, ProjectFilter &sort_filter) : editing_item(nullptr), - project_parent(parent) + project_parent(parent), + sort_filter_(sort_filter) { rename_timer.setInterval(1000); connect(&rename_timer, SIGNAL(timeout()), this, SLOT(rename_interval())); @@ -97,13 +98,13 @@ void SourcesCommon::show_context_menu(QWidget* parent, const QModelIndexList& it QAction* toolbar_action = view_menu->addAction(tr("Show Toolbar")); toolbar_action->setCheckable(true); - toolbar_action->setChecked(project_parent->toolbar_widget->isVisible()); - connect(toolbar_action, SIGNAL(triggered(bool)), project_parent->toolbar_widget, SLOT(setVisible(bool))); + toolbar_action->setChecked(project_parent->IsToolbarVisible()); + connect(toolbar_action, SIGNAL(triggered(bool)), project_parent, SLOT(SetToolbarVisible(bool))); QAction* show_sequences = view_menu->addAction(tr("Show Sequences")); show_sequences->setCheckable(true); - show_sequences->setChecked(panel_project->sorter->get_show_sequences()); - connect(show_sequences, SIGNAL(triggered(bool)), panel_project->sorter, SLOT(set_show_sequences(bool))); + show_sequences->setChecked(sort_filter_.get_show_sequences()); + connect(show_sequences, SIGNAL(triggered(bool)), &sort_filter_, SLOT(set_show_sequences(bool))); if (items.size() > 0) { if (items.size() == 1) { @@ -282,7 +283,7 @@ void SourcesCommon::dropEvent(QWidget* parent, bool replace = false; if (urls.size() == 1 && drop_item.isValid() - && (m != nullptr && m->get_type() == MEDIA_TYPE_FOOTAGE) + && m->get_type() == MEDIA_TYPE_FOOTAGE && !QFileInfo(paths.at(0)).isDir() && olive::CurrentConfig.drop_on_media_to_replace && QMessageBox::question( diff --git a/project/sourcescommon.h b/project/sourcescommon.h index 191b43fbb..506610ebc 100644 --- a/project/sourcescommon.h +++ b/project/sourcescommon.h @@ -26,6 +26,7 @@ #include #include "project/footage.h" +#include "project/projectfilter.h" class Project; class QMouseEvent; @@ -36,7 +37,7 @@ class QDropEvent; class SourcesCommon : public QObject { Q_OBJECT public: - SourcesCommon(Project *parent); + SourcesCommon(Project *parent, ProjectFilter& sort_filter); QAbstractItemView* view; void show_context_menu(QWidget* parent, const QModelIndexList &items); @@ -66,6 +67,8 @@ private: // we cache the selected footage items for open_create_proxy_dialog() QVector cached_selected_footage; + + ProjectFilter& sort_filter_; }; #endif // SOURCESCOMMON_H diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index 76fc7f584..f7955e319 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -391,16 +391,14 @@ bool MainWindow::load_css_from_file(const QString &fn) { void MainWindow::Restyle() { // Set up UI style - if (olive::styling::UseNativeUI()) { - qApp->setStyle(QStyleFactory::create("")); - } else { + if (!olive::styling::UseNativeUI()) { qApp->setStyle(QStyleFactory::create("Fusion")); // Set up whether to load custom CSS or default CSS+palette if (!olive::CurrentConfig.css_path.isEmpty() && load_css_from_file(olive::CurrentConfig.css_path)) { - setPalette(QPalette()); + qApp->setPalette(qApp->style()->standardPalette()); } else { diff --git a/ui/sourceiconview.cpp b/ui/sourceiconview.cpp index 66c62e6cf..4916a653a 100644 --- a/ui/sourceiconview.cpp +++ b/ui/sourceiconview.cpp @@ -27,7 +27,9 @@ #include "project/sourcescommon.h" #include "global/debug.h" -SourceIconView::SourceIconView(QWidget *parent) : QListView(parent) { +SourceIconView::SourceIconView(SourcesCommon &commons) : + commons_(commons) +{ setSelectionMode(QAbstractItemView::ExtendedSelection); setResizeMode(QListView::Adjust); setContextMenuPolicy(Qt::CustomContextMenu); @@ -36,17 +38,17 @@ SourceIconView::SourceIconView(QWidget *parent) : QListView(parent) { } void SourceIconView::show_context_menu() { - project_parent->sources_common->show_context_menu(this, selectedIndexes()); + commons_.show_context_menu(this, selectedIndexes()); } void SourceIconView::item_click(const QModelIndex& index) { if (selectedIndexes().size() == 1 && index.column() == 0) { - project_parent->sources_common->item_click(project_parent->item_to_media(index), index); + commons_.item_click(project_parent->item_to_media(index), index); } } void SourceIconView::mousePressEvent(QMouseEvent* event) { - project_parent->sources_common->mousePressEvent(event); + commons_.mousePressEvent(event); if (!indexAt(event->pos()).isValid()) selectionModel()->clear(); QListView::mousePressEvent(event); } @@ -70,7 +72,7 @@ void SourceIconView::dragMoveEvent(QDragMoveEvent *event) { void SourceIconView::dropEvent(QDropEvent* event) { QModelIndex drop_item = indexAt(event->pos()); if (!drop_item.isValid()) drop_item = rootIndex(); - project_parent->sources_common->dropEvent(this, event, drop_item, selectedIndexes()); + commons_.dropEvent(this, event, drop_item, selectedIndexes()); } void SourceIconView::mouseDoubleClickEvent(QMouseEvent *) { @@ -84,6 +86,6 @@ void SourceIconView::mouseDoubleClickEvent(QMouseEvent *) { } } if (default_behavior) { - project_parent->sources_common->mouseDoubleClickEvent(selectedIndexes()); + commons_.mouseDoubleClickEvent(selectedIndexes()); } } diff --git a/ui/sourceiconview.h b/ui/sourceiconview.h index e561a7a6f..a396aa938 100644 --- a/ui/sourceiconview.h +++ b/ui/sourceiconview.h @@ -23,24 +23,28 @@ #include +#include "project/sourcescommon.h" + class Project; class SourceIconView : public QListView { - Q_OBJECT + Q_OBJECT public: - SourceIconView(QWidget* parent = 0); - Project* project_parent; + SourceIconView(SourcesCommon& commons); + Project* project_parent; - void mousePressEvent(QMouseEvent* event); - void mouseDoubleClickEvent(QMouseEvent *event); - void dragEnterEvent(QDragEnterEvent *event); - void dragMoveEvent(QDragMoveEvent *event); - void dropEvent(QDropEvent* event); + void mousePressEvent(QMouseEvent* event); + void mouseDoubleClickEvent(QMouseEvent *event); + void dragEnterEvent(QDragEnterEvent *event); + void dragMoveEvent(QDragMoveEvent *event); + void dropEvent(QDropEvent* event); signals: - void changed_root(); + void changed_root(); private slots: - void show_context_menu(); - void item_click(const QModelIndex& index); + void show_context_menu(); + void item_click(const QModelIndex& index); +private: + SourcesCommon& commons_; }; #endif // SOURCEICONVIEW_H diff --git a/ui/sourcetable.cpp b/ui/sourcetable.cpp index a421cd80b..5a0d67ac0 100644 --- a/ui/sourcetable.cpp +++ b/ui/sourcetable.cpp @@ -45,7 +45,7 @@ #include #include -SourceTable::SourceTable(QWidget* parent) : QTreeView(parent) { +SourceTable::SourceTable(SourcesCommon& commons) : commons_(commons) { setSortingEnabled(true); setAcceptDrops(true); sortByColumn(0, Qt::AscendingOrder); @@ -58,22 +58,22 @@ SourceTable::SourceTable(QWidget* parent) : QTreeView(parent) { } void SourceTable::show_context_menu() { - project_parent->sources_common->show_context_menu(this, selectionModel()->selectedRows()); + commons_.show_context_menu(this, selectionModel()->selectedRows()); } void SourceTable::item_click(const QModelIndex& index) { if (selectionModel()->selectedRows().size() == 1 && index.column() == 0) { - project_parent->sources_common->item_click(project_parent->item_to_media(index), index); + commons_.item_click(project_parent->item_to_media(index), index); } } void SourceTable::mousePressEvent(QMouseEvent* event) { - project_parent->sources_common->mousePressEvent(event); + commons_.mousePressEvent(event); QTreeView::mousePressEvent(event); } void SourceTable::mouseDoubleClickEvent(QMouseEvent* ) { - project_parent->sources_common->mouseDoubleClickEvent(selectionModel()->selectedRows()); + commons_.mouseDoubleClickEvent(selectionModel()->selectedRows()); } void SourceTable::dragEnterEvent(QDragEnterEvent *event) { @@ -93,5 +93,5 @@ void SourceTable::dragMoveEvent(QDragMoveEvent *event) { } void SourceTable::dropEvent(QDropEvent* event) { - project_parent->sources_common->dropEvent(this, event, indexAt(event->pos()), selectionModel()->selectedRows()); + commons_.dropEvent(this, event, indexAt(event->pos()), selectionModel()->selectedRows()); } diff --git a/ui/sourcetable.h b/ui/sourcetable.h index 251d87776..cc28ea48f 100644 --- a/ui/sourcetable.h +++ b/ui/sourcetable.h @@ -25,6 +25,8 @@ #include #include +#include "project/sourcescommon.h" + class Project; class Media; @@ -32,7 +34,7 @@ class SourceTable : public QTreeView { Q_OBJECT public: - SourceTable(QWidget* parent = 0); + SourceTable(SourcesCommon& commons); Project* project_parent; protected: void mousePressEvent(QMouseEvent*); @@ -43,6 +45,8 @@ protected: private slots: void item_click(const QModelIndex& index); void show_context_menu(); +private: + SourcesCommon& commons_; }; #endif // SOURCETABLE_H diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 684f93f47..30b07e443 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -240,7 +240,7 @@ void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) { QVector media_list; panel_timeline->importing_files = false; - if (event->source() == panel_project->tree_view || event->source() == panel_project->icon_view) { + if (panel_project->IsProjectWidget(event->source())) { QModelIndexList items = panel_project->get_current_selected(); media_list.resize(items.size()); for (int i=0;i Date: Sat, 23 Mar 2019 01:41:05 +1100 Subject: [PATCH 14/35] restored setting to play past the end of the sequence --- dialogs/preferencesdialog.cpp | 6 ++++++ dialogs/preferencesdialog.h | 5 +++++ global/config.cpp | 5 +++++ global/config.h | 7 +++++++ panels/viewer.cpp | 5 +++-- 5 files changed, 26 insertions(+), 2 deletions(-) diff --git a/dialogs/preferencesdialog.cpp b/dialogs/preferencesdialog.cpp index 4703e0ae8..a9b8d2d6d 100644 --- a/dialogs/preferencesdialog.cpp +++ b/dialogs/preferencesdialog.cpp @@ -256,6 +256,8 @@ void PreferencesDialog::accept() { olive::CurrentConfig.use_native_menu_styling = native_menus->isChecked(); #endif + olive::CurrentConfig.auto_seek_to_beginning = auto_seek_to_beginning->isChecked(); + // Check if the thumbnail or waveform icon if (olive::CurrentConfig.thumbnail_resolution != thumbnail_res_spinbox->value() || olive::CurrentConfig.waveform_resolution != waveform_res_spinbox->value()) { @@ -560,6 +562,10 @@ void PreferencesDialog::setup_ui() { add_default_effects_to_clips->setChecked(olive::CurrentConfig.add_default_effects_to_clips); behavior_tab_layout->addWidget(add_default_effects_to_clips); + auto_seek_to_beginning = new QCheckBox(tr("Automatically Seek to the Beginning When Playing at the End of a Sequence")); + auto_seek_to_beginning->setChecked(olive::CurrentConfig.auto_seek_to_beginning); + behavior_tab_layout->addWidget(auto_seek_to_beginning); + // Appearance QWidget* appearance_tab = new QWidget(this); tabWidget->addTab(appearance_tab, tr("Appearance")); diff --git a/dialogs/preferencesdialog.h b/dialogs/preferencesdialog.h index 67538b7a7..fa87c457b 100644 --- a/dialogs/preferencesdialog.h +++ b/dialogs/preferencesdialog.h @@ -248,6 +248,11 @@ private: */ QCheckBox* add_default_effects_to_clips; + /** + * @brief UI widget for enabling/disabling Config::auto_seek_to_beginning + */ + QCheckBox* auto_seek_to_beginning; + /** * @brief UI widget for selecting the current UI style */ diff --git a/global/config.cpp b/global/config.cpp index 14377d672..667b178a9 100644 --- a/global/config.cpp +++ b/global/config.cpp @@ -64,6 +64,7 @@ Config::Config() upcoming_queue_type(olive::FRAME_QUEUE_TYPE_SECONDS), loop(false), seek_also_selects(false), + auto_seek_to_beginning(true), effect_textbox_lines(3), use_software_fallback(false), center_timeline_timecodes(true), @@ -179,6 +180,9 @@ void Config::load(QString path) { } else if (stream.name() == "SeekAlsoSelects") { stream.readNext(); seek_also_selects = (stream.text() == "1"); + } else if (stream.name() == "AutoSeekToBeginning") { + stream.readNext(); + auto_seek_to_beginning = (stream.text() == "1"); } else if (stream.name() == "CSSPath") { stream.readNext(); css_path = stream.text().toString(); @@ -271,6 +275,7 @@ void Config::save(QString path) { stream.writeTextElement("UpcomingFrameQueueType", QString::number(upcoming_queue_type)); stream.writeTextElement("Loop", QString::number(loop)); stream.writeTextElement("SeekAlsoSelects", QString::number(seek_also_selects)); + stream.writeTextElement("AutoSeekToBeginning", QString::number(auto_seek_to_beginning)); stream.writeTextElement("CSSPath", css_path); stream.writeTextElement("EffectTextboxLines", QString::number(effect_textbox_lines)); stream.writeTextElement("UseSoftwareFallback", QString::number(use_software_fallback)); diff --git a/global/config.h b/global/config.h index f11183ef5..968e4a8c3 100644 --- a/global/config.h +++ b/global/config.h @@ -413,6 +413,13 @@ struct Config { */ bool seek_also_selects; + /** + * @brief Automatically seek to the beginning of a sequence if the user plays beyond the end of it + * + * TRUE if this behavior should be enabled. + */ + bool auto_seek_to_beginning; + /** * @brief CSS Path * diff --git a/panels/viewer.cpp b/panels/viewer.cpp index 510bc6263..7e17bb583 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -402,7 +402,7 @@ void Viewer::play(bool in_to_out) { if (!is_recording_cued() && playback_speed >= 0 && (playing_in_to_out - || seq->playhead >= sequence_end_frame + || (olive::CurrentConfig.auto_seek_to_beginning && seq->playhead >= sequence_end_frame) || (seek_to_in && seq->playhead >= seq->workarea_out))) { seek(seek_to_in ? seq->workarea_in : 0); } @@ -890,7 +890,8 @@ void Viewer::timer_update() { pause(); } } else if (playback_speed > 0) { - if (seq->playhead >= seq->getEndFrame()) { + long end_frame = seq->getEndFrame(); + if ((olive::CurrentConfig.auto_seek_to_beginning || previous_playhead < end_frame) && seq->playhead >= end_frame) { pause(); } if (seq->using_workarea && seq->playhead >= seq->workarea_out) { From 8c8977f18d83c28b41d12e3ea8304d73fb424bd4 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 23 Mar 2019 01:46:02 +1100 Subject: [PATCH 15/35] removed novst macro --- effects/effect.cpp | 2 -- effects/effectloaders.cpp | 2 -- effects/internal/vsthost.cpp | 4 ---- effects/internal/vsthost.h | 4 ---- 4 files changed, 12 deletions(-) diff --git a/effects/effect.cpp b/effects/effect.cpp index 8e29a468c..5fbff641f 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -85,9 +85,7 @@ EffectPtr Effect::Create(Clip* c, const EffectMeta* em) { case EFFECT_INTERNAL_SHAKE: return std::make_shared(c, em); case EFFECT_INTERNAL_CORNERPIN: return std::make_shared(c, em); case EFFECT_INTERNAL_FILLLEFTRIGHT: return std::make_shared(c, em); -#ifndef NOVST case EFFECT_INTERNAL_VST: return std::make_shared(c, em); -#endif #ifndef NOFREI0R case EFFECT_INTERNAL_FREI0R: return std::make_shared(c, em); #endif diff --git a/effects/effectloaders.cpp b/effects/effectloaders.cpp index 250e8e4a7..b30938f43 100644 --- a/effects/effectloaders.cpp +++ b/effects/effectloaders.cpp @@ -59,11 +59,9 @@ void load_internal_effects() { em.internal = EFFECT_INTERNAL_PAN; effects.append(em); -#ifndef NOVST em.name = "VST Plugin 2.x"; em.internal = EFFECT_INTERNAL_VST; effects.append(em); -#endif em.name = "Tone"; em.internal = EFFECT_INTERNAL_TONE; diff --git a/effects/internal/vsthost.cpp b/effects/internal/vsthost.cpp index 7fe21df0f..de723af8b 100644 --- a/effects/internal/vsthost.cpp +++ b/effects/internal/vsthost.cpp @@ -20,8 +20,6 @@ #include "vsthost.h" -#ifndef NOVST - // adapted from http://teragonaudio.com/article/How-to-make-your-own-VST-host.html #include @@ -419,5 +417,3 @@ void VSTHost::change_plugin() { } show_interface_btn->SetEnabled(plugin != nullptr); } - -#endif diff --git a/effects/internal/vsthost.h b/effects/internal/vsthost.h index 9d3b46e21..8bc117201 100644 --- a/effects/internal/vsthost.h +++ b/effects/internal/vsthost.h @@ -21,8 +21,6 @@ #ifndef VSTHOSTWIN_H #define VSTHOSTWIN_H -#ifndef NOVST - #include "effects/effect.h" #include "global/crossplatformlib.h" @@ -77,6 +75,4 @@ private: #endif }; -#endif - #endif // VSTHOSTWIN_H From 81a7b148168496d96bf631d9dbb1a8747ee4b019 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 23 Mar 2019 02:24:28 +1100 Subject: [PATCH 16/35] use QLibrary to load external libs instead of direct OS calls --- effects/effectloaders.cpp | 19 +++--- effects/internal/frei0reffect.cpp | 26 +++---- effects/internal/frei0reffect.h | 3 +- effects/internal/vsthost.cpp | 110 ++++++++++-------------------- effects/internal/vsthost.h | 13 ++-- global/crossplatformlib.cpp | 64 ----------------- global/crossplatformlib.h | 49 ------------- olive.pro | 5 -- 8 files changed, 66 insertions(+), 223 deletions(-) delete mode 100644 global/crossplatformlib.cpp delete mode 100644 global/crossplatformlib.h diff --git a/effects/effectloaders.cpp b/effects/effectloaders.cpp index b30938f43..fd012a227 100644 --- a/effects/effectloaders.cpp +++ b/effects/effectloaders.cpp @@ -25,12 +25,11 @@ #include "global/path.h" #include "panels/panels.h" #include "panels/effectcontrols.h" -#include "global/crossplatformlib.h" #include "global/config.h" #include #include - +#include #include #ifndef NOFREI0R @@ -206,15 +205,19 @@ void EffectInit::StartLoading() { void load_frei0r_effects_worker(const QString& dir, EffectMeta& em, QVector& loaded_names) { QDir search_dir(dir); if (search_dir.exists()) { - QList entry_list = search_dir.entryList(LibFilter(), QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot); + QList entry_list = search_dir.entryList(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot); for (int j=0;j(LibAddress(effect, "f0r_get_plugin_info")); + + QString path_without_extension = search_dir.filePath(QFileInfo(entry_list.at(j)).baseName()); + + QLibrary effect; + effect.setFileName(path_without_extension); + if (effect.load()) { + f0rGetPluginInfo get_info_func = reinterpret_cast(effect.resolve("f0r_get_plugin_info")); if (get_info_func != nullptr) { f0r_plugin_info_t info; get_info_func(&info); @@ -231,11 +234,9 @@ void load_frei0r_effects_worker(const QString& dir, EffectMeta& em, QVectorpath).filePath(em->filename); - handle = LibLoad(dll_fn); - if(handle == nullptr) { + handle.setFileName(dll_fn); + + + if (!handle.load()) { QString dll_error; #ifdef _WIN32 @@ -75,18 +77,18 @@ Frei0rEffect::Frei0rEffect(Clip* c, const EffectMeta *em) : return; } - f0rInitFunc init = reinterpret_cast(LibAddress(handle, "f0r_init")); + f0rInitFunc init = reinterpret_cast(handle.resolve("f0r_init")); init(); construct_module(); f0r_plugin_info_t info; - f0rGetPluginInfo info_func = reinterpret_cast(LibAddress(handle, "f0r_get_plugin_info")); + f0rGetPluginInfo info_func = reinterpret_cast(handle.resolve("f0r_get_plugin_info")); info_func(&info); param_count = info.num_params; - get_param_info = reinterpret_cast(LibAddress(handle, "f0r_get_param_info")); + get_param_info = reinterpret_cast(handle.resolve("f0r_get_param_info")); for (int i=0;i(LibAddress(handle, "f0r_deinit")); + if (handle.isLoaded()) { + f0rDeinitFunc deinit = reinterpret_cast(handle.resolve("f0r_deinit")); deinit(); - LibClose(handle); + handle.unload(); } } void Frei0rEffect::process_image(double timecode, uint8_t *input, uint8_t *output, int) { - f0rUpdateFunc update_func = reinterpret_cast(LibAddress(handle, "f0r_update")); + f0rUpdateFunc update_func = reinterpret_cast(handle.resolve("f0r_update")); for (int i=0;i(LibAddress(handle, "f0r_set_param_value")); + f0rSetParamValue set_param = reinterpret_cast(handle.resolve("f0r_set_param_value")); switch (param_info.type) { case F0R_PARAM_BOOL: { @@ -197,7 +199,7 @@ void Frei0rEffect::refresh() { void Frei0rEffect::destruct_module() { if (open) { - f0rDestructFunc destruct = reinterpret_cast(LibAddress(handle, "f0r_destruct")); + f0rDestructFunc destruct = reinterpret_cast(handle.resolve("f0r_destruct")); destruct(instance); open = false; @@ -205,7 +207,7 @@ void Frei0rEffect::destruct_module() { } void Frei0rEffect::construct_module() { - f0rConstructFunc construct = reinterpret_cast(LibAddress(handle, "f0r_construct")); + f0rConstructFunc construct = reinterpret_cast(handle.resolve("f0r_construct")); instance = construct(parent_clip->media_width(), parent_clip->media_height()); open = true; diff --git a/effects/internal/frei0reffect.h b/effects/internal/frei0reffect.h index 6f7356b28..b309a15cd 100644 --- a/effects/internal/frei0reffect.h +++ b/effects/internal/frei0reffect.h @@ -23,6 +23,7 @@ #ifndef NOFREI0R +#include #include #include "effects/effect.h" @@ -41,7 +42,7 @@ public: virtual void refresh(); private: - ModulePtr handle; + QLibrary handle; f0r_instance_t instance; int param_count; f0rGetParamInfo get_param_info; diff --git a/effects/internal/vsthost.cpp b/effects/internal/vsthost.cpp index de723af8b..09ed8b593 100644 --- a/effects/internal/vsthost.cpp +++ b/effects/internal/vsthost.cpp @@ -34,7 +34,14 @@ #include "global/global.h" #include "global/debug.h" -#ifdef __linux__ +// Load libraries for retrieving the native window handle. Used for VST plugins that have a separate window +// dedicated to controls. +#if defined(_WIN32) +#include +#elif defined(__APPLE__) +#include +class NSWindow; +#elif defined(__linux__) #include #endif @@ -105,95 +112,53 @@ typedef int32_t (*processEventsFuncPtr)(VstEvents *events); typedef void (*processFuncPtr)(AEffect *effect, float **inputs, float **outputs, int32_t sampleFrames); void VSTHost::loadPlugin() { + QString dll_fn = file_field->GetFileAt(0); if (dll_fn.isEmpty()) { return; } -#if defined(__APPLE__) - bundle = BundleLoad(dll_fn); + // Try to load the plugin + modulePtr.setFileName(dll_fn); + if (!modulePtr.load()) { - if (bundle == NULL) { - QMessageBox::critical(nullptr, tr("Error loading VST plugin"), tr("Failed to create VST reference")); + // Show an error if the plugin fails to load + + qCritical() << "Failed to load VST plugin" << dll_fn << "-" << modulePtr.errorString(); + QMessageBox::critical(olive::MainWindow, + tr("Error loading VST plugin"), + tr("Failed to load VST plugin \"%1\": %2").arg(dll_fn, modulePtr.errorString())); return; + } - vstPluginFuncPtr mainEntryPoint = NULL; - mainEntryPoint = (vstPluginFuncPtr)CFBundleGetFunctionPointerForName(bundle, CFSTR("VSTPluginMain")); - // VST plugins previous to the 2.4 SDK used main_macho for the entry point name - if(mainEntryPoint == NULL) { - mainEntryPoint = (vstPluginFuncPtr)CFBundleGetFunctionPointerForName(bundle, CFSTR("main_macho")); + // Try to find the VST entry point (first using VSTPluginMain() ) + vstPluginFuncPtr mainEntryPoint = reinterpret_cast(modulePtr.resolve("VSTPluginMain")); + + if (mainEntryPoint == nullptr) { + // If there's no VSTPluginMain(), the plugin may use main() instead + mainEntryPoint = reinterpret_cast(modulePtr.resolve("main")); } - if(mainEntryPoint == NULL) { - qCritical() << "Couldn't get a pointer to VST plugin's main()"; - BundleClose(bundle); + + if (mainEntryPoint == nullptr) { + QMessageBox::critical(olive::MainWindow, + tr("Error loading VST plugin"), + tr("Failed to locate entry point for dynamic library.")); + modulePtr.unload(); return; } + // Instantiate the plugin plugin = mainEntryPoint(hostCallback); - if(plugin == NULL) { - qCritical() << "Plugin's main() returns null"; - BundleClose(bundle); - return; - } -#else - modulePtr = LibLoad(dll_fn); - if(modulePtr == nullptr) { - QString dll_error; -#ifdef _WIN32 - DWORD dll_err = GetLastError(); - dll_error = QString::number(dll_err); -#elif defined(__linux__) || defined(__HAIKU__) - dll_error = dlerror(); -#endif - qCritical() << "Failed to load VST plugin" << dll_fn << "-" << dll_error; - - QString msg_err = tr("Failed to load VST plugin \"%1\": %2").arg(dll_fn, dll_error); - -#ifdef _WIN32 - if (dll_err == 193) { -#ifdef _WIN64 - msg_err += "\n\n" + tr("NOTE: You can't load 32-bit VST plugins into a 64-bit build of Olive. Please find a 64-bit version of this plugin or switch to a 32-bit build of Olive."); -#elif _WIN32 - msg_err += "\n\n" + tr("NOTE: You can't load 64-bit VST plugins into a 32-bit build of Olive. Please find a 32-bit version of this plugin or switch to a 64-bit build of Olive."); -#endif - } -#endif - - QMessageBox::critical(nullptr, tr("Error loading VST plugin"), msg_err); - - return; - } - - vstPluginFuncPtr mainEntryPoint = reinterpret_cast(LibAddress(modulePtr, "VSTPluginMain")); - - if (mainEntryPoint == nullptr) { - // if there's no VSTPluginMain(), fallback to main() - mainEntryPoint = reinterpret_cast(LibAddress(modulePtr, "main")); - } - - if (mainEntryPoint == nullptr) { - QMessageBox::critical(nullptr, tr("Error loading VST plugin"), tr("Failed to locate entry point for dynamic library.")); - LibClose(modulePtr); - } else { - // Instantiate the plugin - plugin = mainEntryPoint(hostCallback); - } -#endif } void VSTHost::freePlugin() { if (plugin != nullptr) { stopPlugin(); data_cache.clear(); -#if defined(__APPLE__) - CFBundleUnloadExecutable(bundle); - CFRelease(bundle); -#else - LibClose(modulePtr); -#endif + modulePtr.unload(); plugin = nullptr; } } @@ -406,13 +371,10 @@ void VSTHost::change_plugin() { dialog->setFixedSize(eRect->right - eRect->left, eRect->bottom - eRect->top); } else { -#ifdef __APPLE__ - CFBundleUnloadExecutable(bundle); - CFRelease(bundle); -#else - LibClose(modulePtr); -#endif + + modulePtr.unload(); plugin = nullptr; + } } show_interface_btn->SetEnabled(plugin != nullptr); diff --git a/effects/internal/vsthost.h b/effects/internal/vsthost.h index 8bc117201..1d64548ef 100644 --- a/effects/internal/vsthost.h +++ b/effects/internal/vsthost.h @@ -21,17 +21,16 @@ #ifndef VSTHOSTWIN_H #define VSTHOSTWIN_H +#include +#include + #include "effects/effect.h" - #include "global/crossplatformlib.h" - #include "include/vestige.h" // Plugin's dispatcher function typedef intptr_t (*dispatcherFuncPtr)(AEffect *effect, int32_t opCode, int32_t index, int32_t value, void *ptr, float opt); -#include - class VSTHost : public Effect { Q_OBJECT public: @@ -68,11 +67,7 @@ private: void send_data_cache_to_plugin(); -#if defined(__APPLE__) - CFBundleRef bundle; -#else - ModulePtr modulePtr; -#endif + QLibrary modulePtr; }; #endif // VSTHOSTWIN_H diff --git a/global/crossplatformlib.cpp b/global/crossplatformlib.cpp deleted file mode 100644 index f5b7d486b..000000000 --- a/global/crossplatformlib.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#include "crossplatformlib.h" - -#include - -ModulePtr LibLoad(const QString &filename) { -#ifdef _WIN32 - LPCWSTR dll_fn_w = reinterpret_cast(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 diff --git a/global/crossplatformlib.h b/global/crossplatformlib.h deleted file mode 100644 index bd1935a7d..000000000 --- a/global/crossplatformlib.h +++ /dev/null @@ -1,49 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#ifndef CROSSPLATFORMLIB_H -#define CROSSPLATFORMLIB_H - -#include - -#ifdef _WIN32 - #include - #define LibAddress GetProcAddress - #define LibClose FreeModule - #define ModulePtr HMODULE -#elif defined(__linux__) || defined(__APPLE__) || defined(__HAIKU__) - #include - #define LibAddress dlsym - #define LibClose dlclose - #define ModulePtr void* -#endif - -ModulePtr LibLoad(const QString& filename); -QStringList LibFilter(); - -#ifdef __APPLE__ -#include -class NSWindow; - -CFBundleRef BundleLoad(const QString& filename); -void BundleClose(CFBundleRef bundle); -#endif - -#endif // CROSSPLATFORMLIB_H diff --git a/olive.pro b/olive.pro index e86586c3f..5e338de17 100644 --- a/olive.pro +++ b/olive.pro @@ -135,7 +135,6 @@ SOURCES += \ project/projectfilter.cpp \ effects/internal/frei0reffect.cpp \ effects/effectloaders.cpp \ - global/crossplatformlib.cpp \ effects/internal/vsthost.cpp \ ui/flowlayout.cpp \ dialogs/proxydialog.cpp \ @@ -262,7 +261,6 @@ HEADERS += \ project/projectfilter.h \ effects/internal/frei0reffect.h \ effects/effectloaders.h \ - global/crossplatformlib.h \ effects/internal/vsthost.h \ ui/flowlayout.h \ dialogs/proxydialog.h \ @@ -338,9 +336,6 @@ unix:!mac { CONFIG += link_pkgconfig PKGCONFIG += libavutil libavformat libavcodec libavfilter libswscale libswresample } -unix:!mac:!haiku { - LIBS += -ldl -} RESOURCES += \ icons/icons.qrc \ From 37374e6ef3de320446ec96c719452ebd90945078 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 23 Mar 2019 02:52:13 +1100 Subject: [PATCH 17/35] more fixes for migrating to QLibrary --- effects/internal/frei0reffect.cpp | 26 +++----------------------- effects/internal/frei0reffect.h | 1 - effects/internal/vsthost.h | 1 - 3 files changed, 3 insertions(+), 25 deletions(-) diff --git a/effects/internal/frei0reffect.cpp b/effects/internal/frei0reffect.cpp index 94d93a611..e5c0516df 100644 --- a/effects/internal/frei0reffect.cpp +++ b/effects/internal/frei0reffect.cpp @@ -50,29 +50,9 @@ Frei0rEffect::Frei0rEffect(Clip* c, const EffectMeta *em) : if (!handle.load()) { - QString dll_error; - -#ifdef _WIN32 - DWORD dll_err = GetLastError(); - dll_error = QString::number(dll_err); -#elif __linux__ - dll_error = dlerror(); -#endif - qCritical() << "Failed to load Frei0r plugin" << dll_fn << "-" << dll_error; - - QString msg_err = tr("Failed to load Frei0r plugin \"%1\": %2").arg(dll_fn, dll_error); - -#ifdef _WIN32 - if (dll_err == 193) { -#ifdef _WIN64 - msg_err += "\n\n" + tr("NOTE: You can't load 32-bit Frei0r plugins into a 64-bit build of Olive. Please find a 64-bit version of this plugin or switch to a 32-bit build of Olive."); -#elif _WIN32 - msg_err += "\n\n" + tr("NOTE: You can't load 64-bit Frei0r plugins into a 32-bit build of Olive. Please find a 32-bit version of this plugin or switch to a 64-bit build of Olive."); -#endif - } -#endif - - QMessageBox::critical(nullptr, tr("Error loading Frei0r plugin"), msg_err); + QString dll_error = handle.errorString(); + QMessageBox::critical(nullptr, tr("Error loading Frei0r plugin"), + tr("Failed to load Frei0r plugin \"%1\": %2").arg(dll_fn, dll_error)); return; } diff --git a/effects/internal/frei0reffect.h b/effects/internal/frei0reffect.h index b309a15cd..2078289b0 100644 --- a/effects/internal/frei0reffect.h +++ b/effects/internal/frei0reffect.h @@ -27,7 +27,6 @@ #include #include "effects/effect.h" -#include "global/crossplatformlib.h" typedef void (*f0rGetParamInfo)(f0r_param_info_t * info, int param_index ); diff --git a/effects/internal/vsthost.h b/effects/internal/vsthost.h index 1d64548ef..216cb8401 100644 --- a/effects/internal/vsthost.h +++ b/effects/internal/vsthost.h @@ -25,7 +25,6 @@ #include #include "effects/effect.h" -#include "global/crossplatformlib.h" #include "include/vestige.h" // Plugin's dispatcher function From cc69f5b326b7192d09b7bf1e9728c7128790403d Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 23 Mar 2019 03:04:58 +1100 Subject: [PATCH 18/35] set file field to default empty string --- effects/fields/filefield.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/effects/fields/filefield.cpp b/effects/fields/filefield.cpp index 4e4eab335..577a695f2 100644 --- a/effects/fields/filefield.cpp +++ b/effects/fields/filefield.cpp @@ -7,7 +7,8 @@ FileField::FileField(EffectRow* parent, const QString &id) : EffectField(parent, id, EFFECT_FIELD_FILE) { - + // Set default value to an empty string + SetValueAt(0, ""); } QString FileField::GetFileAt(double timecode) From a516a9fd59c1de84a6520328e99e72d2e0f0d823 Mon Sep 17 00:00:00 2001 From: ZoomTen Date: Sat, 23 Mar 2019 17:31:31 +0700 Subject: [PATCH 19/35] added v1 of indonesian translation --- ts/olive_id.ts | 3625 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3625 insertions(+) create mode 100644 ts/olive_id.ts diff --git a/ts/olive_id.ts b/ts/olive_id.ts new file mode 100644 index 000000000..236f8b59a --- /dev/null +++ b/ts/olive_id.ts @@ -0,0 +1,3625 @@ + + + + + AboutDialog + + + Olive is a non-linear video editor. This software is free and protected by the GNU GPL. + Olive adalah aplikasi pengedit video yang bersifat non-linier. Aplikasi ini bebas, gratis, dan terlindungi GNU GPL. + + + + Olive Team is obliged to inform users that Olive source code is available for download from its website. + Olive Team berkewajiban memberitahu pengguna bahwa kode sumber aplikasi ini dapat diunduh dari situs resminya. + + + + ActionSearch + + + Search for action... + Cari Aksi... + + + + AdvancedVideoDialog + + + Advanced Video Settings + Pengaturan Video Lanjutan + + + + Pixel Format: + Bentuk piksel: + + + + Threads: + Jumlah thread/utas: + + + + Audio + + + %1 Audio + Audio %1 + + + + Recording %1 + Merekam %1 + + + + AudioNoiseEffect + + + Amount + Kenyaringan + + + + Mix + + + + + Cacher + + + + Could not open %1 - %2 + Tidak dapat membuka %1 - %2 + + + + ChannelLayoutName + + + Invalid + Salah + + + + Mono + Mono + + + + Stereo + Stereo + + + + ClipPropertiesDialog + + + "%1" Properties + Properti untuk "%1" + + + + Multiple Clip Properties + Properti untuk Beberapa Klip + + + + Name: + Nama: + + + + Duration: + Durasi: + + + + (multiple) + (beberapa) + + + + CollapsibleWidget + + + <untitled> + <belum dinamai> + + + + ColorButton + + + Set Color + Pilih Warna + + + + CornerPinEffect + + + Top Left + Kiri Atas + + + + Top Right + Kanan Atas + + + + Bottom Left + Kiri Bawah + + + + Bottom Right + Kanan Bawah + + + + Perspective + Perspektif + + + + DebugDialog + + + Debug Log + Awakutu / Debug + + + + DemoNotice + + + + Welcome to Olive! + Selamat datang di Olive! + + + + Olive is a free open-source video editor released under the GNU GPL. If you have paid for this software, you have been scammed. + differentiate "free" as in "free of charge" and "free" as in "freedom/libre" + Olive adalah aplikasi edit video yang bebas, gratis dan terbuka sumbernya, terlisensi GNU GPL. Jika Anda membayar untuk aplikasi ini, Anda telah tertipu. + + + + 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 + Aplikasi ini masih dalam tahap ALPHA, artinya aplikasi ini belum stabil dan kemungkinan besar akan crash, memiliki bug/kutu, dan banyak fitur yang belum ada. Kami tidak menjamin apapun, jadi Anda dipersilahkan menggunakan aplikasi ini dengan menanggung resikonya. Jika menemukan bug/kutu atau ingin meminta suatu fitur, silahkan lapor di %1 + + + + Thank you for trying Olive and we hope you enjoy it! + Terima kasih Anda telah mencoba Olive dan kami harap Anda menyukainya! + + + + Effect + + + Invalid effect + Efek tidak ada + + + + No candidate for effect '%1'. This effect may be corrupt. Try reinstalling it or Olive. + Tidak ada kandidat untuk efek '%1'. Efek mungkin korup. Coba menginstal ulang efek tersebut, atau menginstal ulang Olive. + + + Cu&t + &Potong + + + Move &Up + Pindah ke &Atas + + + Move &Down + Pindah ke &Bawah + + + D&elete + &Hapus + + + Load Settings From File + Buka Pengaturan Efek dari File + + + Save Settings to File + Simpan Pengaturan ke File + + + + Save Effect Settings + Simpan Pengaturan Efek + + + + + Effect XML Settings %1 + Pengaturan XML Efek %1 + + + + Save Settings Failed + Gagal Menyimpan Pengaturan + + + + Failed to open "%1" for writing. + Gagal menulis file "%1" + + + + Load Effect Settings + Buka Pengaturan Efek + + + + + Load Settings Failed + Gagal Membuka Pengaturan + + + + Failed to open "%1" for reading. + considering changing "file" to the defined equivalent "berkas", but it might not be familiar to most people + Gagal membaca file "%1" + + + + This settings file doesn't match this effect. + File pengaturan ini tidak cocok dengan efek yang dipilih. + + + + EffectControls + + &Paste + &Tempel + + + + (none) + (tidak ada) + + + + Effects: + Efek: + + + + Add Video Effect + Masukkan Efek Video + + + + VIDEO EFFECTS + EFEK VIDEO + + + + Add Video Transition + Masukkan Transisi Video + + + + Add Audio Effect + Masukkan Efek Audio + + + + AUDIO EFFECTS + EFEK AUDIO + + + + Add Audio Transition + Masukkan Transisi Audio + + + (Multiple clips selected) + (Beberapa klip terseleksi) + + + + EffectRow + + + Disable Keyframes + Matikan Keyframe + + + + Disabling keyframes will delete all current keyframes. Are you sure you want to do this? + Mematikan keyframe akan menghapus semua keyframe di efek ini. Benarkah Anda ingin melakukan hal tersebut? + + + + EffectUI + + + %1 (Opening) + %1 (Membuka) + + + + %1 (Closing) + %1 (Menutup) + + + + %1 (multiple) + %1 (beberapa) + + + + Cu&t + &Potong + + + + &Copy + &Salin + + + + Move &Up + Pindah ke &Atas + + + + Move &Down + Pindah ke &Bawah + + + + D&elete + &Hapus + + + + Load Settings From File + Buka Pengaturan Efek dari File + + + + Save Settings to File + Simpan Pengaturan ke File + + + + EmbeddedFileChooser + + + File: + + + + + ExportDialog + + + Export "%1" + Ekspor "%1" + + + + Unknown codec name %1 + Kodek %1 tidak diketahui + + + + Export Failed + Gagal Mengekspor + + + + Export failed - %1 + Gagal mengekspor - %1 + + + + Invalid dimensions + Dimensi salah + + + + Export width and height must both be even numbers/divisible by 2. + Lebar dan tinggi video ekspor harus genap/habis dibagi 2. + + + + Invalid codec + Kodek salah + + + + Couldn't determine output parameters for the selected codec. This is a bug, please contact the developers. + Tidak dapat menset pengaturan keluaran/output. Ini merupakan kesalahan, silahkan hubungi pengembang aplikasi. + + + + Invalid format + Format salah + + + + Couldn't determine output format. This is a bug, please contact the developers. + Tidak dapat memilih format keluaran/output. Ini merupakan kutu/bug, silahkan hubungi pengembang aplikasi. + + + + Export Media + Ekspor Media + + + + %p% (Total: %1:%2:%3) + %p% (lama: %1:%2:%3) + + + + %p% (ETA: %1:%2:%3) + %p% (perkiraan: %1:%2:%3) + + + + Quality-based (Constant Rate Factor) + Berbasis kualitas (CRF) + + + + Constant Bitrate + Laju bit konstan (CBR) + + + + + Invalid Codec + Kodek Salah + + + + Failed to find a suitable encoder for this codec. Export will likely fail. + Tidak dapat mencari enkoder yang cocok untuk kodek ini. Ekspor kemungkinan gagal. + + + + Failed to find pixel format for this encoder. Export will likely fail. + Tidak dapat menentukan format piksel untuk enkoder ini. Ekspor kemungkinan gagal. + + + + Bitrate (Mbps): + Laju bit (Mbps): + + + + Quality (CRF): + Kualitas (CRF): + + + + Quality Factor: + +0 = lossless +17-18 = visually lossless (compressed, but unnoticeable) +23 = high quality +51 = lowest quality possible + Faktor kualitas: + +0 = lossless / tidak terkompresi +17-18 = lossless secara visual (masih terkompresi namun tidak terlihat pecah-pecah) +23 = kualitas tinggi +51 = kualitas paling rendah + + + + Target File Size (MB): + Ukuran File yang Ditargetkan (MB): + + + + Format: + + + + + Range: + Sepanjang: + + + + Entire Sequence + Seluruh rangkaian + + + + In to Out + Masuk hingga Keluar + + + + Video + + + + + + Codec: + Kodek: + + + + Width: + Lebar: + + + + Height: + Tinggi: + + + + Frame Rate: + Laju frame (fps): + + + + Compression Type: + Jenis Kompresi: + + + + Advanced + Pengaturan Lanjut + + + + Audio + + + + + Sampling Rate: + Laju sampel: + + + + Bitrate (Kbps/CBR): + Laju bit (Kbps/CBR): + + + + ExportThread + + + failed to send frame to encoder (%1) + gagal mengirim frame ke enkoder (%1) + + + + failed to receive packet from encoder (%1) + gagal menerima paket dari enkoder (%1) + + + + could not video encoder for %1 + tidak dapat mencari enkoder video untuk %1 + + + + could not allocate video stream + tidak dapat mengalokasikan stream video + + + + could not allocate video encoding context + tidak dapat mengalokasikan konteks mengenkode video + + + + could not open output video encoder (%1) + tidak dapat membuka enkoder video keluaran (%1) + + + + could not copy video encoder parameters to output stream (%1) + tidak dapat menyalin parameter enkoder video ke stream keluaran (%1) + + + + could not audio encoder for %1 + tidak dapat mencari enkoder audio untuk %1 + + + + could not allocate audio stream + tidak dapat mengalokasikan stream audio + + + + could not allocate audio encoding context + tidak dapat mengalokasikan konteks mengenkode audio + + + + could not open output audio encoder (%1) + tidak dapat membuka enkoder audio keluaran (%1) + + + + could not copy audio encoder parameters to output stream (%1) + tidak dapat menyalin parameter enkoder audio ke stream keluaran (%1) + + + + could not allocate audio buffer (%1) + tidak dapat mengalokasikan buffer audio (%1) + + + + could not create output format context + tidak dapat membuat konteks format keluaran + + + + could not open output file (%1) + tidak dapat membuka file keluaran (%1) + + + + could not write output file header (%1) + tidak dapat menulis header untuk file keluaran (%1) + + + + could not write output file trailer (%1) + tidak dapat menulis trailer untuk file keluaran (%1) + + + + FillLeftRightEffect + + + Type + Tipe + + + + Fill Left with Right + Penuhi Suara Kiri dengan Kanan + + + + Fill Right with Left + Penuhi Suara Kanan dengan Kiri + + + + Frei0rEffect + + + Failed to load Frei0r plugin "%1": %2 + Gagal membuka plugin Frei0r "%1": %2 + + + NOTE: You can't load 32-bit Frei0r plugins into a 64-bit build of Olive. Please find a 64-bit version of this plugin or switch to a 32-bit build of Olive. + CATATAN: Plugin Frei0r 32-bit tidak dapat dibuka dalam Olive versi 64-bit. Silahkan mencari versi 64-bit dari plugin ini atau instal Olive versi 32-bit. + + + NOTE: You can't load 64-bit Frei0r plugins into a 32-bit build of Olive. Please find a 32-bit version of this plugin or switch to a 64-bit build of Olive. + CATATAN: Plugin Frei0r 64-bit tidak dapat dibuka dalam Olive versi 32-bit. Silahkan mencari versi 32-bit dari plugin ini atau instal Olive versi 64-bit. + + + + Error loading Frei0r plugin + Gagal membuka plugin Frei0r + + + + GraphEditor + + + Graph Editor + Pengedit Grafik + + + + Linear + Linier + + + + Bezier + + + + + Hold + Tahan + + + + GraphView + + + Zoom to Selection + Perbesar ke Seleksi + + + + Zoom to Show All + Perlihatkan Semua + + + + Reset View + Kembalikan Seperti Semula + + + + InterlacingName + + + None (Progressive) + Tidak ada (Progresif) + + + + Top Field First + Utamakan Bidang Atas + + + + Bottom Field First + Utamakan Bidang Bawah + + + + Invalid + Salah + + + + KeyframeNavigator + + + Enable Keyframes + Nyalakan Keyframe + + + + KeyframeView + + + Linear + Linier + + + + Bezier + + + + + Hold + Tahan + + + + LabelSlider + + + &Edit + + + + + &Reset to Default + &Kembalikan seperti Semula + + + + + Set Value + Ubah Jumlah + + + + + New value: + "value" actually would be "harga" or "nilai" but it probably won't fit + Jumlah: + + + + LoadDialog + + + Loading... + Memuat... + + + + Loading '%1'... + Memuat '%1'... + + + + Cancel + Batalkan + + + + LoadThread + + + Version Mismatch + Versi tak Cocok + + + + This project was saved in a different version of Olive and may not be fully compatible with this version. Would you like to attempt loading it anyway? + Proyek ini disimpan menggunakan versi Olive yang lain dan kemungkinan tidak sepenuhnya kompatibel dengan versi ini. Tetap dibuka? + + + + Invalid Clip Link + Tautan Klip Salah + + + + This project contains an invalid clip link. It may be corrupt. Would you like to continue loading it? + Proyek ini terdapat tautan klip yang salah, kemungkinan korup. Tetap memuat? + + + + %1 - Line: %2 Col: %3 + %1 - Baris: %2 Kolom: %3 + + + + User aborted loading + Pengguna membatalkan pemuatan proyek + + + + XML Parsing Error + Gagal Membaca XML + + + + Couldn't load '%1'. %2 + Tidak dapat membaca '%1'. %2 + + + + Project Load Error + Gagal Memuat Proyek + + + + Error loading project: %1 + Gagal memuat proyek: %1 + + + + MainWindow + + + Welcome to %1 + Selamat datang di %1 + + + + &File + + + + + &New + &Baru + + + + &Open Project + Buka &Proyek + + + + Clear Recent List + Hapus Daftar "Terakhir Dibuka" + + + + Open Recent + Buka Terakhir + + + + &Save Project + &Simpan Proyek + + + + Save Project &As + Simpan Proyek Seba&gai + + + + &Import... + &Impor... + + + + &Export... + &Ekspor... + + + + E&xit + &Keluar + + + + &Edit + + + + + &Undo + &Urung + + + + Redo + Ulangi + + + + Select &All + Seleksi &Semua + + + + Deselect All + Batalkan Semua Pilihan + + + + Ripple to In Point + Atur hingga Titik Masuk + + + + Ripple to Out Point + Atur hingga Titik Keluar + + + + Edit to In Point + Edit ke Titik Masuk + + + + Edit to Out Point + Edit ke Titik Keluar + + + + Delete In/Out Point + Hapus Titik Masuk/Keluar + + + + Ripple Delete In/Out Point + Hapus dan Sesuaikan Titik Masuk/Keluar + + + + Set/Edit Marker + Set/Edit Penanda + + + + &View + &Tampilan + + + + Zoom In + Perbesar Tampilan + + + + Zoom Out + Perkecil Tampilan + + + + Increase Track Height + Lebarkan Trek + + + + Decrease Track Height + Persempit Trek + + + + Toggle Show All + "show all" + Perlihatkan Semua + + + + Track Lines + Garis Trek + + + + Rectified Waveforms + "flatten" or "center at bottom" + Visualisasi Audio Rata Bawah + + + + Frames + Frame + + + + Drop Frame + + + + + Non-Drop Frame + + + + + Milliseconds + Milisekon + + + + Title/Action Safe Area + + + + + Off + Matikan + + + + Default + + + + + 4:3 + + + + + 16:9 + + + + + Custom + Kustom + + + + Full Screen + Layar Penuh + + + + Full Screen Viewer + Penampil Layar Penuh + + + + &Playback + &Pemutaran + + + + Go to Start + Lompat ke Awal + + + + Previous Frame + Frame sebelumnya + + + + Play/Pause + Mainkan/Berhenti + + + + Play In to Out + Mainkan dari Titik Masuk hingga Keluar + + + + Next Frame + Frame berikutnya + + + + Go to End + Lompat ke Akhir + + + + Go to Previous Cut + Lompat ke Cut Sebelumnya + + + + Go to Next Cut + Lompat ke Cut Berikutnya + + + + Go to In Point + Lompat ke Titik Masuk + + + + Go to Out Point + Lompat ke Titik Keluar + + + + Shuttle Left + Jalankan ke Kiri + + + + Shuttle Stop + Hentikan jalan + + + + Shuttle Right + Jalankan ke Kanan + + + + Loop + Putar secara Berulang + + + + &Window + &Jendela + + + + Project + Proyek + + + + Effect Controls + Pengaturan Efek + + + + Timeline + Garis Waktu + + + + Graph Editor + Pengedit Grafik + + + + Media Viewer + Penampil Media + + + + Sequence Viewer + Penampil Rangkaian + + + + Maximize Panel + Lebarkan Panel + + + + Lock Panels + Kunci Panel + + + + Reset to Default Layout + Kembalikan Layout Semula + + + + &Tools + &Alat + + + + Pointer Tool + Alat Tunjuk + + + + Edit Tool + Alat Edit + + + + Ripple Tool + Alat Pengatur + + + + Razor Tool + Alat Potong + + + + Slip Tool + Alat Slip + + + + Slide Tool + Alat Geser Klip + + + + Hand Tool + Alat Geser Tampilan + + + + Transition Tool + Alat Transisi + + + + Enable Snapping + Nyalakan Lekatan + + + + Selecting Also Seeks + idk how to translate this + Menyeleksi Juga Menggeser + + + + Edit Tool Also Seeks + Alat Edit Juga Menggeser + + + + Edit Tool Selects Links + Alat Edit Menyeleksi Tautan + + + + Seek Also Selects + Menggeser Juga Menyeleksi + + + + Seek to the End of Pastes + Geser hingga Akhir Tempelan + + + + Scroll Wheel Zooms + Scroll Wheel Memperbesar/Memperkecil Tampilan + + + + Hold CTRL to toggle this setting + Tekan CTRL untuk mengaktifkan pengaturan ini + + + + Invert Timeline Scroll Axes + Balikkan Arah Gulir Garis Waktu + + + + Enable Drag Files to Timeline + Seret dan Lepas file ke Timeline + + + + Auto-Scale By Default + Atur Ukuran Video secara Default + + + + Enable Seek to Import + Nyalakan Geser-untuk-Impor + + + + Audio Scrubbing + Nyalakan Audio Scrubbing + + + + Enable Drop on Media to Replace + Seret pada Media untuk Menggantikan + + + + Enable Hover Focus + Nyalakan Fokus Melayang + + + + Ask For Name When Setting Marker + Tanyakan Nama ketika Menaruh Penanda + + + + No Auto-Scroll + Matikan Gulir Otomatis + + + + Page Auto-Scroll + Gulir Halaman Otomatis + + + + Smooth Auto-Scroll + Gulir Halus Otomatis + + + + Preferences + Preferensi + + + + Clear Undo + Hapus Daftar Urung (Undo) + + + + &Help + &Bantuan + + + + A&ction Search + &Cari Aksi + + + + Debug Log + Awakutu / Debug + + + + &About... + &Tentang... + + + + <untitled> + <belum dinamai> + + + + Marker + + + Set Marker + Masukkan Penanda + + + + Set clip marker name: + Masukkan nama penanda: + + + + Set sequence marker name: + Masukkan nama penanda rangkaian: + + + + Media + + + New Folder + Folder Baru + + + + Name: + Nama: + + + + Filename: + Nama file: + + + + Video Dimensions: + Dimensi Video: + + + + Frame Rate: + Laju frame: + + + + %1 field(s) (%2 frame(s)) + %1 baris (%2 frame) + + + + Interlacing: + Mode interlace: + + + + Audio Frequency: + Frekuensi Audio: + + + + Audio Channels: + Kanal Audio: + + + + Name: %1 +Video Dimensions: %2x%3 +Frame Rate: %4 +Audio Frequency: %5 +Audio Layout: %6 + Nama: %1 +Dimensi Video: %2x%3 +Laju Frame: %4 +Frekuensi Audio: %5 +Tata Audio: %6 + + + + Name + Nama + + + + Duration + Durasi + + + + Rate + Laju + + + + MediaPropertiesDialog + + + "%1" Properties + Properti "%1" + + + + Tracks: + Jumlah trek: + + + + Video %1: %2x%3 %4FPS + + + + + Audio %1: %2Hz %3 + + + + + %n channel(s) + + %n kanal + + + + + Conform to Frame Rate: + Ubah laju frame jadi: + + + + Alpha is Premultiplied + Idk how to translate this either + Alpha dipremultiplikasi + + + + Auto (%1) + + + + + Interlacing: + Mode interlace: + + + + Name: + Nama: + + + + MenuHelper + + + &Project + &Proyek + + + + &Sequence + &Rangkaian + + + + &Folder + + + + + Set In Point + Set Titik Masuk + + + + Set Out Point + Set Titik Keluar + + + + Reset In Point + Kembalikan Titik Masuk + + + + Reset Out Point + Kembalikan Titik Keluar + + + + Clear In/Out Point + Hapus Titik Masuk/Keluar + + + + Add Default Transition + Masukkan Transisi Biasa + + + + Link/Unlink + Tautkan/Lepaskan + + + + Enable/Disable + Nyalakan/Matikan + + + + Nest + Sarangkan + + + + Cu&t + &Potong + + + + Cop&y + &Salin + + + + + &Paste + &Tempel + + + + Paste Insert + Tempel dan Masukkan + + + + Duplicate + Gandakan + + + + Delete + Hapus + + + + Ripple Delete + literally the function of ripple delete: "delete and adjust" + Hapus dan Sesuaikan + + + + Split + Pisahkan + + + + Invalid aspect ratio + Rasio aspek salah + + + + The aspect ratio '%1' is invalid. Please try again. + Rasio aspek '%1' salah. Silahkan coba lagi. + + + + Enter custom aspect ratio + Masukkan rasio aspek kustom + + + + Enter the aspect ratio to use for the title/action safe area (e.g. 16:9): + Masukkan rasio aspek yang ingin dipakai untuk safe area judul/aksi (contohnya 16:9) + + + + NewSequenceDialog + + + Editing "%1" + Mengedit "%1" + + + + New Sequence + Rangkaian Baru + + + + Preset: + + + + + Film 4K + + + + + TV 4K (Ultra HD/2160p) + + + + + 1080p + + + + + 720p + + + + + 480p + + + + + 360p + + + + + 240p + + + + + 144p + + + + + NTSC (480i) + + + + + PAL (576i) + + + + + Custom + Kustom + + + + Video + + + + + Width: + Lebar: + + + + Height: + Tinggi: + + + + Frame Rate: + Laju frame (fps): + + + + Pixel Aspect Ratio: + Rasio aspek piksel: + + + + Square Pixels (1.0) + Persegi (1.0) + + + + Interlacing: + Mode interlace: + + + + None (Progressive) + Tidak ada (Progresif) + + + + Audio + + + + + Sample Rate: + Laju sampel: + + + + Name: + Nama: + + + + OliveGlobal + + + Olive Project %1 + Proyek Olive %1 + + + + Auto-recovery + Auto-pulih + + + + Olive didn't close properly and an autorecovery file was detected. Would you like to open it? + Olive tidak ditutup sebagaimana mestinya, dan ditemukan sebuah file auto-pulih. Buka? + + + + Open Project... + Buka Proyek... + + + + Missing recent project + Proyek Terakhir Tidak Ada + + + + The project '%1' no longer exists. Would you like to remove it from the recent projects list? + Proyek '%1' tidak ada lagi. Hapus dari daftar "proyek terakhir"? + + + + Save Project As... + Simpan Proyek Sebagai... + + + + Unsaved Project + Proyek Belum Disimpan + + + + This project has changed since it was last saved. Would you like to save it before closing? + Proyek ini diubah sejak terakhir disimpan. Simpan sebelum ditutup? + + + + No active sequence + Tidak ada rangkaian aktif + + + + Please open the sequence you wish to export. + Buka dahulu rangkaian/sequence yang ingin diekspor. + + + + Missing Project File + File Proyek Tidak Ada + + + + Specified project '%1' does not exist. + Proyek yang dipilih, '%1', tidak ditemukan. + + + + PanEffect + + + Pan + Geser/Pan + + + + PreferencesDialog + + + Preferences + Preferensi + + + + Invalid CSS File + File CSS Salah + + + + CSS file '%1' does not exist. + Tidak ditemukan file CSS '%1' + + + + Confirm Reset All Shortcuts + Konfirmasi + + + + Are you sure you wish to reset all keyboard shortcuts to their defaults? + Anda ingin mengembalikan semua pintasan keyboard seperti semula. Yakin? + + + + Import Keyboard Shortcuts + Impor Pintasan Keyboard + + + + + Error saving shortcuts + Gagal menyimpan pintasan + + + + Failed to open file for reading + Gagal membuka file + + + + Export Keyboard Shortcuts + Ekspor Pintasan Keyboard + + + + Export Shortcuts + Ekspor Pintasan + + + + Shortcuts exported successfully + Pintasan berhasil diekspor + + + + Failed to open file for writing + Gagal membaca file + + + + Browse for CSS file + Telusuri file CSS + + + + Delete All Previews + Hapus Semua Pratinjau + + + + Are you sure you want to delete all previews? + Yakin menghapus semua pratinjau? + + + + Previews Deleted + Pratinjau Dihapus + + + + All previews deleted succesfully. You may have to re-open your current project for changes to take effect. + Semua pratinjau berhasil dihapus. Anda mungkin perlu membuka proyek kembali. + + + + Language: + Bahasa: + + + + Automatically Seek to the Beginning When Playing at the End of a Sequence + Pindahkan Kursor secara Otomatis ke Awal Ketika Mencapai Akhir Rangkaian + + + + Custom CSS: + CSS Custom: + + + + Browse + Telusur + + + + Image sequence formats: + Format rangkaian gambar: + + + + Audio Recording: + Rekaman Audio: + + + + Mono + + + + + Stereo + Stereo + + + + Effect Textbox Lines: + Baris Teks Efek: + + + + Thumbnail Resolution: + according to kbbi it should be "keluku" but not a lot of people know that + Resolusi Thumbnail: + + + + Waveform Resolution: + Resolusi Waveform: + + + + Delete Previews + Hapus Pratinjau + + + + Use Software Fallbacks When Possible + Gunakan Software Fallback Sebisa Mungkin + + + + Default Sequence Settings + Pengaturan Rangkaian + + + + General + + + + + Behavior + Kelakuan + + + + Add Default Effects to New Clips + Tambahkan Efek-Efek Biasa pada Klip Baru + + + + Appearance + Penampilan + + + + Theme + Tema + + + + Olive Dark (Default) + Gelap (Default) + + + + Olive Light + Terang + + + + Native + Selaras/native + + + + Native (Light Icons) + Selaras (Ikon Terang) + + + + Use Native Menu Styling + Gunakan Gaya Menu Selaras + + + Seeking + "geser" may not be understood well + Tampilan Frame + + + Accurate Seeking +Always show the correct frame (visual may pause briefly as correct frame is retrieved) + Tampilan Akurat +Selalu tampilkan frame yang sebenarnya (dapat terhenti sejenak sembari mencari frame yang benar) + + + Fast Seeking +Seek quickly (may briefly show inaccurate frames when seeking - doesn't affect playback/export) + Tampilan Cepat +Tampilkan frame dengan cepat (dapat menampilkan frame yang salah ketika menggeser kursor di timeline - tidak berpengaruh pada pemutaran/ekspor) + + + + Memory Usage + Pemakaian Memori + + + + Upcoming Frame Queue: + Antri Frame Ke Depan: + + + + + frames + frame + + + + + seconds + detik + + + + Previous Frame Queue: + Antri Frame Ke Belakang: + + + + Playback + Pemutaran + + + + Output Device: + Peranti Output: + + + + + Default + + + + + Input Device: + Peranti Masukan: + + + + Sample Rate: + Laju sampel: + + + + Audio + + + + + Search for action or shortcut + Cari aksi atau pintasan + + + + Action + Aksi + + + + Shortcut + Pintasan + + + + Import + Impor + + + + Export + Ekspor + + + + Reset Selected + Kembalikan Seleksi + + + + Reset All + Kembalikan Semua + + + + Keyboard + + + + + PreviewGenerator + + + Failed to find any valid video/audio streams + Gagal mencari stream video/audio yang benar + + + + Could not open file - %1 + Tidak dapat membuka file - %1 + + + + Could not find stream information - %1 + Tidak dapat mencari informasi stream - %1 + + + + Project + + + Search media, markers, etc. + Cari media, penanda, dll. + + + + Project + Proyek + + + + Sequence + Rangkaian + + + + Replace '%1' + Ganti '%1' + + + + + All Files + Semua file + + + + + No active sequence + Tidak ada rangkaian aktif + + + + No sequence is active, please open the sequence you want to replace clips from. + Tidak ada rangkaian aktif, silahkan buka rangkaian yang akan diganti klipnya. + + + + Active sequence selected + Rangkaian aktif terseleksi + + + + You cannot insert a sequence into itself, so no clips of this media would be in this sequence. + Anda tak dapat memasukkan rangkaian ke dalam rangkaian itu sendiri, jadi tidak ada klip sejenis ini dalam rangkaian. + + + + Rename '%1' + Ganti nama '%1' + + + + Enter new name: + Masukkan nama pengganti: + + + + Delete media in use? + Hapus media yang sedang dipakai? + + + + The media '%1' is currently used in '%2'. Deleting it will remove all instances in the sequence. Are you sure you want to do this? + Media '%1' sedang dipakai dalam '%2'. Menghapus media tersebut akan menghapus semua instans media dalam rangkaian. Yakin akan melakukan hal tersebut? + + + + Skip + Lewati + + + + Import a Project + Impor Proyek + + + + "%1" is an Olive project file. It will merge with this project. Do you wish to continue? + "%1" adalah file proyek Olive. File tersebut akan bergabung dengan proyek ini. Lanjutkan? + + + + Image sequence detected + Rangkaian gambar terdeteksi + + + + The file '%1' appears to be part of an image sequence. Would you like to import it as such? + File '%1' sepertinya merupakan rangkaian gambar. Apakah Anda ingin mengimpornya sebaga rangkaian gambar? + + + + Import media... + Impor media... + + + + No sequence is active, please open the sequence you want to delete clips from. + Tidak ada rangkaian aktif, silahkan buka rangkaian yang Anda ingin hapus klipnya. + + + + ProxyDialog + + + Create Proxy + Buat Proksi + + + + Proxy + Proksi + + + + Dimensions: + Ukuran: + + + + Same Size as Source + Sama dengan Sumber + + + + Half Resolution (1/2) + Resolusi setengah (1/2) + + + + Quarter Resolution (1/4) + Resolusi seperempat (1/4) + + + + Eighth Resolution (1/8) + Resolusi seperdelapan (1/8) + + + + Sixteenth Resolution (1/16) + Resolusi seperenambelas (1/16) + + + + Format: + + + + + ProRes HQ + + + + + Location: + Lokasi: + + + + Same as Source (in "%1" folder) + Sama dengan Sumber (dalam folder "%1") + + + + Proxy file exists + File proksi sudah ada + + + + The file "%1" already exists. Do you wish to replace it? + File "%1" sudah ada. Ganti? + + + + Custom Location + Lokasi Kustom + + + + ProxyGenerator + + + Finished generating proxy for "%1" + Selesai membuat proksi untuk "%1" + + + + ReplaceClipMediaDialog + + + Replace clips using "%1" + Ganti klip dengan "%1" + + + + Select which media you want to replace this media's clips with: + Pilih media pengganti media dari klip: + + + + Keep the same media in-points + Samakan titik masuk media + + + + Replace + Ganti + + + + Cancel + Batalkan + + + + No media selected + Tidak ada media yang dipilih + + + + Please select a media to replace with or click 'Cancel'. + Pilih media pengganti atau klik "Batalkan". + + + + Same media selected + Terpilih media sama + + + + You selected the same media that you're replacing. Please select a different one or click 'Cancel'. + Anda memilih media yang sama dengan yang akan diganti. Silahkan pilih yang lain atau klik "Batalkan". + + + + Folder selected + Folder terpilih + + + + You cannot replace footage with a folder. + Anda tidak dapat mengganti media dengan folder. + + + + Active sequence selected + Rangkaian aktif terseleksi + + + + You cannot insert a sequence into itself. + Anda tidak dapat memasukkan rangkaian pada rangkaian itu sendiri. + + + + RichTextEffect + + + Text + Teks + + + + Padding + Ruang Border + + + + Position + Posisi + + + + Vertical Align: + Rata Vertikal: + + + + Top + Atas + + + + Center + Tengah + + + + Bottom + Bawah + + + + Auto-Scroll + Gulir otomatis + + + + Off + Matikan + + + + Up + Ke atas + + + + Down + Ke bawah + + + + Left + Ke kiri + + + + Right + Ke kanan + + + + Shadow + Bayangan + + + + Shadow Color + Warna Bayangan + + + + Shadow Angle + Arah Bayangan + + + + Shadow Distance + Jarak Bayangan + + + + Shadow Softness + Kehalusan Bayangan + + + + Shadow Opacity + "opacity" is a hard word to find a suitable meaning for + Intensitas Bayangan + + + + Sequence + + + %1 (copy) + %1 (salinan) + + + + ShakeEffect + + + Intensity + Intensitas + + + + Rotation + Rotasi + + + + Frequency + Frekuensi + + + + SolidEffect + + + Type + Tipe + + + + Solid Color + Warna + + + + SMPTE Bars + + + + + Checkerboard + Kotak-Kotak + + + + Opacity + + + + + Color + Warna + + + + Checkerboard Size + Ukuran Kotak-Kotak + + + + SourcesCommon + + + Import... + Impor... + + + + New + Baru + + + + View + Tampilan + + + + Tree View + Tampilan Pohon + + + + Icon View + Tampilan Ikon + + + + Show Toolbar + Tampilkan Toolbar + + + + Show Sequences + Tampilkan Rangkaian + + + + Replace/Relink Media + Ganti/Taut Media + + + + Reveal in Explorer + Buka di Explorer + + + + Reveal in Finder + Buka di Finder + + + + Reveal in File Manager + Buka di Manajer Berkas + + + + Replace Clips Using This Media + Ganti Klip dengan Media Ini + + + + Create Sequence With This Media + Buat Rangkaian dengan Media Ini + + + + Duplicate + Gandakan + + + + Delete All Clips Using This Media + Hapus Semua Klip yang Menggunakan Media Ini + + + + Proxy + Proksi + + + + Generating proxy: %1% complete + Membuat proksi: %1% + + + + Create/Modify Proxy + Buat/Ubah Proksi + + + + Create Proxy + Buat Proksi + + + + Modify Proxy + Ubah Proksi + + + + Restore Original + Kembalikan Seperti Semula + + + + Delete + Hapus + + + + Preview in Media Viewer + Pratayang di Penampil Media + + + + Properties... + Properti... + + + + Replace Media + Ganti Media + + + + You dropped a file onto '%1'. Would you like to replace it with the dropped file? + Anda menjatuhkan file ke '%1'. Ganti klip dengan file tersebut? + + + + Delete proxy + Hapus proksi + + + + Would you like to delete the proxy file "%1" as well? + Hapus file proksi "%1" juga? + + + + SpeedDialog + + + Speed/Duration + Kecepatan/Durasi + + + + Speed: + Kecepatan: + + + + Frame Rate: + Laju frame (fps): + + + + Duration: + Durasi: + + + + Reverse + Terbalik + + + + Maintain Audio Pitch + Tahan Pitch + + + + Ripple Changes + + + + + TextEditDialog + + + Edit Text + Edit Teks + + + + Thin + + + + + Extra Light + + + + + Light + + + + + Normal + + + + + Medium + + + + + Demi Bold + + + + + Bold + + + + + Extra Bold + + + + + Black + + + + + TextEditEx + + + Edit Text + Edit Teks + + + + &Edit Text + &Edit Teks + + + + TextEffect + + + Text + Teks + + + + Font + Fon + + + + Size + Ukuran + + + + Color + Warna + + + + Alignment + Rata + + + + Left + Kiri + + + + + Center + Tengah + + + + Right + Kanan + + + + Justify + Kanan-Kiri + + + + Top + Atas + + + + Bottom + Bawah + + + + Word Wrap + "bungkus kata" is also possible but feels weird + Sesuaikan Lebar Kata + + + + Padding + Ruang Border + + + + Position + Posisi + + + + Outline + Garis Teks + + + + Outline Color + Warna Garis + + + + Outline Width + Ketebalan Garis + + + + Shadow + Bayangan + + + + Shadow Color + Warna Bayangan + + + + Shadow Angle + Arah Bayangan + + + + Shadow Distance + Jarak Bayangan + + + + Shadow Softness + Kehalusan Bayangan + + + + Shadow Opacity + Intensitas Bayangan + + + + Sample Text + Masukkan teks disini + + + + TimecodeEffect + + + Timecode + Kode Waktu + + + + Sequence + Rangkaian + + + + Media + + + + + Scale + Ukuran + + + + Color + Warna + + + + Background Color + Warna Latar + + + + Background Opacity + Transparansi Latar + + + + Offset + + + + + Prepend + Teks Sebelum + + + + Timeline + + + Pointer Tool + Alat Tunjuk + + + + Edit Tool + Alat Edit + + + + Ripple Tool + Alat Pengatur + + + + Razor Tool + Alat Potong + + + + Slip Tool + Alat Slip + + + + Slide Tool + Alat Geser Klip + + + + Hand Tool + Alat Geser Tampilan + + + + Transition Tool + Alat Transisi + + + + Snapping + Lekatan + + + + Zoom In + Perbesar Tampilan + + + + Zoom Out + Perkecil Tampilan + + + + Record audio + Rekam suara + + + + Add title, solid, bars, etc. + Masukkan judul, warna, bars, dll. + + + + Nested Sequence + Rangkaian Bersarang + + + + Effect already exists + Efek sudah ada + + + + Clip '%1' already contains a '%2' effect. Would you like to replace it with the pasted one or add it as a separate effect? + Klip '%1' sudah memiliki efek '%2'. Ganti dengan yang akan ditempel atau tambahkan sebagai efek sendiri? + + + + Add + Tambah + + + + Replace + Ganti + + + + Skip + Lewati + + + + Do this for all conflicts found + Lakukan untuk semua konflik yang ditemukan + + + + Title... + Judul... + + + + Solid Color... + Warna... + + + + Bars... + + + + + Tone... + Nada... + + + + Noise... + + + + + Unsaved Project + Proyek Belum Disimpan + + + + You must save this project before you can record audio in it. + Proyek ini harus disimpan sebelum merekam suara. + + + + Click on the timeline where you want to start recording (drag to limit the recording to a certain timeframe) + Klik tempat dimana Anda akan mulai merekam (seret untuk membatasi rekaman dalam waktu tertentu) + + + + Timeline: + Garis Waktu: + + + + (none) + (tidak ada) + + + + TimelineHeader + + + Center Timecodes + Ratakan Kode Waktu + + + + TimelineWidget + + + &Undo + "takjadi" and "batalkan" are also possible translations + &Urung + + + + &Redo + "kembalikan" is also possible + &Ulangi + + + &Paste + &Tempel + + + + R&ipple Delete Empty Space + Hapus dan Sesuaikan Ruang Kosong + + + + Sequence Settings + Pengaturan Rangkaian + + + + &Speed/Duration + &Kecepatan/Durasi + + + + Auto-s&cale + Per&besar otomatis + + + + &Reveal in Project + &Buka di Proyek + + + + Properties + Properti + + + + %1 +Start: %2 +End: %3 +Duration: %4 + %1 +Mulai: %2 +Akhir: %3 +Durasi: %4 + + + + Error + + + + + Couldn't locate media wrapper for sequence. + + + + + Title + Judul + + + + Solid Color + Warna + + + + Bars + + + + + Tone + Nada + + + + Noise + Kebisingan/Noise + + + + Duration: + Durasi: + + + + ToneEffect + + + Type + Tipe + + + + Sine + Sinus + + + + Frequency + Frekuensi + + + + Amount + Kenyaringan + + + + Mix + + + + + TransformEffect + + + Position + Posisi + + + + Scale + Ukuran + + + + Uniform Scale + Ukuran Merata + + + + Rotation + Rotasi + + + + Anchor Point + Titik Poros + + + + Opacity + + + + + Blend Mode + Mode Penggabungan + + + + Normal + + + + + Transition + + + Length + Panjang + + + + UpdateNotification + + + An update is available from the Olive website. Visit www.olivevideoeditor.org to download it. + Pembaruan aplikasi telah tersedia. Silahkan kunjungi www.olivevideoeditor.org untuk mengunduhnya. + + + + VSTHost + + + + Error loading VST plugin + Gagal membuka plugin VST + + + + Failed to load VST plugin "%1": %2 + Gagal membuka plugin VST "%1": %2 + + + + Failed to locate entry point for dynamic library. + Gagal mencari titik masuk untuk pustaka dinamis (dynamic library) + + + + VST Error + Galat VST + + + + Plugin's magic number is invalid + Identifikasi plugin salah + + + + Plugin + + + + + Interface + Antarmuka + + + + Show + Tampilkan + + + + VST Plugin + Plugin VST + + + + Viewer + + + Sequence Viewer + Tampilan Rangkaian + + + + Media Viewer + Tampilan Media + + + + (none) + (tidak ada) + + + + Drag video only + Tarik video saja + + + + Drag audio only + Tarik audio saja + + + + ViewerWidget + + + Save Frame as Image... + Simpan Frame sebagai Gambar... + + + + Show Fullscreen + Tampilkan Layar Penuh + + + + Disable + Matikan + + + + Screen %1: %2x%3 + Layar %1: %2x%3 + + + + Zoom + Pembesaran + + + + Fit + Pas + + + + Custom + Kustom + + + + Close Media + Tutup Media + + + + Save Frame + Simpan Frame + + + + Viewer Zoom + Pembesaran Tampilan + + + + Set Custom Zoom Value: + Masukkan pembesaran kustom: + + + + ViewerWindow + + + Exit Fullscreen + Keluar dari Layar Penuh + + + + VoidEffect + + + (unknown) + (tidak diketahui) + + + + Missing Effect + Efek Hilang + + + + VolumeEffect + + + Volume + + + + + transition + + + Invalid transition + Transisi salah + + + + No candidate for transition '%1'. This transition may be corrupt. Try reinstalling it or Olive. + Tidak ada kandidat untuk efek '%1'. Efek mungkin korup. Coba menginstal ulang efek tersebut, atau menginstal ulang Olive. + + + From f1bb9f5b06cc2ef86076630fe90b7eb361c2c92b Mon Sep 17 00:00:00 2001 From: ZoomTen Date: Sat, 23 Mar 2019 17:32:07 +0700 Subject: [PATCH 20/35] modifed olive.pro just in case --- olive.pro | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/olive.pro b/olive.pro index 5e338de17..2b4b15559 100644 --- a/olive.pro +++ b/olive.pro @@ -316,7 +316,8 @@ TRANSLATIONS += \ ts/olive_ru.ts \ ts/olive_uk.ts \ ts/olive_bs.ts \ - ts/olive_sr.ts + ts/olive_sr.ts \ + ts/olive_id.ts win32 { RC_FILE = packaging/windows/resources.rc From ad44b00eb390e0c88fa93bc085aaf58c482b0f71 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sun, 24 Mar 2019 12:02:59 +1100 Subject: [PATCH 21/35] fixed keyframe UI issue when disabling keyframes --- effects/effectrow.cpp | 6 ------ ui/sourceiconview.cpp | 9 ++++----- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/effects/effectrow.cpp b/effects/effectrow.cpp index 06b998d66..912d25ad2 100644 --- a/effects/effectrow.cpp +++ b/effects/effectrow.cpp @@ -60,11 +60,6 @@ bool EffectRow::IsKeyframing() { } void EffectRow::SetKeyframingInternal(bool b) { - // No need to run this function if the keyframing state isn't actually changing. - if (b == keyframing_) { - return; - } - if (GetParentEffect()->meta->type != EFFECT_TYPE_TRANSITION) { keyframing_ = b; emit KeyframingSetChanged(keyframing_); @@ -127,7 +122,6 @@ void EffectRow::SetKeyframingEnabled(bool enabled) { } else { - SetKeyframingInternal(true); } diff --git a/ui/sourceiconview.cpp b/ui/sourceiconview.cpp index 4916a653a..3ed554c4c 100644 --- a/ui/sourceiconview.cpp +++ b/ui/sourceiconview.cpp @@ -76,16 +76,15 @@ void SourceIconView::dropEvent(QDropEvent* event) { } void SourceIconView::mouseDoubleClickEvent(QMouseEvent *) { - bool default_behavior = true; if (selectedIndexes().size() == 1) { Media* m = project_parent->item_to_media(selectedIndexes().at(0)); if (m->get_type() == MEDIA_TYPE_FOLDER) { - default_behavior = false; setRootIndex(selectedIndexes().at(0)); emit changed_root(); + return; } } - if (default_behavior) { - commons_.mouseDoubleClickEvent(selectedIndexes()); - } + + // Double click was not a folder, so we perform the default behavior (sending the double click to SourcesCommon) + commons_.mouseDoubleClickEvent(selectedIndexes()); } From be01bdd6f901bb88c37adcf5026f9c378456dc72 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sun, 24 Mar 2019 18:44:03 +1100 Subject: [PATCH 22/35] use qt's OS macros --- effects/effectloaders.cpp | 2 +- effects/internal/vsthost.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/effects/effectloaders.cpp b/effects/effectloaders.cpp index fd012a227..83fdc5b64 100644 --- a/effects/effectloaders.cpp +++ b/effects/effectloaders.cpp @@ -246,7 +246,7 @@ void load_frei0r_effects() { QList effect_dirs = get_effects_paths(); // add defined paths for frei0r plugins on unix -#if defined(__APPLE__) || defined(__linux__) || defined(__HAIKU__) +#if defined(Q_OS_MACOS) || defined(Q_OS_LINUX) || defined(__HAIKU__) effect_dirs.prepend("/usr/lib/frei0r-1"); effect_dirs.prepend("/usr/local/lib/frei0r-1"); effect_dirs.prepend(QDir::homePath() + "/.frei0r-1/lib"); diff --git a/effects/internal/vsthost.cpp b/effects/internal/vsthost.cpp index 09ed8b593..2958832f1 100644 --- a/effects/internal/vsthost.cpp +++ b/effects/internal/vsthost.cpp @@ -36,12 +36,12 @@ // Load libraries for retrieving the native window handle. Used for VST plugins that have a separate window // dedicated to controls. -#if defined(_WIN32) +#if defined(Q_OS_WIN) #include -#elif defined(__APPLE__) +#elif defined(Q_OS_MACOS) #include class NSWindow; -#elif defined(__linux__) +#elif defined(Q_OS_LINUX) #include #endif @@ -337,11 +337,11 @@ void VSTHost::show_interface(bool show) { dialog->setVisible(show); if (show) { -#if defined(_WIN32) +#if defined(Q_OS_WIN) dispatcher(plugin, effEditOpen, 0, 0, reinterpret_cast(dialog->windowHandle()->winId()), 0); -#elif defined(__APPLE__) +#elif defined(Q_OS_MACOS) dispatcher(plugin, effEditOpen, 0, 0, reinterpret_cast(dialog->windowHandle()->winId()), 0); -#elif defined(__linux__) || defined(__HAIKU__) +#elif defined(Q_OS_LINUX) || defined(__HAIKU__) dispatcher(plugin, effEditOpen, 0, 0, reinterpret_cast(dialog->windowHandle()->winId()), 0); #endif } else { From 54518a5896efc9c9c4477a0e6ae4724d6e9e20fc Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sun, 24 Mar 2019 22:34:34 +1100 Subject: [PATCH 23/35] custom style delegate for icon view --- global/config.h | 5 +- global/math.cpp | 67 ++- global/math.h | 4 + icons/icons.qrc | 1 + icons/listview.svg | 829 +++++++++++++++++++++++++++++++++++ panels/project.cpp | 52 ++- panels/project.h | 2 + project/footage.cpp | 14 - project/footage.h | 2 - project/media.cpp | 39 +- project/media.h | 2 + project/previewgenerator.cpp | 4 - project/sourcescommon.h | 3 +- ui/sourceiconview.cpp | 125 ++++++ ui/sourceiconview.h | 10 + 15 files changed, 1085 insertions(+), 74 deletions(-) create mode 100644 icons/listview.svg diff --git a/global/config.h b/global/config.h index 968e4a8c3..c72b52077 100644 --- a/global/config.h +++ b/global/config.h @@ -120,7 +120,10 @@ namespace olive { PROJECT_VIEW_TREE, /** Display project media in icon browser */ - PROJECT_VIEW_ICON + PROJECT_VIEW_ICON, + + /** Display project media in list browser */ + PROJECT_VIEW_LIST }; /** diff --git a/global/math.cpp b/global/math.cpp index 31c630d01..fe19b229b 100644 --- a/global/math.cpp +++ b/global/math.cpp @@ -26,57 +26,76 @@ #include "debug.h" int lerp(int a, int b, double t) { - return qRound(((1.0 - t) * a) + (t * b)); + return qRound(((1.0 - t) * a) + (t * b)); } float float_lerp(float a, float b, float t) { - return ((1.0F - t) * a) + (t * b); + return ((1.0F - t) * a) + (t * b); } double double_lerp(double a, double b, double t) { - return ((1.0 - t) * a) + (t * b); + return ((1.0 - t) * a) + (t * b); } double quad_from_t(double a, double b, double c, double t) { - return qPow(1.0 - t, 2)*a + 2*(1.0 - t)*t*b + qPow(t, 2)*c; + return qPow(1.0 - t, 2)*a + 2*(1.0 - t)*t*b + qPow(t, 2)*c; } double quad_t_from_x(double x, double a, double b, double c) { - return (a - b + qSqrt(a*x + c*x - 2*b*x + qPow(b, 2) - a*c))/(a - 2*b + c); - // alt: return (a - b - qSqrt(a*x + c*x - 2*b*x + qPow(b, 2) - a*c))/(a - 2*b + c); + return (a - b + qSqrt(a*x + c*x - 2*b*x + qPow(b, 2) - a*c))/(a - 2*b + c); + // alt: return (a - b - qSqrt(a*x + c*x - 2*b*x + qPow(b, 2) - a*c))/(a - 2*b + c); } double cubic_from_t(double a, double b, double c, double d, double t) { - return qPow(1.0 - t, 3)*a + 3*qPow(1.0 - t, 2)*t*b + 3*(1.0 - t)*qPow(t, 2)*c + qPow(t, 3)*d; + return qPow(1.0 - t, 3)*a + 3*qPow(1.0 - t, 2)*t*b + 3*(1.0 - t)*qPow(t, 2)*c + qPow(t, 3)*d; } double cubic_t_from_x(double x_target, double a, double b, double c, double d) { - double tolerance = 0.0001; + double tolerance = 0.0001; - double lower = 0.0; - double upper = 1.0; + double lower = 0.0; + double upper = 1.0; - double percent = 0.5; - double x = cubic_from_t(a, b, c, d, percent); + double percent = 0.5; + double x = cubic_from_t(a, b, c, d, percent); - while (qAbs(x_target - x) > tolerance) { - if (x_target > x) { - lower = percent; - } else { - upper = percent; - } + while (qAbs(x_target - x) > tolerance) { + if (x_target > x) { + lower = percent; + } else { + upper = percent; + } - percent = (upper + lower) / 2.0; - x = cubic_from_t(a, b, c, d, percent); - } + percent = (upper + lower) / 2.0; + x = cubic_from_t(a, b, c, d, percent); + } - return percent; + return percent; } double amplitude_to_db(double amplitude) { - return (20.0*(qLn(amplitude)/qLn(10.0))); + return (20.0*(qLn(amplitude)/qLn(10.0))); } double db_to_amplitude(double db) { - return qPow(M_E, (db*qLn(10.0))/20.0); + return qPow(M_E, (db*qLn(10.0))/20.0); +} + +QRect fit_size_into_rect(const QRect &r, int width, int height) +{ + // Get aspect ratio of object we're fitting + double inner_ar = double(width) / double(height); + + // Get aspect ratio of rectangle + double rect_ar = double(r.width()) / double(r.height()); + + if (rect_ar > inner_ar) { + // The rect is wider than the object, so we'll be limiting by height and scaling by width + int new_width = qRound(r.height() * inner_ar); + return QRect(r.x() + (r.width() / 2 - new_width / 2), r.y(), new_width, r.height()); + } else { + // The rect is taller than the object, so we'll be limiting by width and scaling by height + int new_height = qRound(r.width() / inner_ar); + return QRect(r.x(), r.y() + (r.height() / 2 - new_height / 2), r.width(), new_height); + } } diff --git a/global/math.h b/global/math.h index 9e6a7a45a..ed71f3981 100644 --- a/global/math.h +++ b/global/math.h @@ -21,6 +21,8 @@ #ifndef MATH_H #define MATH_H +#include + int lerp(int a, int b, double t); float float_lerp(float a, float b, float t); double double_lerp(double a, double b, double t); @@ -30,6 +32,8 @@ 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); +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); diff --git a/icons/icons.qrc b/icons/icons.qrc index 8d00cf945..341bbf1b1 100644 --- a/icons/icons.qrc +++ b/icons/icons.qrc @@ -52,5 +52,6 @@ align-right.svg justify-center.svg bold.svg + listview.svg diff --git a/icons/listview.svg b/icons/listview.svg new file mode 100644 index 000000000..062cebc39 --- /dev/null +++ b/icons/listview.svg @@ -0,0 +1,829 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Martin Ruskov + + + http://commons.wikimedia.org/wiki/Tango_icon + + + + + + + + + + + + + + + + + + diff --git a/panels/project.cpp b/panels/project.cpp index 93e5005b3..fb609a114 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -103,31 +103,31 @@ Project::Project(QWidget *parent) : QPushButton* toolbar_new = new QPushButton(); toolbar_new->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/add-button.svg"))); - toolbar_new->setToolTip("New"); + toolbar_new->setToolTip(tr("New")); connect(toolbar_new, SIGNAL(clicked(bool)), this, SLOT(make_new_menu())); toolbar->addWidget(toolbar_new); QPushButton* toolbar_open = new QPushButton(); toolbar_open->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/open.svg"))); - toolbar_open->setToolTip("Open Project"); + toolbar_open->setToolTip(tr("Open Project")); connect(toolbar_open, SIGNAL(clicked(bool)), olive::Global.get(), SLOT(OpenProject())); toolbar->addWidget(toolbar_open); QPushButton* toolbar_save = new QPushButton(); toolbar_save->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/save.svg"))); - toolbar_save->setToolTip("Save Project"); + toolbar_save->setToolTip(tr("Save Project")); connect(toolbar_save, SIGNAL(clicked(bool)), olive::Global.get(), SLOT(save_project())); toolbar->addWidget(toolbar_save); QPushButton* toolbar_undo = new QPushButton(); toolbar_undo->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/undo.svg"))); - toolbar_undo->setToolTip("Undo"); + toolbar_undo->setToolTip(tr("Undo")); connect(toolbar_undo, SIGNAL(clicked(bool)), olive::Global.get(), SLOT(undo())); toolbar->addWidget(toolbar_undo); QPushButton* toolbar_redo = new QPushButton(); toolbar_redo->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/redo.svg"))); - toolbar_redo->setToolTip("Redo"); + toolbar_redo->setToolTip(tr("Redo")); connect(toolbar_redo, SIGNAL(clicked(bool)), olive::Global.get(), SLOT(redo())); toolbar->addWidget(toolbar_redo); @@ -138,16 +138,22 @@ Project::Project(QWidget *parent) : QPushButton* toolbar_tree_view = new QPushButton(); toolbar_tree_view->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/treeview.svg"))); - toolbar_tree_view->setToolTip("Tree View"); + toolbar_tree_view->setToolTip(tr("Tree View")); connect(toolbar_tree_view, SIGNAL(clicked(bool)), this, SLOT(set_tree_view())); toolbar->addWidget(toolbar_tree_view); QPushButton* toolbar_icon_view = new QPushButton(); toolbar_icon_view->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/iconview.svg"))); - toolbar_icon_view->setToolTip("Icon View"); + toolbar_icon_view->setToolTip(tr("Icon View")); connect(toolbar_icon_view, SIGNAL(clicked(bool)), this, SLOT(set_icon_view())); toolbar->addWidget(toolbar_icon_view); + QPushButton* toolbar_list_view = new QPushButton(); + toolbar_list_view->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/listview.svg"))); + toolbar_list_view->setToolTip(tr("List View")); + connect(toolbar_list_view, SIGNAL(clicked(bool)), this, SLOT(set_list_view())); + toolbar->addWidget(toolbar_list_view); + verticalLayout->addWidget(toolbar_widget); // tree view @@ -180,9 +186,9 @@ Project::Project(QWidget *parent) : icon_view_controls->addStretch(); - QSlider* icon_size_slider = new QSlider(Qt::Horizontal); + icon_size_slider = new QSlider(Qt::Horizontal); icon_size_slider->setMinimum(16); - icon_size_slider->setMaximum(120); + icon_size_slider->setMaximum(256); icon_view_controls->addWidget(icon_size_slider); connect(icon_size_slider, SIGNAL(valueChanged(int)), this, SLOT(set_icon_view_size(int))); @@ -191,12 +197,12 @@ Project::Project(QWidget *parent) : icon_view = new SourceIconView(sources_common); icon_view->project_parent = this; icon_view->setModel(&sorter); - icon_view->setIconSize(QSize(100, 100)); + icon_view->setGridSize(QSize(100, 100)); icon_view->setViewMode(QListView::IconMode); icon_view->setUniformItemSizes(true); icon_view_container_layout->addWidget(icon_view); - icon_size_slider->setValue(icon_view->iconSize().height()); + icon_size_slider->setValue(icon_view->gridSize().height()); verticalLayout->addWidget(icon_view_container); @@ -1322,13 +1328,22 @@ void Project::save_project(bool autorecovery) { void Project::update_view_type() { tree_view->setVisible(olive::CurrentConfig.project_view_type == olive::PROJECT_VIEW_TREE); - icon_view_container->setVisible(olive::CurrentConfig.project_view_type == olive::PROJECT_VIEW_ICON); + icon_view_container->setVisible(olive::CurrentConfig.project_view_type == olive::PROJECT_VIEW_ICON + || olive::CurrentConfig.project_view_type == olive::PROJECT_VIEW_LIST); + switch (olive::CurrentConfig.project_view_type) { case olive::PROJECT_VIEW_TREE: sources_common.view = tree_view; break; case olive::PROJECT_VIEW_ICON: + case olive::PROJECT_VIEW_LIST: + icon_view->setViewMode(olive::CurrentConfig.project_view_type == olive::PROJECT_VIEW_ICON ? + QListView::IconMode : QListView::ListMode); + + // update list/grid size since they use this value slightly differently + set_icon_view_size(icon_size_slider->value()); + sources_common.view = icon_view; break; } @@ -1339,6 +1354,12 @@ void Project::set_icon_view() { update_view_type(); } +void Project::set_list_view() +{ + olive::CurrentConfig.project_view_type = olive::PROJECT_VIEW_LIST; + update_view_type(); +} + void Project::set_tree_view() { olive::CurrentConfig.project_view_type = olive::PROJECT_VIEW_TREE; update_view_type(); @@ -1367,7 +1388,12 @@ void Project::clear_recent_projects() { } void Project::set_icon_view_size(int s) { - icon_view->setIconSize(QSize(s, s)); + if (icon_view->viewMode() == QListView::IconMode) { + icon_view->setGridSize(QSize(s, s)); + } else { + icon_view->setGridSize(QSize()); + icon_view->setIconSize(QSize(s, s)); + } } void Project::set_up_dir_enabled() { diff --git a/panels/project.h b/panels/project.h index 4cf77fe95..e3dfbf3bf 100644 --- a/panels/project.h +++ b/panels/project.h @@ -112,6 +112,7 @@ private: QString get_file_name_from_path(const QString &path); QDir proj_dir; QWidget* icon_view_container; + QSlider* icon_size_slider; QPushButton* directory_up; QLineEdit* toolbar_search; @@ -124,6 +125,7 @@ private: private slots: void update_view_type(); void set_icon_view(); + void set_list_view(); void set_tree_view(); void clear_recent_projects(); void set_icon_view_size(int); diff --git a/project/footage.cpp b/project/footage.cpp index bde8c4c20..7ac98617a 100644 --- a/project/footage.cpp +++ b/project/footage.cpp @@ -77,17 +77,3 @@ FootageStream* Footage::get_stream_from_file_index(bool video, int index) { } return nullptr; } - -void FootageStream::make_square_thumb() { - // generate square version for QListView? - int square_size = qMax(video_preview.width(), video_preview.height()); - QPixmap pixmap(square_size, square_size); - pixmap.fill(Qt::transparent); - QPainter p(&pixmap); - int diff = (video_preview.width() - video_preview.height())>>1; - int sqx = (diff < 0) ? -diff : 0; - int sqy = (diff > 0) ? diff : 0; - p.drawImage(sqx, sqy, video_preview); - p.end(); - video_preview_square = QIcon(pixmap); -} diff --git a/project/footage.h b/project/footage.h index 04ff51706..a6f45d8ac 100644 --- a/project/footage.h +++ b/project/footage.h @@ -62,9 +62,7 @@ struct FootageStream { // preview thumbnail/waveform bool preview_done; QImage video_preview; - QIcon video_preview_square; QVector audio_preview; - void make_square_thumb(); }; struct Footage { diff --git a/project/media.cpp b/project/media.cpp index 70d0cb35c..cde487055 100644 --- a/project/media.cpp +++ b/project/media.cpp @@ -284,6 +284,24 @@ int Media::columnCount() const { return 3; } +QString Media::GetStringDuration() { + if (get_type() == MEDIA_TYPE_SEQUENCE) { + Sequence* s = to_sequence().get(); + return frame_to_timecode(s->getEndFrame(), olive::CurrentConfig.timecode_view, s->frame_rate); + } + if (get_type() == MEDIA_TYPE_FOOTAGE) { + Footage* f = to_footage(); + double r = 30; + + if (f->video_tracks.size() > 0 && !qIsNull(f->video_tracks.at(0).video_frame_rate)) + r = f->video_tracks.at(0).video_frame_rate * f->speed; + + long len = f->get_length_in_frames(r); + if (len > 0) return frame_to_timecode(len, olive::CurrentConfig.timecode_view, r); + } + return QString(); +} + QVariant Media::data(int column, int role) { switch (role) { case Qt::DecorationRole: @@ -292,7 +310,7 @@ QVariant Media::data(int column, int role) { Footage* f = to_footage(); if (f->video_tracks.size() > 0 && f->video_tracks.at(0).preview_done) { - return f->video_tracks.at(0).video_preview_square; + return QIcon(QPixmap::fromImage(f->video_tracks.at(0).video_preview)); } } @@ -304,20 +322,7 @@ QVariant Media::data(int column, int role) { case 0: return (root) ? QCoreApplication::translate("Media", "Name") : get_name(); case 1: if (root) return QCoreApplication::translate("Media", "Duration"); - if (get_type() == MEDIA_TYPE_SEQUENCE) { - Sequence* s = to_sequence().get(); - return frame_to_timecode(s->getEndFrame(), olive::CurrentConfig.timecode_view, s->frame_rate); - } - if (get_type() == MEDIA_TYPE_FOOTAGE) { - Footage* f = to_footage(); - double r = 30; - - if (f->video_tracks.size() > 0 && !qIsNull(f->video_tracks.at(0).video_frame_rate)) - r = f->video_tracks.at(0).video_frame_rate * f->speed; - - long len = f->get_length_in_frames(r); - if (len > 0) return frame_to_timecode(len, olive::CurrentConfig.timecode_view, r); - } + return GetStringDuration(); break; case 2: if (root) return QCoreApplication::translate("Media", "Rate"); @@ -336,6 +341,10 @@ QVariant Media::data(int column, int role) { break; case Qt::ToolTipRole: return tooltip; + + case Qt::UserRole: + // User role returns the duration + return GetStringDuration(); } return QVariant(); } diff --git a/project/media.h b/project/media.h index 05d60bfe4..2daff6aaf 100644 --- a/project/media.h +++ b/project/media.h @@ -87,6 +87,8 @@ private: int type; VoidPtr object; + QString GetStringDuration(); + // item functions QList children; Media* parent; diff --git a/project/previewgenerator.cpp b/project/previewgenerator.cpp index 3597e744b..f14fe8ddf 100644 --- a/project/previewgenerator.cpp +++ b/project/previewgenerator.cpp @@ -153,8 +153,6 @@ bool PreviewGenerator::retrieve_preview(const QString& hash) { QString thumb_path = get_thumbnail_path(hash, ms); QFile f(thumb_path); if (f.exists() && ms.video_preview.load(thumb_path)) { - //dout << "loaded thumb" << ms->file_index << "from" << thumb_path; - ms.make_square_thumb(); ms.preview_done = true; } else { found = false; @@ -364,8 +362,6 @@ void PreviewGenerator::generate_waveform() { &data, linesize); - s->make_square_thumb(); - // is video interlaced? s->video_auto_interlacing = (temp_frame->interlaced_frame) ? ((temp_frame->top_field_first) ? VIDEO_TOP_FIELD_FIRST : VIDEO_BOTTOM_FIELD_FIRST) : VIDEO_PROGRESSIVE; s->video_interlacing = s->video_auto_interlacing; diff --git a/project/sourcescommon.h b/project/sourcescommon.h index 506610ebc..b710f552a 100644 --- a/project/sourcescommon.h +++ b/project/sourcescommon.h @@ -46,6 +46,8 @@ public: void dropEvent(QWidget *parent, QDropEvent* e, const QModelIndex& drop_item, const QModelIndexList &items); void item_click(Media* m, const QModelIndex &index); +public slots: + void stop_rename_timer(); private slots: void create_seq_from_selected(); void reveal_in_browser(); @@ -62,7 +64,6 @@ private: QModelIndex editing_index; QModelIndexList selected_items; Project* project_parent; - void stop_rename_timer(); QTimer rename_timer; // we cache the selected footage items for open_create_proxy_dialog() diff --git a/ui/sourceiconview.cpp b/ui/sourceiconview.cpp index 3ed554c4c..e8fbf0fbd 100644 --- a/ui/sourceiconview.cpp +++ b/ui/sourceiconview.cpp @@ -21,18 +21,22 @@ #include "sourceiconview.h" #include +#include #include "panels/project.h" #include "project/media.h" #include "project/sourcescommon.h" #include "global/debug.h" +#include "global/math.h" SourceIconView::SourceIconView(SourcesCommon &commons) : commons_(commons) { + setMovement(QListView::Free); setSelectionMode(QAbstractItemView::ExtendedSelection); setResizeMode(QListView::Adjust); setContextMenuPolicy(Qt::CustomContextMenu); + setItemDelegate(&delegate_); connect(this, SIGNAL(clicked(const QModelIndex&)), this, SLOT(item_click(const QModelIndex&))); connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu())); } @@ -88,3 +92,124 @@ void SourceIconView::mouseDoubleClickEvent(QMouseEvent *) { // Double click was not a folder, so we perform the default behavior (sending the double click to SourcesCommon) commons_.mouseDoubleClickEvent(selectedIndexes()); } + +SourceIconDelegate::SourceIconDelegate(QObject *parent) : + QStyledItemDelegate (parent) +{ +} + +QSize SourceIconDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + if (option.decorationPosition == QStyleOptionViewItem::Top) { // Icon Mode + + return QSize(256, 256); + + } else { + + return QSize(option.decorationSize.height(), option.decorationSize.height()); + + } +} + +void SourceIconDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + QFontMetrics fm = painter->fontMetrics(); + QRect img_rect = option.rect; + + if (option.decorationPosition == QStyleOptionViewItem::Top) { // Icon Mode + + // Draw Text + if (fm.height() < option.rect.height() / 2) { + img_rect.setHeight(img_rect.height()-fm.height()); + + QRect text_rect = option.rect; + text_rect.setTop(text_rect.top() + option.rect.height() - fm.height()); + + QColor text_bgcolor; + QColor text_fgcolor; + + if (option.state & QStyle::State_Selected) { + text_bgcolor = option.palette.highlight().color(); + text_fgcolor = option.palette.highlightedText().color(); + } else { + text_bgcolor = Qt::white; + text_fgcolor = Qt::black; + } + + painter->fillRect(text_rect, text_bgcolor); + painter->setPen(text_fgcolor); + + QString duration_str = index.data(Qt::UserRole).toString(); + int timecode_width = fm.width(duration_str); + int max_name_width = option.rect.width(); + + if (timecode_width < option.rect.width() / 2) { + painter->drawText(text_rect, Qt::AlignBottom | Qt::AlignRight, index.data(Qt::UserRole).toString()); + max_name_width -= timecode_width; + } + + painter->drawText(text_rect, + Qt::AlignBottom | Qt::AlignLeft, + fm.elidedText(index.data(Qt::DisplayRole).toString(), Qt::ElideRight, max_name_width)); + + } + + // Draw image + QIcon ico = index.data(Qt::DecorationRole).value(); + QSize icon_size = ico.actualSize(img_rect.size()); + img_rect = QRect(img_rect.x() + (img_rect.width() / 2 - icon_size.width() / 2), + img_rect.y() + (img_rect.height() / 2 - icon_size.height() / 2), + icon_size.width(), + icon_size.height()); + painter->drawPixmap(img_rect, ico.pixmap(icon_size)); + + if (option.state & QStyle::State_Selected) { + QColor highlight_color = option.palette.highlight().color(); + highlight_color.setAlphaF(0.5); + + painter->setCompositionMode(QPainter::CompositionMode_SourceAtop); + painter->fillRect(img_rect, highlight_color); + } + } else if (option.decorationPosition == QStyleOptionViewItem::Left) { // List Mode + + if (option.state & QStyle::State_Selected) { + painter->fillRect(option.rect, option.palette.highlight()); + } + + img_rect.setWidth(qMin(img_rect.width(), img_rect.height())); + + QIcon ico = index.data(Qt::DecorationRole).value(); + QSize icon_size = ico.actualSize(img_rect.size()); + img_rect = QRect(img_rect.x() + (img_rect.width() / 2 - icon_size.width() / 2), + img_rect.y() + (img_rect.height() / 2 - icon_size.height() / 2), + icon_size.width(), + icon_size.height()); + painter->drawPixmap(img_rect, ico.pixmap(icon_size)); + + QRect text_rect = option.rect; + text_rect.setLeft(text_rect.left() + option.rect.height()); + + int maximum_line_count = qMax(1, option.rect.height() / fm.height() - 1); + QString text; + if (maximum_line_count == 1) { + text = index.data(Qt::DisplayRole).toString(); + } else { + text = index.data(Qt::ToolTipRole).toString(); + if (text.isEmpty()) { + text = index.data(Qt::DisplayRole).toString(); + } else { + QStringList strings = text.split("\n"); + while (strings.size() > maximum_line_count) { + strings.removeLast(); + } + text = strings.join("\n"); + } + } + + painter->setPen(option.state & QStyle::State_Selected ? + option.palette.highlightedText().color() : option.palette.text().color()); + + painter->drawText(text_rect, Qt::AlignLeft | Qt::AlignVCenter, text); + + } +} diff --git a/ui/sourceiconview.h b/ui/sourceiconview.h index df872d01c..e615068f0 100644 --- a/ui/sourceiconview.h +++ b/ui/sourceiconview.h @@ -23,10 +23,19 @@ #include #include +#include #include "project/sourcescommon.h" class Project; +class SourceIconDelegate; + +class SourceIconDelegate : public QStyledItemDelegate { +public: + SourceIconDelegate(QObject *parent = nullptr); + virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; + virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; +}; class SourceIconView : public QListView { Q_OBJECT @@ -46,6 +55,7 @@ private slots: void item_click(const QModelIndex& index); private: SourcesCommon& commons_; + SourceIconDelegate delegate_; }; #endif // SOURCEICONVIEW_H From 03b1a7e01f2fbb8f679b1e60913957b3cc59815b Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sun, 24 Mar 2019 22:45:37 +1100 Subject: [PATCH 24/35] fixed #682 --- dialogs/preferencesdialog.cpp | 2 +- ui/mainwindow.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/dialogs/preferencesdialog.cpp b/dialogs/preferencesdialog.cpp index 74d262b45..e304f06b4 100644 --- a/dialogs/preferencesdialog.cpp +++ b/dialogs/preferencesdialog.cpp @@ -660,7 +660,7 @@ void PreferencesDialog::setup_ui() { // Native menu styling is only available on Windows. Environments like Ubuntu and Mac use the native menu system by // default QCheckBox* native_menus = new QCheckBox(tr("Use Native Menu Styling")); - AddBoolPair(native_menus, &olive::CurrentConfig.use_native_menu_styling); + AddBoolPair(native_menus, &olive::CurrentConfig.use_native_menu_styling, true); appearance_layout->addWidget(native_menus, row, 0, 1, 3); row++; diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index 4f49058fd..981de8f76 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -457,7 +457,8 @@ void MainWindow::Restyle() palette.setColor(QPalette::HighlightedText, Qt::white); // set default CSS - setStyleSheet("QPushButton::checked { background: rgb(25, 25, 25); }"); + setStyleSheet("QPushButton::checked { background: rgb(25, 25, 25); }" + "QMenu::separator { background: #404040; }"); } From efbfca55cd8926859533704e1f6be1dd9763664f Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sun, 24 Mar 2019 22:48:50 +1100 Subject: [PATCH 25/35] corrected separator on native windows menus --- ui/mainwindow.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index 981de8f76..e3231966a 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -457,8 +457,11 @@ void MainWindow::Restyle() palette.setColor(QPalette::HighlightedText, Qt::white); // set default CSS - setStyleSheet("QPushButton::checked { background: rgb(25, 25, 25); }" - "QMenu::separator { background: #404040; }"); + QString stylesheet = "QPushButton::checked { background: rgb(25, 25, 25); }"; + if (!olive::CurrentConfig.use_native_menu_styling) { + stylesheet.append("QMenu::separator { background: #404040; }"); + } + setStyleSheet(stylesheet); } From 8befb907484a4e4cb08896b94fcc5c06c51deba2 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sun, 24 Mar 2019 23:00:54 +1100 Subject: [PATCH 26/35] fixed bug causing projects to fail loading from file --- global/global.cpp | 6 +++--- global/global.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/global/global.cpp b/global/global.cpp index 048a57e9b..382bb3a16 100644 --- a/global/global.cpp +++ b/global/global.cpp @@ -182,6 +182,8 @@ void OliveGlobal::LoadProject(const QString &fn, bool autorecovery) LoadDialog ld(olive::MainWindow); + ld.open(); + LoadThread* lt = new LoadThread(fn, autorecovery); connect(&ld, SIGNAL(cancel()), lt, SLOT(cancel())); connect(lt, SIGNAL(success()), &ld, SLOT(accept())); @@ -190,8 +192,6 @@ void OliveGlobal::LoadProject(const QString &fn, bool autorecovery) connect(lt, SIGNAL(report_progress(int)), &ld, SLOT(setValue(int))); lt->start(); - ld.exec(); - panel_project->ConnectFilterToModel(); } @@ -366,7 +366,7 @@ void OliveGlobal::set_sequence(SequencePtr s) panel_timeline->setFocus(); } -void OliveGlobal::OpenProjectWorker(const QString& fn, bool autorecovery) { +void OliveGlobal::OpenProjectWorker(QString fn, bool autorecovery) { ClearProject(); update_project_filename(fn); LoadProject(fn, autorecovery); diff --git a/global/global.h b/global/global.h index ac05b21bf..1fb372076 100644 --- a/global/global.h +++ b/global/global.h @@ -343,7 +343,7 @@ 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(const 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 From b93aa93a827a514746f32949034150dea1dec4b4 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sun, 24 Mar 2019 23:12:38 +1100 Subject: [PATCH 27/35] fixed possible export crash --- dialogs/exportdialog.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dialogs/exportdialog.cpp b/dialogs/exportdialog.cpp index b983eca15..b80c13d12 100644 --- a/dialogs/exportdialog.cpp +++ b/dialogs/exportdialog.cpp @@ -569,6 +569,9 @@ void ExportDialog::StartExport() { connect(export_thread_, SIGNAL(ProgressChanged(int, qint64)), this, SLOT(update_progress_bar(int, qint64))); connect(renderCancel, SIGNAL(clicked(bool)), export_thread_, SLOT(Interrupt())); + // Close all effects in effect controls (prevents UI threading issues) + panel_effect_controls->Clear(); + // Close all currently open clips close_active_clips(olive::ActiveSequence.get()); From 78fb7d11bde287a47f2ae7c838ebefe7204c77bb Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Mon, 25 Mar 2019 00:29:07 +1100 Subject: [PATCH 28/35] fixed #673 --- rendering/renderfunctions.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rendering/renderfunctions.cpp b/rendering/renderfunctions.cpp index c369f8ab9..8c27b954f 100644 --- a/rendering/renderfunctions.cpp +++ b/rendering/renderfunctions.cpp @@ -484,8 +484,9 @@ GLuint olive::rendering::compose_sequence(ComposeSequenceParams ¶ms) { glBindTexture(GL_TEXTURE_2D, textureID); // set texture filter to bilinear - params.ctx->functions()->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - params.ctx->functions()->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + params.ctx->functions()->glGenerateMipmap(GL_TEXTURE_2D); + params.ctx->functions()->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + params.ctx->functions()->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // draw clip on screen according to gl coordinates glBegin(GL_QUADS); From 276151d415cf507311cc3f7478032725724562ae Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Mon, 25 Mar 2019 01:42:01 +1100 Subject: [PATCH 29/35] fixed bug causing larger than necessary exported files --- rendering/exportthread.cpp | 41 ++++++++++++++++++++++------------- rendering/renderfunctions.cpp | 2 +- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/rendering/exportthread.cpp b/rendering/exportthread.cpp index 6e389c607..9ccf3c79f 100644 --- a/rendering/exportthread.cpp +++ b/rendering/exportthread.cpp @@ -20,17 +20,6 @@ #include "exportthread.h" -#include "global/global.h" -#include "timeline/sequence.h" -#include "panels/panels.h" - -#include "ui/viewerwidget.h" -#include "rendering/renderthread.h" -#include "rendering/renderfunctions.h" -#include "rendering/audio.h" -#include "ui/mainwindow.h" -#include "global/debug.h" - extern "C" { #include #include @@ -43,6 +32,17 @@ extern "C" { #include #include #include +#include + +#include "global/global.h" +#include "timeline/sequence.h" +#include "panels/panels.h" +#include "ui/viewerwidget.h" +#include "rendering/renderthread.h" +#include "rendering/renderfunctions.h" +#include "rendering/audio.h" +#include "ui/mainwindow.h" +#include "global/debug.h" ExportThread::ExportThread(const ExportParams ¶ms, const VideoCodecParams& vparams, @@ -92,7 +92,18 @@ bool ExportThread::Encode(AVFormatContext* ofmt_ctx, AVCodecContext* codec_ctx, } packet->stream_index = stream->index; - if (rescale) av_packet_rescale_ts(packet, codec_ctx->time_base, stream->time_base); + if (rescale) { + if (packet->pts != AV_NOPTS_VALUE) { + packet->pts = qRound(packet->pts * av_q2d(codec_ctx->time_base) / av_q2d(stream->time_base)); + } + if (packet->dts != AV_NOPTS_VALUE) { + packet->dts = qRound(packet->dts * av_q2d(codec_ctx->time_base) / av_q2d(stream->time_base)); + } + if (packet->duration > 0) { + packet->duration = qRound(packet->duration * av_q2d(codec_ctx->time_base) / av_q2d(stream->time_base)); + } + //av_packet_rescale_ts(packet, codec_ctx->time_base, stream->time_base); + } av_interleaved_write_frame(ofmt_ctx, packet); av_packet_unref(packet); } @@ -469,10 +480,10 @@ void ExportThread::Export() // Convert raw RGBA buffer to format expected by the encoder sws_scale(sws_ctx, video_frame->data, video_frame->linesize, 0, video_frame->height, sws_frame->data, sws_frame->linesize); - sws_frame->pts = qRound(timecode_secs/av_q2d(video_stream->time_base)); + sws_frame->pts = qRound(timecode_secs/av_q2d(vcodec_ctx->time_base)); // Send frame to encoder - if (!Encode(fmt_ctx, vcodec_ctx, sws_frame, &video_pkt, video_stream, false)) { + if (!Encode(fmt_ctx, vcodec_ctx, sws_frame, &video_pkt, video_stream, true)) { return; } @@ -578,7 +589,7 @@ void ExportThread::Export() // Flush remaining packets out of video and audio encoders while (continueVideo && continueAudio) { if (continueVideo) { - continueVideo = Encode(fmt_ctx, vcodec_ctx, nullptr, &video_pkt, video_stream, false); + continueVideo = Encode(fmt_ctx, vcodec_ctx, nullptr, &video_pkt, video_stream, true); } if (continueAudio) { continueAudio = Encode(fmt_ctx, acodec_ctx, nullptr, &audio_pkt, audio_stream, true); diff --git a/rendering/renderfunctions.cpp b/rendering/renderfunctions.cpp index 8c27b954f..48cfc1a84 100644 --- a/rendering/renderfunctions.cpp +++ b/rendering/renderfunctions.cpp @@ -407,10 +407,10 @@ GLuint olive::rendering::compose_sequence(ComposeSequenceParams ¶ms) { // run through all of the clip's effects for (int j=0;jeffects.size();j++) { + Effect* e = c->effects.at(j).get(); process_effect(c, e, timecode, coords, textureID, fbo_switcher, params.texture_failed, kTransitionNone); - } // if the clip has an opening transition, process that now From 7b7a083d0a30260887e844df38500f3214a68e09 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Mon, 25 Mar 2019 01:43:13 +1100 Subject: [PATCH 30/35] fixed #684 --- effects/internal/frei0reffect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/effects/internal/frei0reffect.cpp b/effects/internal/frei0reffect.cpp index e5c0516df..c01ee0835 100644 --- a/effects/internal/frei0reffect.cpp +++ b/effects/internal/frei0reffect.cpp @@ -100,7 +100,7 @@ Frei0rEffect::Frei0rEffect(Clip* c, const EffectMeta *em) : } break; case F0R_PARAM_STRING: - new StringField(row, QString::number(i)); + new StringField(row, QString::number(i), false); break; } } From 02d0b359241b7c31c048e23e2ed15cbbfb3a7548 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Mon, 25 Mar 2019 02:05:08 +1100 Subject: [PATCH 31/35] break loop if we receive an averror, fixes #664 --- rendering/cacher.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/rendering/cacher.cpp b/rendering/cacher.cpp index 1fc51e93b..ad79b7463 100644 --- a/rendering/cacher.cpp +++ b/rendering/cacher.cpp @@ -654,6 +654,7 @@ void Cacher::CacheVideoWorker() { // again, an EOF isn't an "error" but will how we add frames (see below) qCritical() << "Failed to retrieve frame from buffersink." << retrieve_code; + break; } else if (decoded_frame->pts != AV_NOPTS_VALUE) { From aff3acb94ed698a94b28d953aed653651a7f055d Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Mon, 25 Mar 2019 02:49:58 +1100 Subject: [PATCH 32/35] implemented default sequence settings --- dialogs/newsequencedialog.cpp | 54 ++++++++++++++++++++++++++++------- dialogs/newsequencedialog.h | 35 +++++++++++++++++++---- dialogs/preferencesdialog.cpp | 23 +++++++++++++++ dialogs/preferencesdialog.h | 13 +++++++++ global/config.cpp | 27 +++++++++++++++++- global/config.h | 25 ++++++++++++++++ panels/project.cpp | 19 ++++-------- panels/viewer.cpp | 11 +++---- 8 files changed, 170 insertions(+), 37 deletions(-) diff --git a/dialogs/newsequencedialog.cpp b/dialogs/newsequencedialog.cpp index f852e5253..67b3537c0 100644 --- a/dialogs/newsequencedialog.cpp +++ b/dialogs/newsequencedialog.cpp @@ -39,19 +39,26 @@ #include "panels/timeline.h" #include "project/media.h" #include "rendering/audio.h" +#include "global/config.h" extern "C" { #include } -NewSequenceDialog::NewSequenceDialog(QWidget *parent, Media *existing) : +NewSequenceDialog::NewSequenceDialog(QWidget *parent, Media *existing, Sequence* iexisting_sequence) : QDialog(parent), - existing_item(existing) + existing_item(existing), + existing_sequence(iexisting_sequence) { + Q_ASSERT(!(existing != nullptr && iexisting_sequence != nullptr)); + setup_ui(); if (existing != nullptr) { - existing_sequence = existing->to_sequence(); + existing_sequence = existing->to_sequence().get(); + } + + if (existing_sequence != nullptr) { setWindowTitle(tr("Editing \"%1\"").arg(existing_sequence->name)); width_numeric->setValue(existing_sequence->width); @@ -80,6 +87,12 @@ 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) { @@ -98,7 +111,7 @@ void NewSequenceDialog::accept() { panel_project->create_sequence_internal(ca, s, true, nullptr); olive::UndoStack.push(ca); - } else { + } else if (existing_item != nullptr) { // The dialog was given an existing Sequence object, so we'll apply the changes to it @@ -106,7 +119,7 @@ void NewSequenceDialog::accept() { double multiplier = frame_rate_combobox->currentData().toDouble() / existing_sequence->frame_rate; - EditSequenceCommand* esc = new EditSequenceCommand(existing_item, existing_sequence); + 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(); @@ -123,6 +136,18 @@ void NewSequenceDialog::accept() { } olive::UndoStack.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->name = sequence_name_edit->text(); + existing_sequence->width = width_numeric->value(); + existing_sequence->height = height_numeric->value(); + existing_sequence->frame_rate = frame_rate_combobox->currentData().toDouble(); + existing_sequence->audio_frequency = audio_frequency_combobox->currentData().toInt(); + existing_sequence->audio_layout = AV_CH_LAYOUT_STEREO; + } QDialog::accept(); @@ -210,13 +235,13 @@ void NewSequenceDialog::setup_ui() { videoLayout->addWidget(new QLabel(tr("Width:"), this), 0, 0, 1, 1); width_numeric = new QSpinBox(videoGroupBox); width_numeric->setMaximum(9999); - width_numeric->setValue(1920); + width_numeric->setValue(olive::CurrentConfig.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(1080); + height_numeric->setValue(olive::CurrentConfig.default_sequence_height); videoLayout->addWidget(height_numeric, 1, 2, 1, 2); videoLayout->addWidget(new QLabel(tr("Frame Rate:"), this), 2, 0, 1, 1); @@ -232,7 +257,11 @@ void NewSequenceDialog::setup_ui() { 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); - frame_rate_combobox->setCurrentIndex(6); + for (int i=0;icount();i++) { + if (qFuzzyCompare(frame_rate_combobox->itemData(i).toDouble(), olive::CurrentConfig.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); @@ -258,7 +287,11 @@ void NewSequenceDialog::setup_ui() { audio_frequency_combobox = new QComboBox(audioGroupBox); combobox_audio_sample_rates(audio_frequency_combobox); - audio_frequency_combobox->setCurrentIndex(4); + for (int i=0;icount();i++) { + if (audio_frequency_combobox->itemData(i) == olive::CurrentConfig.default_sequence_audio_frequency) { + audio_frequency_combobox->setCurrentIndex(i); + } + } audioLayout->addWidget(audio_frequency_combobox, 0, 1, 1, 1); @@ -268,7 +301,8 @@ void NewSequenceDialog::setup_ui() { QHBoxLayout* nameLayout = new QHBoxLayout(nameWidget); nameLayout->setContentsMargins(0, 0, 0, 0); - nameLayout->addWidget(new QLabel(tr("Name:"), this)); + sequence_name_label = new QLabel(tr("Name:")); + nameLayout->addWidget(sequence_name_label); sequence_name_edit = new QLineEdit(nameWidget); diff --git a/dialogs/newsequencedialog.h b/dialogs/newsequencedialog.h index 631923647..4e5ad8c34 100644 --- a/dialogs/newsequencedialog.h +++ b/dialogs/newsequencedialog.h @@ -50,8 +50,13 @@ public: * * 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); + explicit NewSequenceDialog(QWidget *parent = nullptr, Media* existing = nullptr, Sequence* iexisting_sequence = nullptr); /** * @brief Set the name for the new Sequence @@ -68,6 +73,17 @@ public: */ 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 @@ -86,16 +102,16 @@ private slots: void preset_changed(int index); private: - /** - * @brief Internal reference to an existing Sequence (if one was provided to the constructor) - */ - SequencePtr existing_sequence; - /** * @brief Internal reference to an existing Media wrapper (if one was provided to the constructor) */ Media* existing_item; + /** + * @brief Internal reference to an existing Sequence (if one was provided to the constructor) + */ + Sequence* existing_sequence; + /** * @brief Internal function to create the dialog's UI */ @@ -136,6 +152,13 @@ private: */ 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 */ diff --git a/dialogs/preferencesdialog.cpp b/dialogs/preferencesdialog.cpp index e304f06b4..3fc27bdfb 100644 --- a/dialogs/preferencesdialog.cpp +++ b/dialogs/preferencesdialog.cpp @@ -51,6 +51,7 @@ #include "panels/panels.h" #include "ui/columnedgridlayout.h" #include "ui/mainwindow.h" +#include "dialogs/newsequencedialog.h" KeySequenceEditor::KeySequenceEditor(QWidget* parent, QAction* a) : QKeySequenceEdit(parent), action(a) { @@ -86,6 +87,14 @@ PreferencesDialog::PreferencesDialog(QWidget *parent) : setup_ui(); setup_kbd_shortcuts(olive::MainWindow->menuBar()); + + // set up default sequence + default_sequence.name = tr("Default Sequence"); + default_sequence.width = olive::CurrentConfig.default_sequence_width; + default_sequence.height = olive::CurrentConfig.default_sequence_height; + default_sequence.frame_rate = olive::CurrentConfig.default_sequence_framerate; + default_sequence.audio_frequency = olive::CurrentConfig.default_sequence_audio_frequency; + default_sequence.audio_layout = olive::CurrentConfig.default_sequence_audio_channel_layout; } void PreferencesDialog::setup_kbd_shortcut_worker(QMenu* menu, QTreeWidgetItem* parent) { @@ -265,6 +274,12 @@ void PreferencesDialog::accept() { olive::CurrentConfig.effect_textbox_lines = effect_textbox_lines_field->value(); olive::CurrentConfig.language_file = language_combobox->currentData().toString(); + olive::CurrentConfig.default_sequence_width = default_sequence.width; + olive::CurrentConfig.default_sequence_height = default_sequence.height; + olive::CurrentConfig.default_sequence_framerate = default_sequence.frame_rate; + olive::CurrentConfig.default_sequence_audio_frequency = default_sequence.audio_frequency; + olive::CurrentConfig.default_sequence_audio_channel_layout = default_sequence.audio_layout; + for (int i=0;iisChecked(); } @@ -470,6 +485,13 @@ void PreferencesDialog::delete_all_previews() { } } +void PreferencesDialog::edit_default_sequence_settings() +{ + NewSequenceDialog nsd(this, nullptr, &default_sequence); + nsd.SetNameEditable(false); + nsd.exec(); +} + void PreferencesDialog::setup_ui() { QVBoxLayout* verticalLayout = new QVBoxLayout(this); QTabWidget* tabWidget = new QTabWidget(this); @@ -560,6 +582,7 @@ void PreferencesDialog::setup_ui() { // General -> Default Sequence Settings QPushButton* default_sequence_settings = new QPushButton(tr("Default Sequence Settings")); + connect(default_sequence_settings, SIGNAL(clicked(bool)), this, SLOT(edit_default_sequence_settings())); general_layout->addWidget(default_sequence_settings); tabWidget->addTab(general_tab, tr("General")); diff --git a/dialogs/preferencesdialog.h b/dialogs/preferencesdialog.h index 38efcdf7e..f360284ea 100644 --- a/dialogs/preferencesdialog.h +++ b/dialogs/preferencesdialog.h @@ -118,6 +118,11 @@ private slots: */ void delete_all_previews(); + /** + * @brief Shows a NewSequenceDialog attached to default_sequence + */ + void edit_default_sequence_settings(); + private: /** @@ -243,6 +248,14 @@ private: */ QComboBox* ui_style; + /** + * @brief Stored default Sequence object + * + * Default Sequence settings are loaded into an actual Sequence object that can be loaded into NewSequenceDialog + * for the sake of familiarity with the user. + */ + Sequence default_sequence; + /** * @brief List of keyboard shortcut actions that can be triggered (links with key_shortcut_items and * key_shortcut_fields) diff --git a/global/config.cpp b/global/config.cpp index cc2e2b441..5ab9a2293 100644 --- a/global/config.cpp +++ b/global/config.cpp @@ -73,7 +73,12 @@ Config::Config() add_default_effects_to_clips(true), invert_timeline_scroll_axes(true), style(olive::styling::kOliveDefaultDark), - use_native_menu_styling(true) + use_native_menu_styling(true), + default_sequence_width(1920), + default_sequence_height(1080), + default_sequence_framerate(29.97), + default_sequence_audio_frequency(48000), + default_sequence_audio_channel_layout(3) {} void Config::load(QString path) { @@ -219,6 +224,21 @@ void Config::load(QString path) { } else if (stream.name() == "NativeMenuStyling") { stream.readNext(); use_native_menu_styling = (stream.text() == "1"); + } else if (stream.name() == "DefaultSequenceWidth") { + stream.readNext(); + default_sequence_width = stream.text().toInt(); + } else if (stream.name() == "DefaultSequenceHeight") { + stream.readNext(); + default_sequence_height = stream.text().toInt(); + } else if (stream.name() == "DefaultSequenceFrameRate") { + stream.readNext(); + default_sequence_framerate = stream.text().toDouble(); + } else if (stream.name() == "DefaultSequenceAudioFrequency") { + stream.readNext(); + default_sequence_audio_frequency = stream.text().toInt(); + } else if (stream.name() == "DefaultSequenceAudioLayout") { + stream.readNext(); + default_sequence_audio_channel_layout = stream.text().toInt(); } } } @@ -288,6 +308,11 @@ void Config::save(QString path) { stream.writeTextElement("AddDefaultEffectsToClips", QString::number(add_default_effects_to_clips)); stream.writeTextElement("Style", QString::number(style)); stream.writeTextElement("NativeMenuStyling", QString::number(use_native_menu_styling)); + stream.writeTextElement("DefaultSequenceWidth", QString::number(default_sequence_width)); + stream.writeTextElement("DefaultSequenceHeight", QString::number(default_sequence_height)); + 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.writeEndElement(); // configuration stream.writeEndDocument(); // doc diff --git a/global/config.h b/global/config.h index c72b52077..498a9895c 100644 --- a/global/config.h +++ b/global/config.h @@ -533,6 +533,31 @@ struct Config { */ bool use_native_menu_styling; + /** + * @brief Default Sequence video width + */ + int default_sequence_width; + + /** + * @brief Default Sequence video height + */ + int default_sequence_height; + + /** + * @brief Default Sequence video frame rate + */ + double default_sequence_framerate; + + /** + * @brief Default Sequence audio frequency + */ + int default_sequence_audio_frequency; + + /** + * @brief Default Sequence audio channel layout + */ + int default_sequence_audio_channel_layout; + /** * @brief Load config from file * diff --git a/panels/project.cpp b/panels/project.cpp index fb609a114..e4781a160 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -65,13 +65,6 @@ extern "C" { #include "global/debug.h" #include "ui/menu.h" -// TODO make these configurable -const int kDefaultSequenceWidth = 1920; -const int kDefaultSequenceHeight = 1080; -const double kDefaultSequenceFrameRate = 29.97; -const int kDefaultSequenceFrequency = 48000; -const int kDefaultSequenceChannelLayout = 3; - #define MAXIMUM_RECENT_PROJECTS 10 // FIXME: should be configurable QString autorecovery_filename; @@ -261,12 +254,12 @@ SequencePtr create_sequence_from_media(QVector s->name = panel_project->get_next_sequence_name(); - // shitty hardcoded default values - s->width = kDefaultSequenceWidth; - s->height = kDefaultSequenceHeight; - s->frame_rate = kDefaultSequenceFrameRate; - s->audio_frequency = kDefaultSequenceFrequency; - s->audio_layout = kDefaultSequenceChannelLayout; + // Retrieve default Sequence settings from Config + s->width = olive::CurrentConfig.default_sequence_width; + s->height = olive::CurrentConfig.default_sequence_height; + s->frame_rate = olive::CurrentConfig.default_sequence_framerate; + s->audio_frequency = olive::CurrentConfig.default_sequence_audio_frequency; + s->audio_layout = olive::CurrentConfig.default_sequence_audio_channel_layout; bool got_video_values = false; bool got_audio_values = false; diff --git a/panels/viewer.cpp b/panels/viewer.cpp index 7e17bb583..b91c00d07 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -802,8 +802,7 @@ void Viewer::set_media(Media* m) { new_sequence->workarea_out = footage->out; } - // FIXME: Move this magic number to Config - new_sequence->frame_rate = 30; + new_sequence->frame_rate = olive::CurrentConfig.default_sequence_framerate; if (footage->video_tracks.size() > 0) { const FootageStream& video_stream = footage->video_tracks.at(0); @@ -826,9 +825,8 @@ void Viewer::set_media(Media* m) { c->refresh(); new_sequence->clips.append(c); } else { - // FIXME: Move this magic number to Config - new_sequence->width = 1920; - new_sequence->height = 1080; + new_sequence->width = olive::CurrentConfig.default_sequence_width; + new_sequence->height = olive::CurrentConfig.default_sequence_height; } if (footage->audio_tracks.size() > 0) { @@ -851,8 +849,7 @@ void Viewer::set_media(Media* m) { viewer_widget->frame_update(); } } else { - // FIXME: Move this magic number to Config - new_sequence->audio_frequency = 48000; + new_sequence->audio_frequency = olive::CurrentConfig.default_sequence_audio_frequency; } new_sequence->audio_layout = AV_CH_LAYOUT_STEREO; From 86b0787f4cf40b5549f0d05baef8fb4cfb56013c Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Mon, 25 Mar 2019 03:36:28 +1100 Subject: [PATCH 33/35] fixed nesting bug where clips would overlap others on timeline --- panels/timeline.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 977de2aa8..2b2f5e002 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -513,6 +513,32 @@ void Timeline::nest() { QVector media_list; media_list.append(m.get()); create_ghosts_from_media(olive::ActiveSequence.get(), earliest_point, media_list); + + // ensure ghosts won't overlap anything + for (int j=0;jclips.size();j++) { + Clip* c = olive::ActiveSequence->clips.at(j).get(); + if (c != nullptr && !selected_clips.contains(j)) { + for (int i=0;itrack() == g.track + && !((c->timeline_in() < g.in + && c->timeline_out() < g.in) + || (c->timeline_in() > g.out + && c->timeline_out() > g.out))) { + // There's a clip occupied by the space taken up by this ghost. Move up/down a track, and seek again + if (g.track < 0) { + g.track--; + } else { + g.track++; + } + j = -1; + break; + } + } + } + } + + add_clips_from_ghosts(ca, olive::ActiveSequence.get()); panel_graph_editor->set_row(nullptr); From 83a181a6dba46c8d71daf5199ccc518458a80afc Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Mon, 25 Mar 2019 10:51:39 +1100 Subject: [PATCH 34/35] fixed menu separators on non-windows platforms --- ui/mainwindow.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index e3231966a..75f20f7a4 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -458,9 +458,15 @@ void MainWindow::Restyle() // set default CSS QString stylesheet = "QPushButton::checked { background: rgb(25, 25, 25); }"; + + // Windows menus have the option of being native, so we may not need this CSS +#ifdef Q_OS_WIN if (!olive::CurrentConfig.use_native_menu_styling) { +#endif stylesheet.append("QMenu::separator { background: #404040; }"); +#ifdef Q_OS_WIN } +#endif setStyleSheet(stylesheet); } From a3c1342f7741495eabc591809f3da9374d1e2a2c Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Mon, 25 Mar 2019 11:43:16 +1100 Subject: [PATCH 35/35] fixed #685 --- dialogs/preferencesdialog.cpp | 1 - ui/mainwindow.cpp | 1 - ui/viewerwindow.cpp | 35 +++++++++++++++++++++++++++++++++++ ui/viewerwindow.h | 35 ++++++++++++++++++++--------------- 4 files changed, 55 insertions(+), 17 deletions(-) diff --git a/dialogs/preferencesdialog.cpp b/dialogs/preferencesdialog.cpp index 3fc27bdfb..6204a938a 100644 --- a/dialogs/preferencesdialog.cpp +++ b/dialogs/preferencesdialog.cpp @@ -60,7 +60,6 @@ KeySequenceEditor::KeySequenceEditor(QWidget* parent, QAction* a) void KeySequenceEditor::set_action_shortcut() { action->setShortcut(keySequence()); - action->setShortcutContext(Qt::ApplicationShortcut); } void KeySequenceEditor::reset_to_default() { diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index 75f20f7a4..5f79b151b 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -341,7 +341,6 @@ void kbd_shortcut_processor(QByteArray& file, QMenu* menu, bool save, bool first } } } - a->setShortcutContext(Qt::ApplicationShortcut); } } } diff --git a/ui/viewerwindow.cpp b/ui/viewerwindow.cpp index 69bb74053..646db81f9 100644 --- a/ui/viewerwindow.cpp +++ b/ui/viewerwindow.cpp @@ -52,6 +52,41 @@ void ViewerWindow::set_texture(GLuint t, double iar, QMutex* imutex) { update(); } +void ViewerWindow::shortcut_copier(QVector& shortcuts, QMenu* menu) { + QList menu_action = menu->actions(); + for (int i=0;imenu() != nullptr) { + shortcut_copier(shortcuts, menu_action.at(i)->menu()); + } else if (!menu_action.at(i)->isSeparator() && !menu_action.at(i)->shortcut().isEmpty()) { + QShortcut* sc = new QShortcut(this); + sc->setKey(menu_action.at(i)->shortcut()); + connect(sc, SIGNAL(activated()), menu_action.at(i), SLOT(trigger())); + shortcuts.append(sc); + } + } +} + +void ViewerWindow::showEvent(QShowEvent *) +{ + // Here, we copy all shortcuts from the MainWindow to this window. I don't like this solution, but messing around + // with Qt's event system proved fruitless. Also setting the shortcuts to ApplicationShortcut rather than + // WindowShortcut caused issues elsewhere (shortcuts being picked up in comboboxes and dialog boxes - we only + // want the shortcuts to be shared to this window). Therefore, this and shortcut_copier() are so far the best + // solutions I can find. + + // Clear any existing shortcuts in case they've changed since the last showing + for (int i=0;i menubar_actions = olive::MainWindow->menuBar()->actions(); + for (int i=0;imenu()); + } +} + void ViewerWindow::keyPressEvent(QKeyEvent *e) { if (e->key() == Qt::Key_Escape) { hide(); diff --git a/ui/viewerwindow.h b/ui/viewerwindow.h index ccba77452..1257fa13e 100644 --- a/ui/viewerwindow.h +++ b/ui/viewerwindow.h @@ -29,27 +29,32 @@ class QMenu; class QShortcut; class ViewerWindow : public QOpenGLWidget { - Q_OBJECT + Q_OBJECT public: - ViewerWindow(QWidget *parent); - void set_texture(GLuint t, double iar, QMutex *imutex); + ViewerWindow(QWidget *parent); + void set_texture(GLuint t, double iar, QMutex *imutex); protected: - virtual void keyPressEvent(QKeyEvent*) override; - virtual void mousePressEvent(QMouseEvent*) override; - virtual void mouseMoveEvent(QMouseEvent*) override; + virtual void showEvent(QShowEvent*) override; + virtual void keyPressEvent(QKeyEvent*) override; + virtual void mousePressEvent(QMouseEvent*) override; + virtual void mouseMoveEvent(QMouseEvent*) override; - virtual void paintGL() override; + virtual void paintGL() override; private: - GLuint texture; - double ar; - QMutex* mutex; + GLuint texture; + double ar; + QMutex* mutex; - // exit full screen message - QTimer fullscreen_msg_timer; - bool show_fullscreen_msg; - QRect fullscreen_msg_rect; + // shortcuts + void shortcut_copier(QVector& shortcuts, QMenu* menu); + QVector shortcuts_; + + // exit full screen message + QTimer fullscreen_msg_timer; + bool show_fullscreen_msg; + QRect fullscreen_msg_rect; private slots: - void fullscreen_msg_timeout(); + void fullscreen_msg_timeout(); }; #endif // VIEWERWINDOW_H