Merge branch 'master' into resizablebars
@@ -4,6 +4,6 @@ Olive is a free non-linear video editor for Windows, macOS, and Linux.
|
||||
|
||||
Discover more and download binaries at: https://www.olivevideoeditor.org/
|
||||
|
||||
For compilation information, check the [wiki](https://github.com/olive-editor/olive/wiki). Currently the `master` branch serves more or less as the stable branch and the majority of development happens in the `alpha` branch. Before filing a feature request or bug report, please try the `alpha` branch first to ensure it hasn't already been addressed.
|
||||
Compiling instructions for Windows, macOS, and Linux are [here](https://olivevideoeditor.org/compile.php).
|
||||
|
||||
If you like Olive, please consider helping keep it alive by supporting it on [Patreon](https://www.patreon.com/olivevideoeditor).
|
||||
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
@@ -49,5 +49,7 @@
|
||||
<file>transition-tool.png</file>
|
||||
<file>transition-tool-disabled.png</file>
|
||||
<file>error.png</file>
|
||||
<file>dirup.png</file>
|
||||
<file>dirup-disabled.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@@ -32,7 +32,8 @@ Config::Config()
|
||||
autoscroll(AUTOSCROLL_PAGE_SCROLL),
|
||||
audio_rate(48000),
|
||||
fast_seeking(false),
|
||||
hover_focus(false)
|
||||
hover_focus(false),
|
||||
project_view_type(PROJECT_VIEW_TREE)
|
||||
{}
|
||||
|
||||
void Config::load(QString path) {
|
||||
@@ -115,6 +116,9 @@ void Config::load(QString path) {
|
||||
} else if (stream.name() == "HoverFocus") {
|
||||
stream.readNext();
|
||||
hover_focus = (stream.text() == "1");
|
||||
} else if (stream.name() == "ProjectViewType") {
|
||||
stream.readNext();
|
||||
project_view_type = stream.text().toInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -163,6 +167,7 @@ void Config::save(QString path) {
|
||||
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.writeEndElement(); // configuration
|
||||
stream.writeEndDocument(); // doc
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
#define AUTOSCROLL_PAGE_SCROLL 1
|
||||
#define AUTOSCROLL_SMOOTH_SCROLL 2
|
||||
|
||||
#define PROJECT_VIEW_TREE 0
|
||||
#define PROJECT_VIEW_ICON 1
|
||||
|
||||
struct Config {
|
||||
Config();
|
||||
bool saved_layout;
|
||||
@@ -44,6 +47,7 @@ struct Config {
|
||||
int audio_rate;
|
||||
bool fast_seeking;
|
||||
bool hover_focus;
|
||||
int project_view_type;
|
||||
|
||||
void load(QString path);
|
||||
void save(QString path);
|
||||
|
||||
@@ -97,8 +97,8 @@ bool ExportThread::setupVideo() {
|
||||
}
|
||||
|
||||
// allocate context
|
||||
vcodec_ctx = video_stream->codec;
|
||||
// vcodec_ctx = avcodec_alloc_context3(vcodec);
|
||||
// vcodec_ctx = video_stream->codec;
|
||||
vcodec_ctx = avcodec_alloc_context3(vcodec);
|
||||
if (!vcodec_ctx) {
|
||||
dout << "[ERROR] Could not allocate video encoding context";
|
||||
ed->export_error = "could not allocate video encoding context";
|
||||
@@ -125,7 +125,7 @@ bool ExportThread::setupVideo() {
|
||||
itoa(vcodec_ctx, buffer, 10);*/
|
||||
|
||||
//av_opt_set(vcodec_ctx->priv_data, "preset", "fast", AV_OPT_SEARCH_CHILDREN);
|
||||
av_opt_set(vcodec_ctx->priv_data, "x264opts", "opencl", AV_OPT_SEARCH_CHILDREN);
|
||||
//av_opt_set(vcodec_ctx->priv_data, "x264opts", "opencl", AV_OPT_SEARCH_CHILDREN);
|
||||
|
||||
switch (video_compression_type) {
|
||||
case COMPRESSION_TYPE_CFR:
|
||||
@@ -203,8 +203,8 @@ bool ExportThread::setupAudio() {
|
||||
}
|
||||
|
||||
// allocate context
|
||||
acodec_ctx = audio_stream->codec;
|
||||
// acodec_ctx = avcodec_alloc_context3(acodec);
|
||||
// acodec_ctx = audio_stream->codec;
|
||||
acodec_ctx = avcodec_alloc_context3(acodec);
|
||||
if (!acodec_ctx) {
|
||||
dout << "[ERROR] Could not find allocate audio encoding context";
|
||||
ed->export_error = "could not allocate audio encoding context";
|
||||
@@ -448,14 +448,14 @@ void ExportThread::run() {
|
||||
avcodec_close(vcodec_ctx);
|
||||
av_packet_unref(&video_pkt);
|
||||
av_frame_free(&video_frame);
|
||||
// avcodec_free_context(&vcodec_ctx);
|
||||
avcodec_free_context(&vcodec_ctx);
|
||||
}
|
||||
|
||||
if (audio_enabled) {
|
||||
avcodec_close(acodec_ctx);
|
||||
av_packet_unref(&audio_pkt);
|
||||
av_frame_free(&audio_frame);
|
||||
// avcodec_free_context(&acodec_ctx);
|
||||
avcodec_free_context(&acodec_ctx);
|
||||
}
|
||||
|
||||
avformat_free_context(fmt_ctx);
|
||||
|
||||
@@ -128,6 +128,7 @@ bool PreviewGenerator::retrieve_preview(const QString& hash) {
|
||||
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;
|
||||
@@ -255,7 +256,7 @@ void PreviewGenerator::generate_waveform() {
|
||||
if (!s->preview_done) {
|
||||
int dstH = 120;
|
||||
int dstW = dstH * ((float)temp_frame->width/(float)temp_frame->height);
|
||||
uint8_t* data = new uint8_t[dstW*dstH*3];
|
||||
uint8_t* data = new uint8_t[dstW*dstH*4];
|
||||
|
||||
sws_ctx = sws_getContext(
|
||||
temp_frame->width,
|
||||
@@ -263,7 +264,7 @@ void PreviewGenerator::generate_waveform() {
|
||||
static_cast<AVPixelFormat>(temp_frame->format),
|
||||
dstW,
|
||||
dstH,
|
||||
static_cast<AVPixelFormat>(AV_PIX_FMT_RGB24),
|
||||
static_cast<AVPixelFormat>(AV_PIX_FMT_RGBA),
|
||||
SWS_FAST_BILINEAR,
|
||||
NULL,
|
||||
NULL,
|
||||
@@ -271,10 +272,11 @@ void PreviewGenerator::generate_waveform() {
|
||||
);
|
||||
|
||||
int linesize[AV_NUM_DATA_POINTERS];
|
||||
linesize[0] = dstW*3;
|
||||
linesize[0] = dstW*4;
|
||||
sws_scale(sws_ctx, temp_frame->data, temp_frame->linesize, 0, temp_frame->height, &data, linesize);
|
||||
|
||||
s->video_preview = QImage(data, dstW, dstH, linesize[0], QImage::Format_RGB888);
|
||||
s->video_preview = QImage(data, dstW, dstH, linesize[0], QImage::Format_RGBA8888);
|
||||
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;
|
||||
|
||||
@@ -130,15 +130,6 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
|
||||
layout()->invalidate();
|
||||
|
||||
// TODO maybe replace these with non-pointers later on?
|
||||
panel_sequence_viewer = new Viewer(this);
|
||||
panel_footage_viewer = new Viewer(this);
|
||||
panel_project = new Project(this);
|
||||
panel_effect_controls = new EffectControls(this);
|
||||
panel_timeline = new Timeline(this);
|
||||
|
||||
setup_layout(false);
|
||||
|
||||
connect(ui->menuWindow, SIGNAL(aboutToShow()), this, SLOT(windowMenu_About_To_Be_Shown()));
|
||||
connect(ui->menu_View, SIGNAL(aboutToShow()), this, SLOT(viewMenu_About_To_Be_Shown()));
|
||||
connect(ui->menu_Tools, SIGNAL(aboutToShow()), this, SLOT(toolMenu_About_To_Be_Shown()));
|
||||
@@ -215,6 +206,15 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
}
|
||||
}
|
||||
|
||||
// TODO maybe replace these with non-pointers later on?
|
||||
panel_sequence_viewer = new Viewer(this);
|
||||
panel_footage_viewer = new Viewer(this);
|
||||
panel_project = new Project(this);
|
||||
panel_effect_controls = new EffectControls(this);
|
||||
panel_timeline = new Timeline(this);
|
||||
|
||||
setup_layout(false);
|
||||
|
||||
init_audio();
|
||||
|
||||
connect(ui->action_Undo, SIGNAL(triggered(bool)), this, SLOT(undo()));
|
||||
@@ -439,7 +439,7 @@ void MainWindow::new_project() {
|
||||
panel_project->new_project();
|
||||
updateTitle("");
|
||||
update_ui(false);
|
||||
panel_project->source_table->update();
|
||||
panel_project->tree_view->update();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>653</width>
|
||||
<height>25</height>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menu_File">
|
||||
@@ -148,6 +148,7 @@
|
||||
<addaction name="separator"/>
|
||||
<addaction name="menuTitle_Action_Safe_Area"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionFull_Screen"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuPlayback">
|
||||
|
||||
@@ -1,207 +1,242 @@
|
||||
#-------------------------------------------------
|
||||
#
|
||||
# Project created by QtCreator 2018-05-11T10:31:59
|
||||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
QT += core gui multimedia opengl
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
TARGET = Olive
|
||||
TEMPLATE = app
|
||||
|
||||
# The following define makes your compiler emit warnings if you use
|
||||
# any feature of Qt which has been marked as deprecated (the exact warnings
|
||||
# depend on your compiler). Please consult the documentation of the
|
||||
# deprecated API in order to know how to port your code away from it.
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
# You can also make your code fail to compile if you use deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
mainwindow.cpp \
|
||||
panels/project.cpp \
|
||||
panels/effectcontrols.cpp \
|
||||
panels/viewer.cpp \
|
||||
panels/timeline.cpp \
|
||||
ui/sourcetable.cpp \
|
||||
dialogs/aboutdialog.cpp \
|
||||
ui/timelinewidget.cpp \
|
||||
project/media.cpp \
|
||||
project/footage.cpp \
|
||||
project/sequence.cpp \
|
||||
project/clip.cpp \
|
||||
playback/playback.cpp \
|
||||
playback/audio.cpp \
|
||||
io/config.cpp \
|
||||
dialogs/newsequencedialog.cpp \
|
||||
ui/viewerwidget.cpp \
|
||||
ui/viewercontainer.cpp \
|
||||
dialogs/exportdialog.cpp \
|
||||
ui/collapsiblewidget.cpp \
|
||||
panels/panels.cpp \
|
||||
playback/cacher.cpp \
|
||||
io/exportthread.cpp \
|
||||
ui/timelineheader.cpp \
|
||||
io/previewgenerator.cpp \
|
||||
ui/labelslider.cpp \
|
||||
dialogs/preferencesdialog.cpp \
|
||||
ui/audiomonitor.cpp \
|
||||
project/undo.cpp \
|
||||
ui/scrollarea.cpp \
|
||||
ui/comboboxex.cpp \
|
||||
ui/colorbutton.cpp \
|
||||
dialogs/replaceclipmediadialog.cpp \
|
||||
ui/fontcombobox.cpp \
|
||||
ui/checkboxex.cpp \
|
||||
ui/keyframeview.cpp \
|
||||
ui/texteditex.cpp \
|
||||
dialogs/demonotice.cpp \
|
||||
project/marker.cpp \
|
||||
dialogs/speeddialog.cpp \
|
||||
dialogs/mediapropertiesdialog.cpp \
|
||||
io/crc32.cpp \
|
||||
project/projectmodel.cpp \
|
||||
io/loadthread.cpp \
|
||||
dialogs/loaddialog.cpp \
|
||||
debug.cpp \
|
||||
io/path.cpp \
|
||||
effects/internal/linearfadetransition.cpp \
|
||||
effects/internal/transformeffect.cpp \
|
||||
effects/internal/solideffect.cpp \
|
||||
effects/internal/texteffect.cpp \
|
||||
effects/internal/timecodeeffect.cpp \
|
||||
effects/internal/audionoiseeffect.cpp \
|
||||
effects/internal/paneffect.cpp \
|
||||
effects/internal/toneeffect.cpp \
|
||||
effects/internal/volumeeffect.cpp \
|
||||
effects/internal/crossdissolvetransition.cpp \
|
||||
effects/internal/shakeeffect.cpp \
|
||||
effects/internal/exponentialfadetransition.cpp \
|
||||
effects/internal/logarithmicfadetransition.cpp \
|
||||
effects/internal/cornerpineffect.cpp \
|
||||
io/math.cpp \
|
||||
io/qpainterwrapper.cpp \
|
||||
project/effect.cpp \
|
||||
project/transition.cpp \
|
||||
project/effectrow.cpp \
|
||||
project/effectfield.cpp \
|
||||
effects/internal/cubetransition.cpp \
|
||||
project/effectgizmo.cpp \
|
||||
io/clipboard.cpp \
|
||||
dialogs/stabilizerdialog.cpp \
|
||||
io/avtogl.cpp \
|
||||
ui/resizablescrollbar.cpp
|
||||
|
||||
HEADERS += \
|
||||
mainwindow.h \
|
||||
panels/project.h \
|
||||
panels/effectcontrols.h \
|
||||
panels/viewer.h \
|
||||
panels/timeline.h \
|
||||
ui/sourcetable.h \
|
||||
dialogs/aboutdialog.h \
|
||||
ui/timelinewidget.h \
|
||||
project/media.h \
|
||||
project/footage.h \
|
||||
project/sequence.h \
|
||||
project/clip.h \
|
||||
playback/playback.h \
|
||||
playback/audio.h \
|
||||
io/config.h \
|
||||
dialogs/newsequencedialog.h \
|
||||
ui/viewerwidget.h \
|
||||
ui/viewercontainer.h \
|
||||
dialogs/exportdialog.h \
|
||||
ui/collapsiblewidget.h \
|
||||
panels/panels.h \
|
||||
playback/cacher.h \
|
||||
io/exportthread.h \
|
||||
ui/timelinetools.h \
|
||||
ui/timelineheader.h \
|
||||
io/previewgenerator.h \
|
||||
ui/labelslider.h \
|
||||
dialogs/preferencesdialog.h \
|
||||
ui/audiomonitor.h \
|
||||
project/undo.h \
|
||||
ui/scrollarea.h \
|
||||
ui/comboboxex.h \
|
||||
ui/colorbutton.h \
|
||||
dialogs/replaceclipmediadialog.h \
|
||||
ui/fontcombobox.h \
|
||||
ui/checkboxex.h \
|
||||
ui/keyframeview.h \
|
||||
ui/texteditex.h \
|
||||
dialogs/demonotice.h \
|
||||
project/marker.h \
|
||||
project/selection.h \
|
||||
dialogs/speeddialog.h \
|
||||
dialogs/mediapropertiesdialog.h \
|
||||
io/crc32.h \
|
||||
project/projectmodel.h \
|
||||
io/loadthread.h \
|
||||
dialogs/loaddialog.h \
|
||||
debug.h \
|
||||
io/path.h \
|
||||
effects/internal/transformeffect.h \
|
||||
effects/internal/solideffect.h \
|
||||
effects/internal/texteffect.h \
|
||||
effects/internal/timecodeeffect.h \
|
||||
effects/internal/audionoiseeffect.h \
|
||||
effects/internal/paneffect.h \
|
||||
effects/internal/toneeffect.h \
|
||||
effects/internal/volumeeffect.h \
|
||||
effects/internal/shakeeffect.h \
|
||||
effects/internal/linearfadetransition.h \
|
||||
effects/internal/crossdissolvetransition.h \
|
||||
effects/internal/exponentialfadetransition.h \
|
||||
effects/internal/logarithmicfadetransition.h \
|
||||
effects/internal/cornerpineffect.h \
|
||||
io/math.h \
|
||||
io/qpainterwrapper.h \
|
||||
project/effect.h \
|
||||
project/transition.h \
|
||||
project/effectrow.h \
|
||||
project/effectfield.h \
|
||||
effects/internal/cubetransition.h \
|
||||
project/effectgizmo.h \
|
||||
io/clipboard.h \
|
||||
dialogs/stabilizerdialog.h \
|
||||
io/avtogl.h \
|
||||
ui/resizablescrollbar.h
|
||||
|
||||
FORMS += \
|
||||
mainwindow.ui \
|
||||
panels/effectcontrols.ui \
|
||||
panels/viewer.ui \
|
||||
panels/timeline.ui \
|
||||
dialogs/aboutdialog.ui \
|
||||
dialogs/newsequencedialog.ui \
|
||||
dialogs/exportdialog.ui \
|
||||
dialogs/preferencesdialog.ui \
|
||||
dialogs/demonotice.ui
|
||||
|
||||
win32 {
|
||||
RC_FILE = icons/resources.rc
|
||||
LIBS += -lavutil -lavformat -lavcodec -lavfilter -lswscale -lswresample -lopengl32
|
||||
}
|
||||
|
||||
mac {
|
||||
LIBS += -L/usr/local/lib -lavutil -lavformat -lavcodec -lavfilter -lswscale -lswresample
|
||||
ICON = icons/olive.icns
|
||||
INCLUDEPATH = /usr/local/include
|
||||
}
|
||||
|
||||
linux {
|
||||
CONFIG += link_pkgconfig
|
||||
PKGCONFIG += libavutil libavformat libavcodec libavfilter libswscale libswresample
|
||||
}
|
||||
|
||||
RESOURCES += \
|
||||
icons/icons.qrc
|
||||
#-------------------------------------------------
|
||||
#
|
||||
# Project created by QtCreator 2018-05-11T10:31:59
|
||||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
QT += core gui multimedia opengl
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
mac {
|
||||
TARGET = Olive
|
||||
}
|
||||
!mac {
|
||||
TARGET = olive-editor
|
||||
}
|
||||
TEMPLATE = app
|
||||
|
||||
# The following define makes your compiler emit warnings if you use
|
||||
# any feature of Qt which has been marked as deprecated (the exact warnings
|
||||
# depend on your compiler). Please consult the documentation of the
|
||||
# deprecated API in order to know how to port your code away from it.
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
# You can also make your code fail to compile if you use deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
mainwindow.cpp \
|
||||
panels/project.cpp \
|
||||
panels/effectcontrols.cpp \
|
||||
panels/viewer.cpp \
|
||||
panels/timeline.cpp \
|
||||
ui/sourcetable.cpp \
|
||||
dialogs/aboutdialog.cpp \
|
||||
ui/timelinewidget.cpp \
|
||||
project/media.cpp \
|
||||
project/footage.cpp \
|
||||
project/sequence.cpp \
|
||||
project/clip.cpp \
|
||||
playback/playback.cpp \
|
||||
playback/audio.cpp \
|
||||
io/config.cpp \
|
||||
dialogs/newsequencedialog.cpp \
|
||||
ui/viewerwidget.cpp \
|
||||
ui/viewercontainer.cpp \
|
||||
dialogs/exportdialog.cpp \
|
||||
ui/collapsiblewidget.cpp \
|
||||
panels/panels.cpp \
|
||||
playback/cacher.cpp \
|
||||
io/exportthread.cpp \
|
||||
ui/timelineheader.cpp \
|
||||
io/previewgenerator.cpp \
|
||||
ui/labelslider.cpp \
|
||||
dialogs/preferencesdialog.cpp \
|
||||
ui/audiomonitor.cpp \
|
||||
project/undo.cpp \
|
||||
ui/scrollarea.cpp \
|
||||
ui/comboboxex.cpp \
|
||||
ui/colorbutton.cpp \
|
||||
dialogs/replaceclipmediadialog.cpp \
|
||||
ui/fontcombobox.cpp \
|
||||
ui/checkboxex.cpp \
|
||||
ui/keyframeview.cpp \
|
||||
ui/texteditex.cpp \
|
||||
dialogs/demonotice.cpp \
|
||||
project/marker.cpp \
|
||||
dialogs/speeddialog.cpp \
|
||||
dialogs/mediapropertiesdialog.cpp \
|
||||
io/crc32.cpp \
|
||||
project/projectmodel.cpp \
|
||||
io/loadthread.cpp \
|
||||
dialogs/loaddialog.cpp \
|
||||
debug.cpp \
|
||||
io/path.cpp \
|
||||
effects/internal/linearfadetransition.cpp \
|
||||
effects/internal/transformeffect.cpp \
|
||||
effects/internal/solideffect.cpp \
|
||||
effects/internal/texteffect.cpp \
|
||||
effects/internal/timecodeeffect.cpp \
|
||||
effects/internal/audionoiseeffect.cpp \
|
||||
effects/internal/paneffect.cpp \
|
||||
effects/internal/toneeffect.cpp \
|
||||
effects/internal/volumeeffect.cpp \
|
||||
effects/internal/crossdissolvetransition.cpp \
|
||||
effects/internal/shakeeffect.cpp \
|
||||
effects/internal/exponentialfadetransition.cpp \
|
||||
effects/internal/logarithmicfadetransition.cpp \
|
||||
effects/internal/cornerpineffect.cpp \
|
||||
io/math.cpp \
|
||||
io/qpainterwrapper.cpp \
|
||||
project/effect.cpp \
|
||||
project/transition.cpp \
|
||||
project/effectrow.cpp \
|
||||
project/effectfield.cpp \
|
||||
effects/internal/cubetransition.cpp \
|
||||
project/effectgizmo.cpp \
|
||||
io/clipboard.cpp \
|
||||
dialogs/stabilizerdialog.cpp \
|
||||
io/avtogl.cpp \
|
||||
ui/resizablescrollbar.cpp \
|
||||
ui/sourceiconview.cpp \
|
||||
project/sourcescommon.cpp
|
||||
|
||||
HEADERS += \
|
||||
mainwindow.h \
|
||||
panels/project.h \
|
||||
panels/effectcontrols.h \
|
||||
panels/viewer.h \
|
||||
panels/timeline.h \
|
||||
ui/sourcetable.h \
|
||||
dialogs/aboutdialog.h \
|
||||
ui/timelinewidget.h \
|
||||
project/media.h \
|
||||
project/footage.h \
|
||||
project/sequence.h \
|
||||
project/clip.h \
|
||||
playback/playback.h \
|
||||
playback/audio.h \
|
||||
io/config.h \
|
||||
dialogs/newsequencedialog.h \
|
||||
ui/viewerwidget.h \
|
||||
ui/viewercontainer.h \
|
||||
dialogs/exportdialog.h \
|
||||
ui/collapsiblewidget.h \
|
||||
panels/panels.h \
|
||||
playback/cacher.h \
|
||||
io/exportthread.h \
|
||||
ui/timelinetools.h \
|
||||
ui/timelineheader.h \
|
||||
io/previewgenerator.h \
|
||||
ui/labelslider.h \
|
||||
dialogs/preferencesdialog.h \
|
||||
ui/audiomonitor.h \
|
||||
project/undo.h \
|
||||
ui/scrollarea.h \
|
||||
ui/comboboxex.h \
|
||||
ui/colorbutton.h \
|
||||
dialogs/replaceclipmediadialog.h \
|
||||
ui/fontcombobox.h \
|
||||
ui/checkboxex.h \
|
||||
ui/keyframeview.h \
|
||||
ui/texteditex.h \
|
||||
dialogs/demonotice.h \
|
||||
project/marker.h \
|
||||
project/selection.h \
|
||||
dialogs/speeddialog.h \
|
||||
dialogs/mediapropertiesdialog.h \
|
||||
io/crc32.h \
|
||||
project/projectmodel.h \
|
||||
io/loadthread.h \
|
||||
dialogs/loaddialog.h \
|
||||
debug.h \
|
||||
io/path.h \
|
||||
effects/internal/transformeffect.h \
|
||||
effects/internal/solideffect.h \
|
||||
effects/internal/texteffect.h \
|
||||
effects/internal/timecodeeffect.h \
|
||||
effects/internal/audionoiseeffect.h \
|
||||
effects/internal/paneffect.h \
|
||||
effects/internal/toneeffect.h \
|
||||
effects/internal/volumeeffect.h \
|
||||
effects/internal/shakeeffect.h \
|
||||
effects/internal/linearfadetransition.h \
|
||||
effects/internal/crossdissolvetransition.h \
|
||||
effects/internal/exponentialfadetransition.h \
|
||||
effects/internal/logarithmicfadetransition.h \
|
||||
effects/internal/cornerpineffect.h \
|
||||
io/math.h \
|
||||
io/qpainterwrapper.h \
|
||||
project/effect.h \
|
||||
project/transition.h \
|
||||
project/effectrow.h \
|
||||
project/effectfield.h \
|
||||
effects/internal/cubetransition.h \
|
||||
project/effectgizmo.h \
|
||||
io/clipboard.h \
|
||||
dialogs/stabilizerdialog.h \
|
||||
io/avtogl.h \
|
||||
ui/resizablescrollbar.h \
|
||||
ui/sourceiconview.h \
|
||||
project/sourcescommon.h
|
||||
|
||||
FORMS += \
|
||||
mainwindow.ui \
|
||||
panels/effectcontrols.ui \
|
||||
panels/viewer.ui \
|
||||
panels/timeline.ui \
|
||||
dialogs/aboutdialog.ui \
|
||||
dialogs/newsequencedialog.ui \
|
||||
dialogs/exportdialog.ui \
|
||||
dialogs/preferencesdialog.ui \
|
||||
dialogs/demonotice.ui
|
||||
|
||||
win32 {
|
||||
RC_FILE = icons/resources.rc
|
||||
LIBS += -lavutil -lavformat -lavcodec -lavfilter -lswscale -lswresample -lopengl32
|
||||
}
|
||||
|
||||
mac {
|
||||
LIBS += -L/usr/local/lib -lavutil -lavformat -lavcodec -lavfilter -lswscale -lswresample
|
||||
ICON = icons/olive.icns
|
||||
INCLUDEPATH = /usr/local/include
|
||||
}
|
||||
|
||||
unix:!mac {
|
||||
CONFIG += link_pkgconfig
|
||||
PKGCONFIG += libavutil libavformat libavcodec libavfilter libswscale libswresample
|
||||
}
|
||||
|
||||
RESOURCES += \
|
||||
icons/icons.qrc
|
||||
|
||||
unix:!mac {
|
||||
metainfo.files = $$PWD/packaging/linux/org.olivevideoeditor.Olive.appdata.xml
|
||||
metainfo.path = $$PREFIX/share/metainfo
|
||||
desktop.files = $$PWD/packaging/linux/org.olivevideoeditor.Olive.desktop
|
||||
desktop.path = $$PREFIX/share/applications
|
||||
mime.files = $$PWD/packaging/linux/org.olivevideoeditor.Olive.xml
|
||||
mime.path = $$PREFIX/share/mime/packages
|
||||
icon16.files = $$PWD/packaging/linux/icons/16x16/org.olivevideoeditor.Olive.png
|
||||
icon16.path = $$PREFIX/share/icons/hicolor/16x16/apps
|
||||
icon32.files = $$PWD/packaging/linux/icons/32x32/org.olivevideoeditor.Olive.png
|
||||
icon32.path = $$PREFIX/share/icons/hicolor/32x32/apps
|
||||
icon48.files = $$PWD/packaging/linux/icons/48x48/org.olivevideoeditor.Olive.png
|
||||
icon48.path = $$PREFIX/share/icons/hicolor/48x48/apps
|
||||
icon64.files = $$PWD/packaging/linux/icons/64x64/org.olivevideoeditor.Olive.png
|
||||
icon64.path = $$PREFIX/share/icons/hicolor/64x64/apps
|
||||
icon128.files = $$PWD/packaging/linux/icons/128x128/org.olivevideoeditor.Olive.png
|
||||
icon128.path = $$PREFIX/share/icons/hicolor/128x128/apps
|
||||
icon256.files = $$PWD/packaging/linux/icons/256x256/org.olivevideoeditor.Olive.png
|
||||
icon256.path = $$PREFIX/share/icons/hicolor/256x256/apps
|
||||
icon512.files = $$PWD/packaging/linux/icons/512x512/org.olivevideoeditor.Olive.png
|
||||
icon512.path = $$PREFIX/share/icons/hicolor/512x512/apps
|
||||
icon1024.files = $$PWD/packaging/linux/icons/1024x1024/org.olivevideoeditor.Olive.png
|
||||
icon1024.path = $$PREFIX/share/icons/hicolor/1024x1024/apps
|
||||
INSTALLS += metainfo desktop mime icon16 icon32 icon48 icon64 icon128 icon256 icon512 icon1024
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 198 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop">
|
||||
<id>org.olivevideoeditor.Olive</id>
|
||||
<name>Olive</name>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>GPLv3</project_license>
|
||||
<developer_name>Olive Team</developer_name>
|
||||
<summary>NLE video editor</summary>
|
||||
<description>
|
||||
<p>
|
||||
Olive is a professional open-source NLE video editor.
|
||||
</p>
|
||||
</description>
|
||||
<url type="homepage">https://www.olivevideoeditor.org</url>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image>http://images.libregraphicsworld.org/video/2018/12/introducing-olive/olive-alpha-main-window.jpg</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<content_rating type="oars-1.1" />
|
||||
<releases>
|
||||
<release version="20181223" date="2018-12-23"></release>
|
||||
<release version="20181130" date="2018-11-30"></release>
|
||||
</releases>
|
||||
</component>
|
||||
@@ -0,0 +1,10 @@
|
||||
[Desktop Entry]
|
||||
Name=Olive
|
||||
Comment=Professional open-source NLE video editor
|
||||
Exec=olive-editor
|
||||
Icon=org.olivevideoeditor.Olive
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=AudioVideo;Recorder;
|
||||
MimeType=application/vnd.olive-project;
|
||||
StartupNotify=true
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0"?>
|
||||
<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
|
||||
<mime-type type="application/vnd.olive-project">
|
||||
<comment>Olive project</comment>
|
||||
<glob pattern="*.ove"/>
|
||||
</mime-type>
|
||||
</mime-info>
|
||||
@@ -20,6 +20,9 @@ class QXmlStreamReader;
|
||||
class QFile;
|
||||
class QSortFilterProxyModel;
|
||||
class ComboAction;
|
||||
class SourceIconView;
|
||||
class QPushButton;
|
||||
class SourcesCommon;
|
||||
|
||||
#define LOAD_TYPE_VERSION 69
|
||||
#define LOAD_TYPE_URL 70
|
||||
@@ -40,10 +43,8 @@ Sequence* create_sequence_from_media(QVector<Media *> &media_list);
|
||||
QString get_channel_layout_name(int channels, uint64_t layout);
|
||||
QString get_interlacing_name(int interlacing);
|
||||
|
||||
class Project : public QDockWidget
|
||||
{
|
||||
class Project : public QDockWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Project(QWidget *parent = 0);
|
||||
~Project();
|
||||
@@ -54,7 +55,7 @@ public:
|
||||
void process_file_list(QStringList& files, bool recursive = false, Media* replace = NULL, Media *parent = NULL);
|
||||
void replace_media(Media* item, QString filename);
|
||||
Media *get_selected_folder();
|
||||
bool reveal_media(void* media, QModelIndex parent = QModelIndex());
|
||||
bool reveal_media(Media *media, QModelIndex parent = QModelIndex());
|
||||
void add_recent_project(QString url);
|
||||
|
||||
void new_project();
|
||||
@@ -68,7 +69,10 @@ public:
|
||||
|
||||
QVector<Media*> list_all_project_sequences();
|
||||
|
||||
SourceTable* source_table;
|
||||
SourceTable* tree_view;
|
||||
SourceIconView* icon_view;
|
||||
SourcesCommon* sources_common;
|
||||
|
||||
QSortFilterProxyModel* sorter;
|
||||
|
||||
QVector<Media*> last_imported_media;
|
||||
@@ -93,8 +97,16 @@ private:
|
||||
void list_all_sequences_worker(QVector<Media *> *list, Media* parent);
|
||||
QString get_file_name_from_path(const QString &path);
|
||||
QDir proj_dir;
|
||||
QWidget* icon_view_container;
|
||||
QPushButton* directory_up;
|
||||
private slots:
|
||||
void update_view_type();
|
||||
void set_icon_view();
|
||||
void set_tree_view();
|
||||
void clear_recent_projects();
|
||||
void set_icon_view_size(int);
|
||||
void set_up_dir_enabled();
|
||||
void go_up_dir();
|
||||
};
|
||||
|
||||
class MediaThrobber : public QObject {
|
||||
|
||||
@@ -1,105 +1,105 @@
|
||||
#ifndef VIEWER_H
|
||||
#define VIEWER_H
|
||||
|
||||
#include <QDockWidget>
|
||||
#include <QTimer>
|
||||
|
||||
class Timeline;
|
||||
class ViewerWidget;
|
||||
class Media;
|
||||
struct Sequence;
|
||||
|
||||
namespace Ui {
|
||||
class Viewer;
|
||||
}
|
||||
|
||||
bool frame_rate_is_droppable(float rate);
|
||||
long timecode_to_frame(const QString& s, int view, double frame_rate);
|
||||
QString frame_to_timecode(long f, int view, double frame_rate);
|
||||
|
||||
class Viewer : public QDockWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Viewer(QWidget *parent = 0);
|
||||
~Viewer();
|
||||
|
||||
bool is_focused();
|
||||
void set_main_sequence();
|
||||
void set_media(Media *m);
|
||||
void compose();
|
||||
void set_playpause_icon(bool play);
|
||||
void update_playhead_timecode(long p);
|
||||
void update_end_timecode();
|
||||
void update_header_zoom();
|
||||
void update_viewer();
|
||||
void clear_inout_point();
|
||||
void set_in_point();
|
||||
void set_out_point();
|
||||
void set_zoom(bool in);
|
||||
|
||||
// playback functions
|
||||
void go_to_start();
|
||||
void previous_frame();
|
||||
void next_frame();
|
||||
void seek(long p);
|
||||
void toggle_play();
|
||||
void play();
|
||||
void pause();
|
||||
void go_to_end();
|
||||
bool playing;
|
||||
long playhead_start;
|
||||
qint64 start_msecs;
|
||||
QTimer playback_updater;
|
||||
bool just_played;
|
||||
|
||||
void cue_recording(long start, long end, int track);
|
||||
void uncue_recording();
|
||||
bool is_recording_cued();
|
||||
long recording_start;
|
||||
long recording_end;
|
||||
int recording_track;
|
||||
|
||||
void reset_all_audio();
|
||||
void update_parents();
|
||||
|
||||
ViewerWidget* viewer_widget;
|
||||
|
||||
Media* media;
|
||||
Sequence* seq;
|
||||
|
||||
Ui::Viewer *ui;
|
||||
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
|
||||
public slots:
|
||||
void play_wake();
|
||||
|
||||
private slots:
|
||||
void on_pushButton_clicked();
|
||||
void on_pushButton_5_clicked();
|
||||
void on_pushButton_2_clicked();
|
||||
void on_pushButton_4_clicked();
|
||||
void on_pushButton_3_clicked();
|
||||
void update_playhead();
|
||||
void timer_update();
|
||||
void recording_flasher_update();
|
||||
void zoom_update(int i);
|
||||
void resize_move(double d);
|
||||
private:
|
||||
void clean_created_seq();
|
||||
void set_sequence(bool main, Sequence* s);
|
||||
bool main_sequence;
|
||||
bool created_sequence;
|
||||
long cached_end_frame;
|
||||
QString panel_name;
|
||||
double minimum_zoom;
|
||||
void set_zoom_value(double d);
|
||||
void set_sb_max();
|
||||
|
||||
bool cue_recording_internal;
|
||||
QTimer recording_flasher;
|
||||
};
|
||||
|
||||
#endif // VIEWER_H
|
||||
#ifndef VIEWER_H
|
||||
#define VIEWER_H
|
||||
|
||||
#include <QDockWidget>
|
||||
#include <QTimer>
|
||||
|
||||
class Timeline;
|
||||
class ViewerWidget;
|
||||
class Media;
|
||||
struct Sequence;
|
||||
|
||||
namespace Ui {
|
||||
class Viewer;
|
||||
}
|
||||
|
||||
bool frame_rate_is_droppable(float rate);
|
||||
long timecode_to_frame(const QString& s, int view, double frame_rate);
|
||||
QString frame_to_timecode(long f, int view, double frame_rate);
|
||||
|
||||
class Viewer : public QDockWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Viewer(QWidget *parent = 0);
|
||||
~Viewer();
|
||||
|
||||
bool is_focused();
|
||||
void set_main_sequence();
|
||||
void set_media(Media *m);
|
||||
void compose();
|
||||
void set_playpause_icon(bool play);
|
||||
void update_playhead_timecode(long p);
|
||||
void update_end_timecode();
|
||||
void update_header_zoom();
|
||||
void update_viewer();
|
||||
void clear_inout_point();
|
||||
void set_in_point();
|
||||
void set_out_point();
|
||||
void set_zoom(bool in);
|
||||
|
||||
// playback functions
|
||||
void go_to_start();
|
||||
void previous_frame();
|
||||
void next_frame();
|
||||
void seek(long p);
|
||||
void toggle_play();
|
||||
void play();
|
||||
void pause();
|
||||
void go_to_end();
|
||||
bool playing;
|
||||
long playhead_start;
|
||||
qint64 start_msecs;
|
||||
QTimer playback_updater;
|
||||
bool just_played;
|
||||
|
||||
void cue_recording(long start, long end, int track);
|
||||
void uncue_recording();
|
||||
bool is_recording_cued();
|
||||
long recording_start;
|
||||
long recording_end;
|
||||
int recording_track;
|
||||
|
||||
void reset_all_audio();
|
||||
void update_parents();
|
||||
|
||||
ViewerWidget* viewer_widget;
|
||||
|
||||
Media* media;
|
||||
Sequence* seq;
|
||||
|
||||
Ui::Viewer *ui;
|
||||
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
|
||||
public slots:
|
||||
void play_wake();
|
||||
|
||||
private slots:
|
||||
void on_pushButton_clicked();
|
||||
void on_pushButton_5_clicked();
|
||||
void on_pushButton_2_clicked();
|
||||
void on_pushButton_4_clicked();
|
||||
void on_pushButton_3_clicked();
|
||||
void update_playhead();
|
||||
void timer_update();
|
||||
void recording_flasher_update();
|
||||
void zoom_update(int i);
|
||||
void resize_move(double d);
|
||||
private:
|
||||
void clean_created_seq();
|
||||
void set_sequence(bool main, Sequence* s);
|
||||
bool main_sequence;
|
||||
bool created_sequence;
|
||||
long cached_end_frame;
|
||||
QString panel_name;
|
||||
double minimum_zoom;
|
||||
void set_zoom_value(double d);
|
||||
void set_sb_max();
|
||||
|
||||
bool cue_recording_internal;
|
||||
QTimer recording_flasher;
|
||||
};
|
||||
|
||||
#endif // VIEWER_H
|
||||
|
||||
@@ -70,99 +70,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="zoomControlBar" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>260</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="zoomComboBox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Fit</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>10%</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>25%</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>50%</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>75%</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>100%</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>150%</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>200%</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>400%</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>259</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="playbackControls" native="true">
|
||||
<property name="sizePolicy">
|
||||
|
||||
@@ -109,7 +109,12 @@ void Clip::refresh() {
|
||||
// validates media if it was replaced
|
||||
if (replaced && media != NULL && media->get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
Footage* m = media->to_footage();
|
||||
media_stream = (track < 0) ? m->video_tracks.at(0)->file_index : m->audio_tracks.at(0)->file_index;
|
||||
|
||||
if (track < 0 && m->video_tracks.size() > 0) {
|
||||
media_stream = m->video_tracks.at(0)->file_index;
|
||||
} else if (track >= 0 && m->audio_tracks.size() > 0) {
|
||||
media_stream = m->audio_tracks.at(0)->file_index;
|
||||
}
|
||||
}
|
||||
replaced = false;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <QDebug>
|
||||
#include <QtMath>
|
||||
#include <QPainter>
|
||||
#include "io/previewgenerator.h"
|
||||
|
||||
extern "C" {
|
||||
@@ -55,3 +56,16 @@ FootageStream* Footage::get_stream_from_file_index(bool video, int index) {
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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);
|
||||
video_preview_square = QIcon(pixmap);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <QVariant>
|
||||
#include <QMutex>
|
||||
#include <QPixmap>
|
||||
#include <QIcon>
|
||||
|
||||
#define VIDEO_PROGRESSIVE 0
|
||||
#define VIDEO_TOP_FIELD_FIRST 1
|
||||
@@ -32,7 +33,9 @@ struct FootageStream {
|
||||
// preview thumbnail/waveform
|
||||
bool preview_done;
|
||||
QImage video_preview;
|
||||
QIcon video_preview_square;
|
||||
QVector<char> audio_preview;
|
||||
void make_square_thumb();
|
||||
};
|
||||
|
||||
struct Footage {
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "panels/project.h"
|
||||
#include "projectmodel.h"
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
extern "C" {
|
||||
@@ -253,6 +255,14 @@ QVariant Media::data(int column, int role) {
|
||||
switch (role) {
|
||||
case Qt::DecorationRole:
|
||||
if (column == 0) {
|
||||
if (get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
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 icon;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,280 @@
|
||||
#include "sourcescommon.h"
|
||||
|
||||
#include "panels/panels.h"
|
||||
#include "project/media.h"
|
||||
#include "project/undo.h"
|
||||
#include "panels/timeline.h"
|
||||
#include "panels/project.h"
|
||||
#include "project/footage.h"
|
||||
#include "panels/viewer.h"
|
||||
#include "io/config.h"
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QProcess>
|
||||
#include <QMenu>
|
||||
#include <QAbstractItemView>
|
||||
#include <QMimeData>
|
||||
#include <QMessageBox>
|
||||
#include <QDesktopServices>
|
||||
|
||||
SourcesCommon::SourcesCommon(Project* parent) :
|
||||
project_parent(parent),
|
||||
editing_item(NULL)
|
||||
{
|
||||
rename_timer.setInterval(1000);
|
||||
connect(&rename_timer, SIGNAL(timeout()), this, SLOT(rename_interval()));
|
||||
}
|
||||
|
||||
void SourcesCommon::create_seq_from_selected() {
|
||||
if (!selected_items.isEmpty()) {
|
||||
QVector<Media*> media_list;
|
||||
for (int i=0;i<selected_items.size();i++) {
|
||||
media_list.append(project_parent->item_to_media(selected_items.at(i)));
|
||||
}
|
||||
|
||||
ComboAction* ca = new ComboAction();
|
||||
Sequence* s = create_sequence_from_media(media_list);
|
||||
|
||||
// add clips to it
|
||||
panel_timeline->create_ghosts_from_media(s, 0, media_list);
|
||||
panel_timeline->add_clips_from_ghosts(ca, s);
|
||||
|
||||
project_parent->new_sequence(ca, s, true, NULL);
|
||||
undo_stack.push(ca);
|
||||
}
|
||||
}
|
||||
|
||||
void SourcesCommon::show_context_menu(QWidget* parent, const QModelIndexList& items) {
|
||||
QMenu menu(parent);
|
||||
|
||||
selected_items = items;
|
||||
|
||||
QAction* import_action = menu.addAction("Import...");
|
||||
QObject::connect(import_action, SIGNAL(triggered(bool)), project_parent, SLOT(import_dialog()));
|
||||
|
||||
QAction* new_folder_action = menu.addAction("New Folder...");
|
||||
QObject::connect(new_folder_action, SIGNAL(triggered(bool)), mainWindow, SLOT(on_actionFolder_triggered()));
|
||||
|
||||
if (items.size() > 0) {
|
||||
Media* m = project_parent->item_to_media(items.at(0));
|
||||
|
||||
if (items.size() == 1) {
|
||||
// replace footage
|
||||
int type = m->get_type();
|
||||
if (type == MEDIA_TYPE_FOOTAGE) {
|
||||
QAction* replace_action = menu.addAction("Replace/Relink Media");
|
||||
QObject::connect(replace_action, SIGNAL(triggered(bool)), project_parent, SLOT(replace_selected_file()));
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
QAction* reveal_in_explorer = menu.addAction("Reveal in Explorer");
|
||||
#elif defined(Q_OS_MAC)
|
||||
QAction* reveal_in_explorer = menu.addAction("Reveal in Finder");
|
||||
#else
|
||||
QAction* reveal_in_explorer = menu.addAction("Reveal in File Manager");
|
||||
#endif
|
||||
QObject::connect(reveal_in_explorer, SIGNAL(triggered(bool)), this, SLOT(reveal_in_browser()));
|
||||
}
|
||||
if (type != MEDIA_TYPE_FOLDER) {
|
||||
QAction* replace_clip_media = menu.addAction("Replace Clips Using This Media");
|
||||
QObject::connect(replace_clip_media, SIGNAL(triggered(bool)), project_parent, SLOT(replace_clip_media()));
|
||||
}
|
||||
}
|
||||
|
||||
// duplicate item
|
||||
bool all_sequences = true;
|
||||
bool all_footage = true;
|
||||
for (int i=0;i<items.size();i++) {
|
||||
if (m->get_type() != MEDIA_TYPE_SEQUENCE) {
|
||||
all_sequences = false;
|
||||
}
|
||||
if (m->get_type() != MEDIA_TYPE_FOOTAGE) {
|
||||
all_footage = false;
|
||||
}
|
||||
}
|
||||
|
||||
// create sequence from
|
||||
QAction* create_seq_from = menu.addAction("Create Sequence With This Media");
|
||||
QObject::connect(create_seq_from, SIGNAL(triggered(bool)), this, SLOT(create_seq_from_selected()));
|
||||
|
||||
// ONLY sequences are selected
|
||||
if (all_sequences) {
|
||||
// ONLY sequences are selected
|
||||
QAction* duplicate_action = menu.addAction("Duplicate");
|
||||
QObject::connect(duplicate_action, SIGNAL(triggered(bool)), project_parent, SLOT(duplicate_selected()));
|
||||
}
|
||||
|
||||
// ONLY footage is selected
|
||||
if (all_footage) {
|
||||
QAction* delete_footage_from_sequences = menu.addAction("Delete All Clips Using This Media");
|
||||
QObject::connect(delete_footage_from_sequences, SIGNAL(triggered(bool)), project_parent, SLOT(delete_clips_using_selected_media()));
|
||||
}
|
||||
|
||||
// delete media
|
||||
QAction* delete_action = menu.addAction("Delete");
|
||||
QObject::connect(delete_action, SIGNAL(triggered(bool)), project_parent, SLOT(delete_selected_media()));
|
||||
|
||||
if (items.size() == 1) {
|
||||
QAction* properties_action = menu.addAction("Properties...");
|
||||
QObject::connect(properties_action, SIGNAL(triggered(bool)), project_parent, SLOT(open_properties()));
|
||||
}
|
||||
}
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
QAction* tree_view_action = menu.addAction("Tree View");
|
||||
connect(tree_view_action, SIGNAL(triggered(bool)), project_parent, SLOT(set_tree_view()));
|
||||
|
||||
QAction* icon_view_action = menu.addAction("Icon View");
|
||||
connect(icon_view_action, SIGNAL(triggered(bool)), project_parent, SLOT(set_icon_view()));
|
||||
|
||||
menu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
void SourcesCommon::mousePressEvent(QMouseEvent *) {
|
||||
stop_rename_timer();
|
||||
}
|
||||
|
||||
void SourcesCommon::item_click(Media *m, const QModelIndex& index) {
|
||||
if (editing_item == m) {
|
||||
rename_timer.start();
|
||||
} else {
|
||||
editing_item = m;
|
||||
editing_index = index;
|
||||
}
|
||||
}
|
||||
|
||||
void SourcesCommon::mouseDoubleClickEvent(QMouseEvent *e, const QModelIndexList& selected_items) {
|
||||
stop_rename_timer();
|
||||
if (selected_items.size() == 0) {
|
||||
project_parent->import_dialog();
|
||||
} else if (selected_items.size() == 1) {
|
||||
Media* item = project_parent->item_to_media(selected_items.at(0));
|
||||
switch (item->get_type()) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
panel_footage_viewer->set_media(item);
|
||||
panel_footage_viewer->setFocus();
|
||||
break;
|
||||
case MEDIA_TYPE_SEQUENCE:
|
||||
undo_stack.push(new ChangeSequenceAction(item->to_sequence()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SourcesCommon::dropEvent(QWidget* parent, QDropEvent *event, const QModelIndex& drop_item, const QModelIndexList& items) {
|
||||
const QMimeData* mimeData = event->mimeData();
|
||||
Media* m = project_parent->item_to_media(drop_item);
|
||||
if (mimeData->hasUrls()) {
|
||||
// drag files in from outside
|
||||
QList<QUrl> urls = mimeData->urls();
|
||||
if (!urls.isEmpty()) {
|
||||
QStringList paths;
|
||||
for (int i=0;i<urls.size();i++) {
|
||||
paths.append(urls.at(i).toLocalFile());
|
||||
}
|
||||
bool replace = false;
|
||||
if (urls.size() == 1
|
||||
&& drop_item.isValid()
|
||||
&& m->get_type() == MEDIA_TYPE_FOOTAGE
|
||||
&& !QFileInfo(paths.at(0)).isDir()
|
||||
&& config.drop_on_media_to_replace
|
||||
&& QMessageBox::question(parent, "Replace Media", "You dropped a file onto '" + m->get_name() + "'. Would you like to replace it with the dropped file?", QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) {
|
||||
replace = true;
|
||||
project_parent->replace_media(m, paths.at(0));
|
||||
}
|
||||
if (!replace) {
|
||||
QModelIndex parent;
|
||||
if (drop_item.isValid()) {
|
||||
if (m->get_type() == MEDIA_TYPE_FOLDER) {
|
||||
parent = drop_item;
|
||||
} else {
|
||||
parent = drop_item.parent();
|
||||
}
|
||||
}
|
||||
project_parent->process_file_list(paths, false, NULL, panel_project->item_to_media(parent));
|
||||
}
|
||||
}
|
||||
event->acceptProposedAction();
|
||||
} else {
|
||||
event->ignore();
|
||||
|
||||
// dragging files within project
|
||||
// if we dragged to the root OR dragged to a folder
|
||||
if (!drop_item.isValid() || (drop_item.isValid() && m->get_type() == MEDIA_TYPE_FOLDER)) {
|
||||
QVector<Media*> move_items;
|
||||
for (int i=0;i<items.size();i++) {
|
||||
const QModelIndex& item = items.at(i);
|
||||
const QModelIndex& parent = item.parent();
|
||||
Media* s = project_parent->item_to_media(item);
|
||||
if (parent != drop_item && item != drop_item) {
|
||||
bool ignore = false;
|
||||
if (parent.isValid()) {
|
||||
// if child belongs to a selected parent, assume the user is just moving the parent and ignore the child
|
||||
QModelIndex par = parent;
|
||||
while (par.isValid() && !ignore) {
|
||||
for (int j=0;j<items.size();j++) {
|
||||
if (par == items.at(j)) {
|
||||
ignore = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
par = par.parent();
|
||||
}
|
||||
}
|
||||
if (!ignore) {
|
||||
move_items.append(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (move_items.size() > 0) {
|
||||
MediaMove* mm = new MediaMove();
|
||||
mm->to = m;
|
||||
mm->items = move_items;
|
||||
undo_stack.push(mm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SourcesCommon::reveal_in_browser() {
|
||||
Media* media = project_parent->item_to_media(selected_items.at(0));
|
||||
Footage* m = media->to_footage();
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
QStringList args;
|
||||
args << "/select," << QDir::toNativeSeparators(m->url);
|
||||
QProcess::startDetached("explorer", args);
|
||||
#elif defined(Q_OS_MAC)
|
||||
QStringList args;
|
||||
args << "-e";
|
||||
args << "tell application \"Finder\"";
|
||||
args << "-e";
|
||||
args << "activate";
|
||||
args << "-e";
|
||||
args << "select POSIX file \""+m->url+"\"";
|
||||
args << "-e";
|
||||
args << "end tell";
|
||||
QProcess::startDetached("osascript", args);
|
||||
#else
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(m->url.left(m->url.lastIndexOf('/'))));
|
||||
#endif
|
||||
}
|
||||
|
||||
void SourcesCommon::stop_rename_timer() {
|
||||
rename_timer.stop();
|
||||
}
|
||||
|
||||
void SourcesCommon::rename_interval() {
|
||||
stop_rename_timer();
|
||||
if (view->hasFocus() && editing_item != NULL) {
|
||||
view->edit(editing_index);
|
||||
}
|
||||
}
|
||||
|
||||
void SourcesCommon::item_renamed(Media* item) {
|
||||
if (editing_item == item) {
|
||||
MediaRename* mr = new MediaRename(item, "idk");
|
||||
undo_stack.push(mr);
|
||||
editing_item = NULL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#ifndef SOURCESCOMMON_H
|
||||
#define SOURCESCOMMON_H
|
||||
|
||||
#include <QModelIndexList>
|
||||
#include <QTimer>
|
||||
|
||||
class Project;
|
||||
class QMouseEvent;
|
||||
class Media;
|
||||
class QAbstractItemView;
|
||||
class QDropEvent;
|
||||
|
||||
class SourcesCommon : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
SourcesCommon(Project *parent);
|
||||
QAbstractItemView* view;
|
||||
void show_context_menu(QWidget* parent, const QModelIndexList &items);
|
||||
|
||||
void mousePressEvent(QMouseEvent* e);
|
||||
void mouseDoubleClickEvent(QMouseEvent* e, const QModelIndexList& selected_items);
|
||||
void dropEvent(QWidget *parent, QDropEvent* e, const QModelIndex& drop_item, const QModelIndexList &items);
|
||||
|
||||
void item_click(Media* m, const QModelIndex &index);
|
||||
private slots:
|
||||
void create_seq_from_selected();
|
||||
void reveal_in_browser();
|
||||
void rename_interval();
|
||||
void item_renamed(Media *item);
|
||||
private:
|
||||
Media* editing_item;
|
||||
QModelIndex editing_index;
|
||||
QModelIndexList selected_items;
|
||||
Project* project_parent;
|
||||
void stop_rename_timer();
|
||||
QTimer rename_timer;
|
||||
};
|
||||
|
||||
#endif // SOURCESCOMMON_H
|
||||
@@ -592,6 +592,7 @@ void ReplaceMediaCommand::replace(QString& filename) {
|
||||
// replace media
|
||||
QStringList files;
|
||||
files.append(filename);
|
||||
item->to_footage()->ready_lock.lock();
|
||||
panel_project->process_file_list(files, false, item, NULL);
|
||||
}
|
||||
|
||||
@@ -694,7 +695,7 @@ void EffectDeleteCommand::redo() {
|
||||
mainWindow->setWindowModified(true);
|
||||
}
|
||||
|
||||
MediaMove::MediaMove(SourceTable *s) : table(s), old_project_changed(mainWindow->isWindowModified()) {}
|
||||
MediaMove::MediaMove() : old_project_changed(mainWindow->isWindowModified()) {}
|
||||
|
||||
void MediaMove::undo() {
|
||||
for (int i=0;i<items.size();i++) {
|
||||
|
||||
@@ -302,14 +302,13 @@ private:
|
||||
|
||||
class MediaMove : public QUndoCommand {
|
||||
public:
|
||||
MediaMove(SourceTable* s);
|
||||
MediaMove();
|
||||
QVector<Media*> items;
|
||||
Media* to;
|
||||
void undo();
|
||||
void redo();
|
||||
private:
|
||||
QVector<Media*> froms;
|
||||
SourceTable* table;
|
||||
bool old_project_changed;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#include "otreeview.h"
|
||||
|
||||
OTreeView::OTreeView(QWidget *parent) : QTreeView(parent) {
|
||||
setSortingEnabled(true);
|
||||
sortByColumn(0, Qt::AscendingOrder);
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu()));
|
||||
connect(this, SIGNAL(clicked(const QModelIndex&)), this, SLOT(item_click(const QModelIndex&)));
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef OTREEVIEW_H
|
||||
#define OTREEVIEW_H
|
||||
|
||||
#include <QTreeView>
|
||||
|
||||
#include "ui/sourcetable.h"
|
||||
|
||||
class OTreeView : public QTreeView {
|
||||
Q_OBJECT
|
||||
public:
|
||||
OTreeView(QWidget* parent = 0);
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#endif // OTREEVIEW_H
|
||||
@@ -0,0 +1,67 @@
|
||||
#include "sourceiconview.h"
|
||||
|
||||
#include <QMimeData>
|
||||
|
||||
#include "panels/project.h"
|
||||
#include "project/media.h"
|
||||
#include "project/sourcescommon.h"
|
||||
#include "debug.h"
|
||||
|
||||
SourceIconView::SourceIconView(QWidget *parent) : QListView(parent) {
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(this, SIGNAL(clicked(const QModelIndex&)), this, SLOT(item_click(const QModelIndex&)));
|
||||
connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu()));
|
||||
}
|
||||
|
||||
void SourceIconView::show_context_menu() {
|
||||
project_parent->sources_common->show_context_menu(this, selectedIndexes());
|
||||
}
|
||||
|
||||
void SourceIconView::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);
|
||||
}
|
||||
}
|
||||
|
||||
void SourceIconView::mousePressEvent(QMouseEvent* event) {
|
||||
project_parent->sources_common->mousePressEvent(event);
|
||||
if (!indexAt(event->pos()).isValid()) selectionModel()->clear();
|
||||
QListView::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void SourceIconView::dragEnterEvent(QDragEnterEvent *event) {
|
||||
if (event->mimeData()->hasUrls()) {
|
||||
event->acceptProposedAction();
|
||||
} else {
|
||||
QListView::dragEnterEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void SourceIconView::dragMoveEvent(QDragMoveEvent *event) {
|
||||
if (event->mimeData()->hasUrls()) {
|
||||
event->acceptProposedAction();
|
||||
} else {
|
||||
QListView::dragMoveEvent(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());
|
||||
}
|
||||
|
||||
void SourceIconView::mouseDoubleClickEvent(QMouseEvent *event) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
if (default_behavior) {
|
||||
project_parent->sources_common->mouseDoubleClickEvent(event, selectedIndexes());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef SOURCEICONVIEW_H
|
||||
#define SOURCEICONVIEW_H
|
||||
|
||||
#include <QListView>
|
||||
|
||||
class Project;
|
||||
|
||||
class SourceIconView : public QListView {
|
||||
Q_OBJECT
|
||||
public:
|
||||
SourceIconView(QWidget* parent = 0);
|
||||
Project* project_parent;
|
||||
|
||||
void mousePressEvent(QMouseEvent* event);
|
||||
void mouseDoubleClickEvent(QMouseEvent *event);
|
||||
void dragEnterEvent(QDragEnterEvent *event);
|
||||
void dragMoveEvent(QDragMoveEvent *event);
|
||||
void dropEvent(QDropEvent* event);
|
||||
signals:
|
||||
void changed_root();
|
||||
private slots:
|
||||
void show_context_menu();
|
||||
void item_click(const QModelIndex& index);
|
||||
};
|
||||
|
||||
#endif // SOURCEICONVIEW_H
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "mainwindow.h"
|
||||
#include "io/config.h"
|
||||
#include "project/media.h"
|
||||
#include "project/sourcescommon.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include <QDragEnterEvent>
|
||||
@@ -25,193 +26,30 @@
|
||||
#include <QProcess>
|
||||
|
||||
SourceTable::SourceTable(QWidget* parent) : QTreeView(parent) {
|
||||
editing_item = NULL;
|
||||
setSortingEnabled(true);
|
||||
sortByColumn(0, Qt::AscendingOrder);
|
||||
rename_timer.setInterval(1000);
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(&rename_timer, SIGNAL(timeout()), this, SLOT(rename_interval()));
|
||||
connect(this, SIGNAL(clicked(const QModelIndex&)), this, SLOT(item_click(const QModelIndex&)));
|
||||
connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu()));
|
||||
}
|
||||
|
||||
void SourceTable::show_context_menu() {
|
||||
QMenu menu(this);
|
||||
|
||||
QAction* import_action = menu.addAction("Import...");
|
||||
connect(import_action, SIGNAL(triggered(bool)), project_parent, SLOT(import_dialog()));
|
||||
|
||||
QAction* new_folder_action = menu.addAction("New Folder...");
|
||||
connect(new_folder_action, SIGNAL(triggered(bool)), mainWindow, SLOT(on_actionFolder_triggered()));
|
||||
|
||||
QModelIndexList selected_items = selectionModel()->selectedRows();
|
||||
|
||||
if (selected_items.size() > 0) {
|
||||
Media* m = project_parent->item_to_media(selected_items.at(0));
|
||||
|
||||
if (selected_items.size() == 1) {
|
||||
// replace footage
|
||||
int type = m->get_type();
|
||||
if (type == MEDIA_TYPE_FOOTAGE) {
|
||||
QAction* replace_action = menu.addAction("Replace/Relink Media");
|
||||
connect(replace_action, SIGNAL(triggered(bool)), project_parent, SLOT(replace_selected_file()));
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
QAction* reveal_in_explorer = menu.addAction("Reveal in Explorer");
|
||||
#elif defined(Q_OS_MAC)
|
||||
QAction* reveal_in_explorer = menu.addAction("Reveal in Finder");
|
||||
#else
|
||||
QAction* reveal_in_explorer = menu.addAction("Reveal in File Manager");
|
||||
#endif
|
||||
connect(reveal_in_explorer, SIGNAL(triggered(bool)), this, SLOT(reveal_in_browser()));
|
||||
}
|
||||
if (type != MEDIA_TYPE_FOLDER) {
|
||||
QAction* replace_clip_media = menu.addAction("Replace Clips Using This Media");
|
||||
connect(replace_clip_media, SIGNAL(triggered(bool)), project_parent, SLOT(replace_clip_media()));
|
||||
}
|
||||
}
|
||||
|
||||
// duplicate item
|
||||
bool all_sequences = true;
|
||||
bool all_footage = true;
|
||||
for (int i=0;i<selected_items.size();i++) {
|
||||
if (m->get_type() != MEDIA_TYPE_SEQUENCE) {
|
||||
all_sequences = false;
|
||||
}
|
||||
if (m->get_type() != MEDIA_TYPE_FOOTAGE) {
|
||||
all_footage = false;
|
||||
}
|
||||
}
|
||||
|
||||
// create sequence from
|
||||
QAction* create_seq_from = menu.addAction("Create Sequence With This Media");
|
||||
connect(create_seq_from, SIGNAL(triggered(bool)), this, SLOT(create_seq_from_selected()));
|
||||
|
||||
// ONLY sequences are selected
|
||||
if (all_sequences) {
|
||||
// ONLY sequences are selected
|
||||
QAction* duplicate_action = menu.addAction("Duplicate");
|
||||
connect(duplicate_action, SIGNAL(triggered(bool)), project_parent, SLOT(duplicate_selected()));
|
||||
}
|
||||
|
||||
// ONLY footage is selected
|
||||
if (all_footage) {
|
||||
QAction* delete_footage_from_sequences = menu.addAction("Delete All Clips Using This Media");
|
||||
connect(delete_footage_from_sequences, SIGNAL(triggered(bool)), project_parent, SLOT(delete_clips_using_selected_media()));
|
||||
}
|
||||
|
||||
// delete media
|
||||
QAction* delete_action = menu.addAction("Delete");
|
||||
connect(delete_action, SIGNAL(triggered(bool)), project_parent, SLOT(delete_selected_media()));
|
||||
|
||||
if (selected_items.size() == 1) {
|
||||
QAction* properties_action = menu.addAction("Properties...");
|
||||
connect(properties_action, SIGNAL(triggered(bool)), project_parent, SLOT(open_properties()));
|
||||
}
|
||||
}
|
||||
|
||||
menu.exec(QCursor::pos());
|
||||
project_parent->sources_common->show_context_menu(this, selectionModel()->selectedRows());
|
||||
}
|
||||
|
||||
void SourceTable::create_seq_from_selected() {
|
||||
QModelIndexList selected_items = selectionModel()->selectedRows();
|
||||
|
||||
if (!selected_items.isEmpty()) {
|
||||
QVector<Media*> media_list;
|
||||
for (int i=0;i<selected_items.size();i++) {
|
||||
media_list.append(project_parent->item_to_media(selected_items.at(i)));
|
||||
}
|
||||
|
||||
ComboAction* ca = new ComboAction();
|
||||
Sequence* s = create_sequence_from_media(media_list);
|
||||
|
||||
// add clips to it
|
||||
panel_timeline->create_ghosts_from_media(s, 0, media_list);
|
||||
panel_timeline->add_clips_from_ghosts(ca, s);
|
||||
|
||||
project_parent->new_sequence(ca, s, true, NULL);
|
||||
undo_stack.push(ca);
|
||||
}
|
||||
}
|
||||
|
||||
void SourceTable::reveal_in_browser() {
|
||||
QModelIndexList selected_items = selectionModel()->selectedRows();
|
||||
Media* media = project_parent->item_to_media(selected_items.at(0));
|
||||
Footage* m = media->to_footage();
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
QStringList args;
|
||||
args << "/select," << QDir::toNativeSeparators(m->url);
|
||||
QProcess::startDetached("explorer", args);
|
||||
#elif defined(Q_OS_MAC)
|
||||
QStringList args;
|
||||
args << "-e";
|
||||
args << "tell application \"Finder\"";
|
||||
args << "-e";
|
||||
args << "activate";
|
||||
args << "-e";
|
||||
args << "select POSIX file \""+m->url+"\"";
|
||||
args << "-e";
|
||||
args << "end tell";
|
||||
QProcess::startDetached("osascript", args);
|
||||
#else
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(m->url.left(m->url.lastIndexOf('/'))));
|
||||
#endif
|
||||
}
|
||||
|
||||
void SourceTable::item_renamed(Media* item) {
|
||||
if (editing_item == item) {
|
||||
MediaRename* mr = new MediaRename(item, "idk");
|
||||
undo_stack.push(mr);
|
||||
editing_item = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void SourceTable::stop_rename_timer() {
|
||||
rename_timer.stop();
|
||||
}
|
||||
|
||||
void SourceTable::rename_interval() {
|
||||
stop_rename_timer();
|
||||
if (hasFocus() && editing_item != NULL) {
|
||||
edit(editing_index);
|
||||
//editItem(editing_item, 0);
|
||||
}
|
||||
}
|
||||
void SourceTable::item_click(const QModelIndex& index) {
|
||||
if (selectionModel()->selectedRows().size() == 1 && index.column() == 0) {
|
||||
Media* m = project_parent->item_to_media(index);
|
||||
if (editing_item == m) {
|
||||
rename_timer.start();
|
||||
} else {
|
||||
editing_item = m;
|
||||
editing_index = index;
|
||||
}
|
||||
project_parent->sources_common->item_click(project_parent->item_to_media(index), index);
|
||||
}
|
||||
}
|
||||
|
||||
void SourceTable::mousePressEvent(QMouseEvent* event) {
|
||||
stop_rename_timer();
|
||||
project_parent->sources_common->mousePressEvent(event);
|
||||
QTreeView::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void SourceTable::mouseDoubleClickEvent(QMouseEvent* e) {
|
||||
stop_rename_timer();
|
||||
QModelIndexList selected_items = selectionModel()->selectedRows();
|
||||
if (selected_items.size() == 0) {
|
||||
project_parent->import_dialog();
|
||||
} else if (selected_items.size() == 1) {
|
||||
Media* item = project_parent->item_to_media(selected_items.at(0));
|
||||
switch (item->get_type()) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
panel_footage_viewer->set_media(item);
|
||||
panel_footage_viewer->setFocus();
|
||||
break;
|
||||
case MEDIA_TYPE_SEQUENCE:
|
||||
undo_stack.push(new ChangeSequenceAction(item->to_sequence()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
void SourceTable::mouseDoubleClickEvent(QMouseEvent* event) {
|
||||
project_parent->sources_common->mouseDoubleClickEvent(event, selectionModel()->selectedRows());
|
||||
}
|
||||
|
||||
void SourceTable::dragEnterEvent(QDragEnterEvent *event) {
|
||||
@@ -231,79 +69,5 @@ void SourceTable::dragMoveEvent(QDragMoveEvent *event) {
|
||||
}
|
||||
|
||||
void SourceTable::dropEvent(QDropEvent* event) {
|
||||
const QMimeData* mimeData = event->mimeData();
|
||||
const QModelIndex& drop_item = indexAt(event->pos());
|
||||
Media* m = project_parent->item_to_media(drop_item);
|
||||
if (mimeData->hasUrls()) {
|
||||
// drag files in from outside
|
||||
QList<QUrl> urls = mimeData->urls();
|
||||
if (!urls.isEmpty()) {
|
||||
QStringList paths;
|
||||
for (int i=0;i<urls.size();i++) {
|
||||
paths.append(urls.at(i).toLocalFile());
|
||||
}
|
||||
bool replace = false;
|
||||
if (urls.size() == 1
|
||||
&& drop_item.isValid()
|
||||
&& m->get_type() == MEDIA_TYPE_FOOTAGE
|
||||
&& !QFileInfo(paths.at(0)).isDir()
|
||||
&& config.drop_on_media_to_replace
|
||||
&& QMessageBox::question(this, "Replace Media", "You dropped a file onto '" + m->get_name() + "'. Would you like to replace it with the dropped file?", QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) {
|
||||
replace = true;
|
||||
project_parent->replace_media(m, paths.at(0));
|
||||
}
|
||||
if (!replace) {
|
||||
QModelIndex parent;
|
||||
if (drop_item.isValid()) {
|
||||
if (m->get_type() == MEDIA_TYPE_FOLDER) {
|
||||
parent = drop_item;
|
||||
} else {
|
||||
parent = drop_item.parent();
|
||||
}
|
||||
}
|
||||
if (parent.isValid()) setExpanded(parent, true);
|
||||
project_parent->process_file_list(paths, false, NULL, panel_project->item_to_media(parent));
|
||||
}
|
||||
}
|
||||
event->acceptProposedAction();
|
||||
} else {
|
||||
event->ignore();
|
||||
|
||||
// dragging files within project
|
||||
// if we dragged to the root OR dragged to a folder
|
||||
if (!drop_item.isValid() || (drop_item.isValid() && m->get_type() == MEDIA_TYPE_FOLDER)) {
|
||||
QVector<Media*> move_items;
|
||||
QModelIndexList selected_items = selectionModel()->selectedRows();
|
||||
for (int i=0;i<selected_items.size();i++) {
|
||||
const QModelIndex& item = selected_items.at(i);
|
||||
const QModelIndex& parent = item.parent();
|
||||
Media* s = project_parent->item_to_media(item);
|
||||
if (parent != drop_item && item != drop_item) {
|
||||
bool ignore = false;
|
||||
if (parent.isValid()) {
|
||||
// if child belongs to a selected parent, assume the user is just moving the parent and ignore the child
|
||||
QModelIndex par = parent;
|
||||
while (par.isValid() && !ignore) {
|
||||
for (int j=0;j<selected_items.size();j++) {
|
||||
if (par == selected_items.at(j)) {
|
||||
ignore = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
par = par.parent();
|
||||
}
|
||||
}
|
||||
if (!ignore) {
|
||||
move_items.append(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (move_items.size() > 0) {
|
||||
MediaMove* mm = new MediaMove(this);
|
||||
mm->to = m;
|
||||
mm->items = move_items;
|
||||
undo_stack.push(mm);
|
||||
}
|
||||
}
|
||||
}
|
||||
project_parent->sources_common->dropEvent(this, event, indexAt(event->pos()), selectionModel()->selectedRows());
|
||||
}
|
||||
|
||||
@@ -12,26 +12,17 @@ class SourceTable : public QTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SourceTable(QWidget* parent = 0);
|
||||
SourceTable(QWidget* parent = 0);
|
||||
Project* project_parent;
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent*);
|
||||
void mouseDoubleClickEvent(QMouseEvent *event);
|
||||
void mouseDoubleClickEvent(QMouseEvent *);
|
||||
void dragEnterEvent(QDragEnterEvent *event);
|
||||
void dragMoveEvent(QDragMoveEvent *event);
|
||||
void dropEvent(QDropEvent *event);
|
||||
private:
|
||||
QTimer rename_timer;
|
||||
Media* editing_item;
|
||||
QModelIndex editing_index;
|
||||
private slots:
|
||||
void rename_interval();
|
||||
void item_click(const QModelIndex& index);
|
||||
void stop_rename_timer();
|
||||
void item_renamed(Media *item);
|
||||
void show_context_menu();
|
||||
void create_seq_from_selected();
|
||||
void reveal_in_browser();
|
||||
void show_context_menu();
|
||||
};
|
||||
|
||||
#endif // SOURCETABLE_H
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "panels/timeline.h"
|
||||
#include "project/footage.h"
|
||||
#include "ui/sourcetable.h"
|
||||
#include "ui/sourceiconview.h"
|
||||
#include "panels/effectcontrols.h"
|
||||
#include "panels/viewer.h"
|
||||
#include "project/undo.h"
|
||||
@@ -265,8 +266,10 @@ void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) {
|
||||
QVector<Media*> media_list;
|
||||
panel_timeline->importing_files = false;
|
||||
|
||||
if (event->source() == panel_project->source_table) {
|
||||
QModelIndexList items = panel_project->source_table->selectionModel()->selectedRows();
|
||||
if (event->source() == panel_project->tree_view || event->source() == panel_project->icon_view) {
|
||||
QModelIndexList items = (event->source() == panel_project->tree_view)
|
||||
? panel_project->tree_view->selectionModel()->selectedRows()
|
||||
: panel_project->icon_view->selectionModel()->selectedIndexes();
|
||||
media_list.resize(items.size());
|
||||
for (int i=0;i<items.size();i++) {
|
||||
media_list[i] = panel_project->item_to_media(items.at(i));
|
||||
|
||||
@@ -19,6 +19,7 @@ class TimelineAction;
|
||||
class QScrollBar;
|
||||
class SetSelectionsCommand;
|
||||
class QPainter;
|
||||
class Media;
|
||||
|
||||
bool same_sign(int a, int b);
|
||||
void draw_waveform(Clip* clip, FootageStream* ms, long media_length, QPainter* p, const QRect& clip_rect, int waveform_start, int waveform_limit, double zoom);
|
||||
@@ -65,7 +66,7 @@ private:
|
||||
// used for "right click ripple"
|
||||
long rc_ripple_min;
|
||||
long rc_ripple_max;
|
||||
void* rc_reveal_media;
|
||||
Media* rc_reveal_media;
|
||||
|
||||
QTimer tooltip_timer;
|
||||
int tooltip_clip;
|
||||
|
||||
@@ -75,6 +75,8 @@ void ViewerContainer::adjust() {
|
||||
|
||||
child->move(widget_x, widget_y);
|
||||
child->resize(widget_width, widget_height);
|
||||
|
||||
zoom = double(widget_width) / double(viewer->seq->width);
|
||||
} else {
|
||||
int zoomed_width = double(viewer->seq->width)*zoom;
|
||||
int zoomed_height = double(viewer->seq->height)*zoom;
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <QFileDialog>
|
||||
#include <QPolygon>
|
||||
#include <QDesktopWidget>
|
||||
#include <QInputDialog>
|
||||
|
||||
extern "C" {
|
||||
#include <libavformat/avformat.h>
|
||||
@@ -91,6 +92,22 @@ void ViewerWidget::show_context_menu() {
|
||||
QAction* show_fullscreen_action = menu.addAction("Show Fullscreen");
|
||||
connect(show_fullscreen_action, SIGNAL(triggered()), this, SLOT(show_fullscreen()));
|
||||
|
||||
QMenu zoom_menu("Zoom");
|
||||
QAction* fit_zoom = zoom_menu.addAction("Fit");
|
||||
connect(fit_zoom, SIGNAL(triggered(bool)), this, SLOT(set_fit_zoom()));
|
||||
zoom_menu.addAction("10%")->setData(0.1);
|
||||
zoom_menu.addAction("25%")->setData(0.25);
|
||||
zoom_menu.addAction("50%")->setData(0.5);
|
||||
zoom_menu.addAction("75%")->setData(0.75);
|
||||
zoom_menu.addAction("100%")->setData(1.0);
|
||||
zoom_menu.addAction("150%")->setData(1.5);
|
||||
zoom_menu.addAction("200%")->setData(2.0);
|
||||
zoom_menu.addAction("400%")->setData(4.0);
|
||||
QAction* custom_zoom = zoom_menu.addAction("Custom");
|
||||
connect(custom_zoom, SIGNAL(triggered(bool)), this, SLOT(set_custom_zoom()));
|
||||
connect(&zoom_menu, SIGNAL(triggered(QAction*)), this, SLOT(set_menu_zoom(QAction*)));
|
||||
menu.addMenu(&zoom_menu);
|
||||
|
||||
menu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
@@ -130,6 +147,30 @@ void ViewerWidget::show_fullscreen() {
|
||||
showFullScreen();
|
||||
}
|
||||
|
||||
void ViewerWidget::set_fit_zoom() {
|
||||
container->fit = true;
|
||||
container->adjust();
|
||||
}
|
||||
|
||||
void ViewerWidget::set_custom_zoom() {
|
||||
bool ok;
|
||||
double d = QInputDialog::getDouble(this, "Viewer Zoom", "Set Custom Zoom Value:", container->zoom*100, 0, 2147483647, 2, &ok);
|
||||
if (ok) {
|
||||
container->fit = false;
|
||||
container->zoom = d*0.01;
|
||||
container->adjust();
|
||||
}
|
||||
}
|
||||
|
||||
void ViewerWidget::set_menu_zoom(QAction* action) {
|
||||
const QVariant& data = action->data();
|
||||
if (!data.isNull()) {
|
||||
container->fit = false;
|
||||
container->zoom = data.toDouble();
|
||||
container->adjust();
|
||||
}
|
||||
}
|
||||
|
||||
void ViewerWidget::retry() {
|
||||
update();
|
||||
}
|
||||
@@ -640,12 +681,8 @@ GLuint ViewerWidget::compose_sequence(QVector<Clip*>& nests, bool render_audio)
|
||||
int widget_width = width();
|
||||
int widget_height = height();
|
||||
|
||||
QString qt_scale_factor = QString(qgetenv("QT_SCALE_FACTOR"));
|
||||
if (!qt_scale_factor.isEmpty()) {
|
||||
double scale = qt_scale_factor.toDouble();
|
||||
widget_width *= scale;
|
||||
widget_height *= scale;
|
||||
}
|
||||
widget_width *= QApplication::desktop()->devicePixelRatio();
|
||||
widget_height *= QApplication::desktop()->devicePixelRatio();
|
||||
|
||||
glViewport(0, 0, widget_width, widget_height);
|
||||
}
|
||||
|
||||
@@ -70,6 +70,10 @@ private slots:
|
||||
void show_context_menu();
|
||||
void save_frame();
|
||||
void show_fullscreen();
|
||||
|
||||
void set_fit_zoom();
|
||||
void set_custom_zoom();
|
||||
void set_menu_zoom(QAction *action);
|
||||
};
|
||||
|
||||
#endif // VIEWERWIDGET_H
|
||||
|
||||